Merge branch 'master' into uta/rainbow
authorAlexey Utkin <alexey.utkin@jetbrains.com>
Wed, 24 Aug 2016 10:06:19 +0000 (13:06 +0300)
committerAlexey Utkin <alexey.utkin@jetbrains.com>
Wed, 24 Aug 2016 10:06:19 +0000 (13:06 +0300)
29 files changed:
java/java-analysis-impl/src/com/intellij/codeInsight/daemon/impl/analysis/HighlightNamesUtil.java
java/java-impl/src/com/intellij/openapi/options/colors/pages/JavaColorSettingsPage.java
platform/analysis-impl/src/com/intellij/codeHighlighting/RainbowHighlighter.java
platform/analysis-impl/src/com/intellij/codeInsight/daemon/UsedColors.java
platform/analysis-impl/src/com/intellij/codeInsight/daemon/impl/GeneralHighlightingPass.java
platform/editor-ui-api/src/com/intellij/openapi/editor/colors/EditorSchemeAttributeDescriptor.java [moved from platform/lang-impl/src/com/intellij/application/options/colors/EditorSchemeAttributeDescriptor.java with 83% similarity]
platform/editor-ui-api/src/com/intellij/openapi/editor/colors/EditorSchemeAttributeDescriptorWithPath.java [new file with mode: 0644]
platform/lang-api/src/com/intellij/openapi/options/colors/RainbowColorSettingsPage.java [new file with mode: 0644]
platform/lang-impl/src/com/intellij/application/options/colors/ClickNavigator.java
platform/lang-impl/src/com/intellij/application/options/colors/ColorAndFontDescription.java
platform/lang-impl/src/com/intellij/application/options/colors/ColorAndFontDescriptionPanel.java
platform/lang-impl/src/com/intellij/application/options/colors/ColorAndFontGlobalState.java [new file with mode: 0644]
platform/lang-impl/src/com/intellij/application/options/colors/ColorAndFontOptions.java
platform/lang-impl/src/com/intellij/application/options/colors/ColorOptionsTree.java
platform/lang-impl/src/com/intellij/application/options/colors/ColorSettingsUtil.java
platform/lang-impl/src/com/intellij/application/options/colors/CustomizedSwitcherPanel.java [new file with mode: 0644]
platform/lang-impl/src/com/intellij/application/options/colors/FontOptions.java
platform/lang-impl/src/com/intellij/application/options/colors/NewColorAndFontPanel.java
platform/lang-impl/src/com/intellij/application/options/colors/OptionsPanelImpl.java
platform/lang-impl/src/com/intellij/application/options/colors/RainbowAttributeDescriptor.java [new file with mode: 0644]
platform/lang-impl/src/com/intellij/application/options/colors/RainbowColorsInSchemeState.java [new file with mode: 0644]
platform/lang-impl/src/com/intellij/application/options/colors/RainbowDescriptionPanel.form [new file with mode: 0644]
platform/lang-impl/src/com/intellij/application/options/colors/RainbowDescriptionPanel.java [new file with mode: 0644]
platform/lang-impl/src/com/intellij/application/options/colors/SchemesPanel.java
platform/lang-impl/src/com/intellij/application/options/colors/SimpleEditorPreview.java
platform/lang-impl/src/com/intellij/application/options/colors/highlighting/HighlightData.java
platform/lang-impl/src/com/intellij/openapi/diff/impl/settings/DiffColorDescriptionPanel.java
platform/lang-impl/src/com/intellij/openapi/options/colors/pages/DefaultLanguageColorsPage.java
platform/platform-resources-en/src/messages/ApplicationBundle.properties

index 4ba8a25730f3125511a6c1b4a3208f69c10f6faf..5c915995234fe27eb26f0effcb61988f1ed181ef 100644 (file)
@@ -21,6 +21,7 @@ import com.intellij.codeInsight.daemon.impl.HighlightInfo;
 import com.intellij.codeInsight.daemon.impl.HighlightInfoType;
 import com.intellij.codeInsight.daemon.impl.JavaHighlightInfoTypes;
 import com.intellij.lang.ASTNode;
+import com.intellij.lang.java.JavaLanguage;
 import com.intellij.openapi.diagnostic.Logger;
 import com.intellij.openapi.editor.colors.TextAttributesKey;
 import com.intellij.openapi.editor.colors.TextAttributesScheme;
@@ -154,7 +155,8 @@ public class HighlightNamesUtil {
     }
 
     HighlightInfo.Builder builder = HighlightInfo.newHighlightInfo(varType).range(elementToHighlight);
-    return RainbowHighlighter.isRainbowEnabled() ? builder.createUnconditionally() : builder.create();
+    return RainbowHighlighter.isRainbowEnabledWithInheritance(JavaLanguage.INSTANCE) ? builder.createUnconditionally()
+                                                                                     : builder.create();
   }
 
   @Nullable
index 0069c98c26b3fb4d6d243fa5c2d0c8bec79097ca..853206b4d5d230b63d069f469c70c4111cecd2b1 100644 (file)
@@ -18,6 +18,8 @@ package com.intellij.openapi.options.colors.pages;
 import com.intellij.application.options.colors.InspectionColorSettingsPage;
 import com.intellij.ide.highlighter.JavaFileHighlighter;
 import com.intellij.ide.highlighter.JavaHighlightingColors;
+import com.intellij.lang.Language;
+import com.intellij.lang.java.JavaLanguage;
 import com.intellij.openapi.editor.colors.CodeInsightColors;
 import com.intellij.openapi.editor.colors.TextAttributesKey;
 import com.intellij.openapi.fileTypes.StdFileTypes;
@@ -25,18 +27,19 @@ import com.intellij.openapi.fileTypes.SyntaxHighlighter;
 import com.intellij.openapi.options.OptionsBundle;
 import com.intellij.openapi.options.colors.AttributesDescriptor;
 import com.intellij.openapi.options.colors.ColorDescriptor;
-import com.intellij.openapi.options.colors.ColorSettingsPage;
+import com.intellij.openapi.options.colors.RainbowColorSettingsPage;
 import com.intellij.pom.java.LanguageLevel;
 import com.intellij.psi.codeStyle.DisplayPriority;
 import com.intellij.psi.codeStyle.DisplayPrioritySortable;
 import org.jetbrains.annotations.NonNls;
 import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
 
 import javax.swing.*;
 import java.util.HashMap;
 import java.util.Map;
 
-public class JavaColorSettingsPage implements ColorSettingsPage, InspectionColorSettingsPage, DisplayPrioritySortable {
+public class JavaColorSettingsPage implements RainbowColorSettingsPage, InspectionColorSettingsPage, DisplayPrioritySortable {
   private static final AttributesDescriptor[] ourDescriptors = {
     new AttributesDescriptor(OptionsBundle.message("options.java.attribute.descriptor.keyword"), JavaHighlightingColors.KEYWORD),
     new AttributesDescriptor(OptionsBundle.message("options.java.attribute.descriptor.number"), JavaHighlightingColors.NUMBER),
@@ -208,4 +211,51 @@ public class JavaColorSettingsPage implements ColorSettingsPage, InspectionColor
   public DisplayPriority getPriority() {
     return DisplayPriority.KEY_LANGUAGE_SETTINGS;
   }
+
+  @Override
+  public boolean isRainbowType(TextAttributesKey type) {
+    return JavaHighlightingColors.LOCAL_VARIABLE_ATTRIBUTES.equals(type)
+        || JavaHighlightingColors.REASSIGNED_LOCAL_VARIABLE_ATTRIBUTES.equals(type)
+        || JavaHighlightingColors.PARAMETER_ATTRIBUTES.equals(type)
+        || JavaHighlightingColors.REASSIGNED_PARAMETER_ATTRIBUTES.equals(type)
+
+        || JavaHighlightingColors.DOC_COMMENT_TAG_VALUE.equals(type);
+  }
+
+  @NotNull
+  @Override
+  public String getRainbowDemoText() {
+    return
+      "import <class>java.util.Date</class>;\n" +
+      "class <class>SomeClass</class> {\n" +
+      "  public int <field>field</field>;\n" +
+      "  <constructorDeclaration>SomeClass</constructorDeclaration>(<interface>AnInterface</interface> <param>param</param>) {\n" +
+      "\n" +
+      "  }\n" +
+      "  /**\n" +
+      "   * Doc comment\n" +
+      "   * @param <javadocTagValue>param1</javadocTagValue> function param\n" +
+      "   * @param <javadocTagValue>param2</javadocTagValue>\n" +
+      "   * @param <javadocTagValue>param3</javadocTagValue>\n" +
+      "   * @param <javadocTagValue>param4</javadocTagValue>\n" +
+      "   * @param <javadocTagValue>param5</javadocTagValue>\n" +
+      "   */\n" +
+      "  void <methodDeclaration>method</methodDeclaration>(int <param>param1</param>,\n" +
+      "              int <param>param2</param>,\n" +
+      "              int <param>param3</param>,\n" +
+      "              int <param>param4</param>,\n" +
+      "              int <param>param5</param>) {\n" +
+      "    int <localVar>localVar1</localVar>, <localVar>localVar2</localVar>, <localVar>localVar3</localVar>, <localVar>localVar4</localVar>, <localVar>localVar5</localVar>;\n" +
+      "\n" +
+      "    <localVar>localVar3</localVar> = <param>param2</param>;\n" +
+      "    this.<field>field</field> = <localVar>localVar3</localVar> + <param>param1</param> + <param>param5</param>;\n" +
+      "  }\n" +
+      "}\n";
+  }
+
+  @Nullable
+  @Override
+  public Language getLanguage() {
+    return JavaLanguage.INSTANCE;
+  }
 }
index f74e74b45e49f24683408ca9eae33e9a1fd2cbee..d19b3166758f2716ded6d6be515249308e424fe2 100644 (file)
@@ -17,6 +17,8 @@ package com.intellij.codeHighlighting;
 
 import com.intellij.codeInsight.daemon.impl.HighlightInfo;
 import com.intellij.codeInsight.daemon.impl.HighlightInfoType;
+import com.intellij.ide.util.PropertiesComponent;
+import com.intellij.lang.Language;
 import com.intellij.lang.annotation.HighlightSeverity;
 import com.intellij.openapi.application.ApplicationManager;
 import com.intellij.openapi.editor.DefaultLanguageHighlighterColors;
@@ -25,11 +27,13 @@ import com.intellij.openapi.editor.colors.TextAttributesKey;
 import com.intellij.openapi.editor.colors.TextAttributesScheme;
 import com.intellij.openapi.editor.markup.TextAttributes;
 import com.intellij.openapi.util.registry.Registry;
+import com.intellij.openapi.util.text.StringHash;
 import com.intellij.openapi.util.text.StringUtil;
 import com.intellij.psi.PsiElement;
 import com.intellij.ui.ColorUtil;
 import com.intellij.ui.JBColor;
 import com.intellij.util.containers.ContainerUtil;
+import org.jetbrains.annotations.Contract;
 import org.jetbrains.annotations.NotNull;
 import org.jetbrains.annotations.Nullable;
 
@@ -44,9 +48,13 @@ public class RainbowHighlighter {
     new JBColor(0x005910, 0xbe9970),
     new JBColor(0xbc5150, 0x9d527c),
   };
-  private static final TextAttributesKey[] RAINBOW_COLOR_KEYS = new TextAttributesKey[RAINBOW_JB_COLORS_DEFAULT.length];
+  public static final TextAttributesKey[] RAINBOW_COLOR_KEYS = new TextAttributesKey[RAINBOW_JB_COLORS_DEFAULT.length];
   private static final int RAINBOW_COLORS_BETWEEN = 4;
   private static final String UNIT_TEST_COLORS = "#000001,#000002,#000003,#000004"; // Do not modify!
+  private static String FALSE = "false";
+  private static String TRUE = "true";
+  private static String INHERITED = "inherited";
+
   static {
     for (int i = 0; i < RAINBOW_JB_COLORS_DEFAULT.length; ++i) {
       JBColor jbColor = RAINBOW_JB_COLORS_DEFAULT[i];
@@ -54,6 +62,9 @@ public class RainbowHighlighter {
       RAINBOW_COLOR_KEYS[i] = TextAttributesKey.createTextAttributesKey("RAINBOW_COLOR" + i, textAttributes);
     }
   }
+  public final static String RAINBOW_TYPE = "rainbow";
+  private final static String RAINBOW_TEMP_PREF = "RAINBOW_TEMP_";
+  public final static Boolean DEFAULT_RAINBOW_ON = Boolean.FALSE;
 
   @NotNull private final TextAttributesScheme myColorsScheme;
   @NotNull private final Color[] myRainbowColors;
@@ -65,11 +76,57 @@ public class RainbowHighlighter {
 
   public static final HighlightInfoType RAINBOW_ELEMENT = new HighlightInfoType.HighlightInfoTypeImpl(HighlightSeverity.INFORMATION, DefaultLanguageHighlighterColors.CONSTANT);
 
-  public static boolean isRainbowEnabled() {
-    return Registry.is("editor.rainbow.identifiers", false);
+  @Nullable
+  @Contract("null -> !null")
+  public static Boolean isRainbowEnabled(@Nullable Language language) {
+    String value = PropertiesComponent.getInstance().getValue(getKey(language), INHERITED);
+    if (TRUE.equals(value)) return Boolean.TRUE;
+    if (FALSE.equals(value)) return Boolean.FALSE;
+    return language == null ? DEFAULT_RAINBOW_ON : null;
+  }
+
+  public static boolean isRainbowEnabledWithInheritance(@Nullable Language language) {
+    Boolean rainbowEnabled = isRainbowEnabled(language);
+    return rainbowEnabled != null ? rainbowEnabled : isRainbowEnabled(null);
+  }
+
+  public static void setRainbowEnabled(@Nullable Language language, @Nullable Boolean enabled) {
+    PropertiesComponent.getInstance().setValue(
+      getKey(language),
+      enabled == null ? INHERITED : enabled.toString());
   }
 
   @NotNull
+  private static String getKey(@Nullable Language language) {
+    return RAINBOW_TYPE + (language == null ? "Default language" : language.getID());
+  }
+
+  public static int hashColor(@NotNull String name, int colorsCount) {
+    return Math.abs(StringHash.murmur(name, 0x55AA)) % colorsCount;
+  }
+
+  public static int getColorIndex(@NotNull int[] index2usage, int hashedIndex, int colorsCount) {
+    int minIndex1 = indexOfMin(index2usage, hashedIndex, colorsCount);
+    int minIndex2 = indexOfMin(index2usage, 0, hashedIndex);
+    return index2usage[minIndex1] <= index2usage[minIndex2] ? minIndex1 : minIndex2;
+  }
+
+  @Contract(pure = true)
+  private static int indexOfMin(@NotNull int[] index2usage, int start, int end) {
+    int min = Integer.MAX_VALUE;
+    int minIndex = start;
+    for (int i = start; i < end; i++) {
+      int value = index2usage[i];
+      if (value < min) {
+        min = value;
+        minIndex = i;
+      }
+    }
+    return minIndex;
+  }
+
+  @NotNull
+  @Contract(pure = true)
   private Color calculateForeground(int colorIndex) {
     return myRainbowColors[colorIndex];
   }
@@ -89,15 +146,36 @@ public class RainbowHighlighter {
       return registryColors.stream().map(s -> ColorUtil.fromHex(s.trim())).toArray(Color[]::new);
     }
 
-    List<Color> foregroundColors = ContainerUtil.map(RAINBOW_COLOR_KEYS, key -> colorsScheme.getAttributes(key).getForegroundColor());
-    List<Color> colors = ColorGenerator.generateLinearColorSequence(foregroundColors, RAINBOW_COLORS_BETWEEN);
+    List<Color> stopColors = ContainerUtil.map(RAINBOW_COLOR_KEYS, key -> colorsScheme.getAttributes(key).getForegroundColor());
+    List<Color> colors = ColorGenerator.generateLinearColorSequence(stopColors, RAINBOW_COLORS_BETWEEN);
     return colors.toArray(new Color[colors.size()]);
   }
 
-  public HighlightInfo getInfo(int colorIndex, @Nullable PsiElement id, @Nullable TextAttributesKey colorKey) {
-    if (id == null) {
-      return null;
+  @NotNull
+  public TextAttributesKey[] getRainbowTempKeys() {
+    TextAttributesKey[] keys = new TextAttributesKey[myRainbowColors.length];
+    for (int i = 0; i < myRainbowColors.length; ++i) {
+      TextAttributesKey key = TextAttributesKey.createTextAttributesKey(RAINBOW_TEMP_PREF + i, new TextAttributes());
+      key.getDefaultAttributes().setForegroundColor(myRainbowColors[i]);
+      keys[i] = key;
     }
+    return keys;
+  }
+
+  public static boolean isRainbowTempKey(TextAttributesKey key) {
+    return key.getExternalName().startsWith(RAINBOW_TEMP_PREF);
+  }
+
+  public HighlightInfo getInfo(int colorIndex, @Nullable PsiElement id, @Nullable TextAttributesKey colorKey) {
+    return id == null ? null : getInfoBuilder(colorIndex, colorKey).range(id).create();
+  }
+
+  public HighlightInfo getInfo(int colorIndex, int start, int end, @Nullable TextAttributesKey colorKey) {
+    return getInfoBuilder(colorIndex, colorKey).range(start, end).create();
+  }
+
+  @NotNull
+  protected HighlightInfo.Builder getInfoBuilder(int colorIndex, @Nullable TextAttributesKey colorKey) {
     if (colorKey == null) {
       colorKey = DefaultLanguageHighlighterColors.LOCAL_VARIABLE;
     }
@@ -107,8 +185,6 @@ public class RainbowHighlighter {
                         .fromFlyweight(myColorsScheme
                                          .getAttributes(colorKey)
                                          .getFlyweight()
-                                         .withForeground(calculateForeground(colorIndex))))
-      .range(id)
-      .create();
+                                         .withForeground(calculateForeground(colorIndex))));
   }
 }
index c656596236c77287c5d138f8b2141d25ff3ea616..18cb439691af9d59739f9d89559e6ffb701a0800 100644 (file)
@@ -18,7 +18,6 @@ package com.intellij.codeInsight.daemon;
 import com.intellij.codeHighlighting.RainbowHighlighter;
 import com.intellij.openapi.util.Key;
 import com.intellij.openapi.util.UserDataHolderEx;
-import com.intellij.openapi.util.text.StringHash;
 import com.intellij.util.ArrayUtil;
 import org.jetbrains.annotations.NotNull;
 
@@ -49,7 +48,7 @@ class UsedColors {
     while (true) {
       Object newColors;
       if (data == null) {
-        colorIndex = hashColor(name, colorsCount);
+        colorIndex = RainbowHighlighter.hashColor(name, colorsCount);
         newColors = new UsedColor(name, colorIndex); // put an object instead of array to save space
       }
       else if (data instanceof UsedColor) {
@@ -59,7 +58,7 @@ class UsedColors {
           newColors = null; // found, no need to create new
         }
         else {
-          int hashedIndex = hashColor(name, colorsCount);
+          int hashedIndex = RainbowHighlighter.hashColor(name, colorsCount);
           if (hashedIndex == usedColor.index) hashedIndex = (hashedIndex + 1) % colorsCount;
           colorIndex = hashedIndex;
           UsedColor newColor = new UsedColor(name, colorIndex);
@@ -68,7 +67,7 @@ class UsedColors {
       }
       else {
         colorIndex = -1;
-        int hashedIndex = hashColor(name, colorsCount);
+        int hashedIndex = RainbowHighlighter.hashColor(name, colorsCount);
         int[] index2usage = new int[colorsCount];
         UsedColor[] usedColors = (UsedColor[])data;
         for (UsedColor usedColor : usedColors) {
@@ -80,9 +79,7 @@ class UsedColors {
           }
         }
         if (colorIndex == -1) {
-          int minIndex1 = indexOfMin(index2usage, hashedIndex, colorsCount);
-          int minIndex2 = indexOfMin(index2usage, 0, hashedIndex);
-          colorIndex = index2usage[minIndex1] <= index2usage[minIndex2] ? minIndex1 : minIndex2;
+          colorIndex = RainbowHighlighter.getColorIndex(index2usage, hashedIndex, colorsCount);
           UsedColor newColor = new UsedColor(name, colorIndex);
           newColors = ArrayUtil.append(usedColors, newColor);
         }
@@ -97,21 +94,4 @@ class UsedColors {
 
     return colorIndex;
   }
-
-  private static int hashColor(@NotNull String name, int colorsCount) {
-    return Math.abs(StringHash.murmur(name, 0x55AA)) % colorsCount;
-  }
-
-  private static int indexOfMin(@NotNull int[] values, int start, int end) {
-    int min = Integer.MAX_VALUE;
-    int minIndex = start;
-    for (int i = start; i < end; i++) {
-      int value = values[i];
-      if (value < min) {
-        min = value;
-        minIndex = i;
-      }
-    }
-    return minIndex;
-  }
 }
index 8de1049f71ad28e41b46f92f591ded93e4d6cc99..02494a2cd03d04759b12e45e070d85dc7195f42f 100644 (file)
@@ -142,7 +142,8 @@ public class GeneralHighlightingPass extends ProgressableTextEditorHighlightingP
     final List<HighlightVisitor> visitors = new ArrayList<>(highlightVisitors.length);
     List<HighlightVisitor> list = Arrays.asList(highlightVisitors);
     for (HighlightVisitor visitor : DumbService.getInstance(myProject).filterByDumbAwareness(list)) {
-      if (visitor instanceof RainbowVisitor && !RainbowHighlighter.isRainbowEnabled()) {
+      if (visitor instanceof RainbowVisitor
+          && !RainbowHighlighter.isRainbowEnabledWithInheritance(psiFile.getLanguage())) {
         continue;
       }
       if (visitor.suitableForFile(psiFile)) {
similarity index 83%
rename from platform/lang-impl/src/com/intellij/application/options/colors/EditorSchemeAttributeDescriptor.java
rename to platform/editor-ui-api/src/com/intellij/openapi/editor/colors/EditorSchemeAttributeDescriptor.java
index fd5315664271876ab1ade654074000e34439279d..f174507a51c266f6d5cc457671b5bf685886d82e 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright 2000-2009 JetBrains s.r.o.
+ * Copyright 2000-2016 JetBrains s.r.o.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -14,9 +14,7 @@
  * limitations under the License.
  */
 
-package com.intellij.application.options.colors;
-
-import com.intellij.openapi.editor.colors.EditorColorsScheme;
+package com.intellij.openapi.editor.colors;
 
 public interface EditorSchemeAttributeDescriptor {
   String getGroup();
diff --git a/platform/editor-ui-api/src/com/intellij/openapi/editor/colors/EditorSchemeAttributeDescriptorWithPath.java b/platform/editor-ui-api/src/com/intellij/openapi/editor/colors/EditorSchemeAttributeDescriptorWithPath.java
new file mode 100644 (file)
index 0000000..e5bc406
--- /dev/null
@@ -0,0 +1,20 @@
+/*
+ * Copyright 2000-2016 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.intellij.openapi.editor.colors;
+
+public interface EditorSchemeAttributeDescriptorWithPath extends EditorSchemeAttributeDescriptor {
+  String NAME_SEPARATOR = "//";
+}
diff --git a/platform/lang-api/src/com/intellij/openapi/options/colors/RainbowColorSettingsPage.java b/platform/lang-api/src/com/intellij/openapi/options/colors/RainbowColorSettingsPage.java
new file mode 100644 (file)
index 0000000..0298623
--- /dev/null
@@ -0,0 +1,31 @@
+/*
+ * Copyright 2000-2016 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.intellij.openapi.options.colors;
+
+import com.intellij.lang.Language;
+import com.intellij.openapi.editor.colors.TextAttributesKey;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+
+public interface RainbowColorSettingsPage extends ColorSettingsPage {
+  boolean isRainbowType(TextAttributesKey type);
+
+  @NotNull
+  String getRainbowDemoText();
+
+  @Nullable
+  Language getLanguage();
+}
index 043aa0fd9bca0b57c94805a089115ad995959d47..4025e031f1c55d168f1e839e2d1a7838da01c72c 100644 (file)
@@ -28,6 +28,7 @@ import com.intellij.openapi.editor.ex.EditorEx;
 import com.intellij.openapi.editor.ex.util.EditorUtil;
 import com.intellij.openapi.editor.highlighter.HighlighterIterator;
 import com.intellij.openapi.fileTypes.SyntaxHighlighter;
+import com.intellij.openapi.editor.colors.EditorSchemeAttributeDescriptor;
 import com.intellij.psi.tree.IElementType;
 import com.intellij.ui.ScrollingUtil;
 import com.intellij.util.ui.UIUtil;
index 0e45a0af226e8af3e8eeafc488f487ea677a918a..db93b73633856cb8f65f3d3da93eab275b233f64 100644 (file)
@@ -17,6 +17,7 @@
 package com.intellij.application.options.colors;
 
 import com.intellij.openapi.editor.colors.EditorColorsScheme;
+import com.intellij.openapi.editor.colors.EditorSchemeAttributeDescriptorWithPath;
 import com.intellij.openapi.editor.colors.impl.AbstractColorsScheme;
 import com.intellij.openapi.editor.colors.impl.ReadOnlyColorsScheme;
 import com.intellij.openapi.editor.markup.EffectType;
@@ -30,7 +31,7 @@ import org.jetbrains.annotations.Nullable;
 import javax.swing.*;
 import java.awt.*;
 
-public abstract class ColorAndFontDescription extends TextAttributes implements EditorSchemeAttributeDescriptor {
+public abstract class ColorAndFontDescription extends TextAttributes implements EditorSchemeAttributeDescriptorWithPath {
   private final String myName;
   private final String myGroup;
   private final String myType;
index 152710c650e38d6f8742b3c0e993cd2795f72c21..16c1462e75e6a8c7f2604daecfddffb251c8cee3 100644 (file)
@@ -17,6 +17,8 @@ package com.intellij.application.options.colors;
 
 import com.intellij.openapi.application.ApplicationBundle;
 import com.intellij.openapi.editor.colors.EditorColorsScheme;
+import com.intellij.openapi.editor.colors.EditorSchemeAttributeDescriptor;
+import com.intellij.openapi.editor.colors.EditorSchemeAttributeDescriptorWithPath;
 import com.intellij.openapi.editor.markup.EffectType;
 import com.intellij.openapi.editor.markup.TextAttributes;
 import com.intellij.openapi.options.colors.AttributesDescriptor;
@@ -29,12 +31,12 @@ import com.intellij.util.BitUtil;
 import com.intellij.util.EventDispatcher;
 import com.intellij.util.FontUtil;
 import com.intellij.util.containers.ContainerUtil;
+import com.intellij.util.ui.JBUI;
 import com.intellij.util.ui.UIUtil;
 import org.jetbrains.annotations.NotNull;
 import org.jetbrains.annotations.Nullable;
 
 import javax.swing.*;
-import javax.swing.event.HyperlinkEvent;
 import java.awt.*;
 import java.awt.event.ActionEvent;
 import java.awt.event.ActionListener;
@@ -85,7 +87,7 @@ public class ColorAndFontDescriptionPanel extends JPanel implements OptionsPanel
     super(new BorderLayout());
     add(myPanel, BorderLayout.CENTER);
 
-    setBorder(BorderFactory.createEmptyBorder(4, 0, 4, 4));
+    setBorder(JBUI.Borders.empty(4, 0, 4, 4));
     myEffectsModel = new EffectsComboModel(ContainerUtil.newArrayList(myEffectsMap.keySet()));
     //noinspection unchecked
     myEffectsCombo.setModel(myEffectsModel);
@@ -97,12 +99,16 @@ public class ColorAndFontDescriptionPanel extends JPanel implements OptionsPanel
       }
     });
 
-    ActionListener actionListener = new ActionListener() {
-      @Override
-      public void actionPerformed(ActionEvent e) {
-        onSettingsChanged(e);
-      }
+    ActionListener actionListener = e -> {
+      myErrorStripeColorChooser.setEnabled(myCbErrorStripe.isSelected());
+      myForegroundChooser.setEnabled(myCbForeground.isSelected());
+      myBackgroundChooser.setEnabled(myCbBackground.isSelected());
+      myEffectsColorChooser.setEnabled(myCbEffects.isSelected());
+      myEffectsCombo.setEnabled(myCbEffects.isSelected());
+
+      myDispatcher.getMulticaster().onSettingsChanged(e);
     };
+
     for (JBCheckBox c : new JBCheckBox[]{myCbBackground, myCbForeground, myCbEffects, myCbErrorStripe, myCbItalic, myCbBold, myInheritAttributesBox}) {
       c.addActionListener(actionListener);
     }
@@ -110,14 +116,10 @@ public class ColorAndFontDescriptionPanel extends JPanel implements OptionsPanel
       c.addActionListener(actionListener);
     }
     myEffectsCombo.addActionListener(actionListener);
+
     Messages.configureMessagePaneUi(myInheritanceLabel, "<html>", null);
-    myInheritanceLabel.addHyperlinkListener(new HyperlinkAdapter() {
-      @Override
-      protected void hyperlinkActivated(HyperlinkEvent e) {
-        onHyperLinkClicked(e);
-      }
-    });
-    myInheritanceLabel.setBorder(BorderFactory.createEmptyBorder());
+    myInheritanceLabel.addHyperlinkListener(e -> myDispatcher.getMulticaster().onHyperLinkClicked(e));
+    myInheritanceLabel.setBorder(JBUI.Borders.empty(4, 0, 4, 4));
     myLabelFont.setVisible(false); // hide for now as it doesn't look that good
   }
 
@@ -127,20 +129,6 @@ public class ColorAndFontDescriptionPanel extends JPanel implements OptionsPanel
     return this;
   }
 
-  private void onHyperLinkClicked(HyperlinkEvent e) {
-    myDispatcher.getMulticaster().onHyperLinkClicked(e);
-  }
-
-  private void onSettingsChanged(ActionEvent e) {
-    myErrorStripeColorChooser.setEnabled(myCbErrorStripe.isSelected());
-    myForegroundChooser.setEnabled(myCbForeground.isSelected());
-    myBackgroundChooser.setEnabled(myCbBackground.isSelected());
-    myEffectsColorChooser.setEnabled(myCbEffects.isSelected());
-    myEffectsCombo.setEnabled(myCbEffects.isSelected());
-
-    myDispatcher.getMulticaster().onSettingsChanged(e);
-  }
-
   public void resetDefault() {
     myLabelFont.setEnabled(false);
     myCbBold.setSelected(false);
@@ -172,7 +160,10 @@ public class ColorAndFontDescriptionPanel extends JPanel implements OptionsPanel
     colorPanel.setEnabled(isChecked);
   }
 
-  public void reset(@NotNull ColorAndFontDescription description) {
+  public void reset(@NotNull EditorSchemeAttributeDescriptor attrDescription) {
+    if (!(attrDescription instanceof ColorAndFontDescription)) return;
+    ColorAndFontDescription description = (ColorAndFontDescription)attrDescription;
+
     if (description.isFontEnabled()) {
       myLabelFont.setEnabled(description.isEditable());
       myCbBold.setEnabled(description.isEditable());
@@ -218,7 +209,7 @@ public class ColorAndFontDescriptionPanel extends JPanel implements OptionsPanel
     Pair<ColorSettingsPage, AttributesDescriptor> baseDescriptor = description.getBaseAttributeDescriptor();
     if (baseDescriptor != null && baseDescriptor.second.getDisplayName() != null) {
       String attrName = baseDescriptor.second.getDisplayName();
-      String attrLabel = attrName.replaceAll(ColorOptionsTree.NAME_SEPARATOR, FontUtil.rightArrow(UIUtil.getLabelFont()));
+      String attrLabel = attrName.replaceAll(EditorSchemeAttributeDescriptorWithPath.NAME_SEPARATOR, FontUtil.rightArrow(UIUtil.getLabelFont()));
       ColorSettingsPage settingsPage = baseDescriptor.first;
       String style = "<div style=\"text-align:right\" vertical-align=\"top\">";
       String tooltipText;
@@ -263,7 +254,10 @@ public class ColorAndFontDescriptionPanel extends JPanel implements OptionsPanel
     myBackgroundChooser.setEditable(isEditEnabled);
   }
 
-  public void apply(@NotNull ColorAndFontDescription description, EditorColorsScheme scheme) {
+  public void apply(@NotNull EditorSchemeAttributeDescriptor attrDescription, EditorColorsScheme scheme) {
+    if (!(attrDescription instanceof ColorAndFontDescription)) return;
+    ColorAndFontDescription description = (ColorAndFontDescription)attrDescription;
+
     description.setInherited(myInheritAttributesBox.isSelected());
     if (description.isInherited()) {
       TextAttributes baseAttributes = description.getBaseAttributes();
diff --git a/platform/lang-impl/src/com/intellij/application/options/colors/ColorAndFontGlobalState.java b/platform/lang-impl/src/com/intellij/application/options/colors/ColorAndFontGlobalState.java
new file mode 100644 (file)
index 0000000..4dc58d3
--- /dev/null
@@ -0,0 +1,112 @@
+/*
+ * Copyright 2000-2016 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.intellij.application.options.colors;
+
+import com.intellij.codeHighlighting.RainbowHighlighter;
+import com.intellij.codeInsight.daemon.DaemonCodeAnalyzer;
+import com.intellij.lang.Language;
+import com.intellij.openapi.editor.Editor;
+import com.intellij.openapi.editor.EditorFactory;
+import com.intellij.openapi.project.Project;
+import com.intellij.psi.PsiDocumentManager;
+import com.intellij.psi.PsiFile;
+import com.intellij.util.EventDispatcher;
+import org.jetbrains.annotations.Contract;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+
+import java.util.HashMap;
+import java.util.Map;
+
+public class ColorAndFontGlobalState {
+  private final EventDispatcher<ColorAndFontSettingsListener> myDispatcher = EventDispatcher.create(ColorAndFontSettingsListener.class);
+  private HashMap<Language, Boolean> myLanguage2RainbowEnabled = new HashMap<>();
+  private final ColorAndFontGlobalState myReferenceState;
+
+  @Nullable
+  @Contract("null -> !null")
+  public Boolean isRainbowOn(@Nullable Language language) {
+    assert myReferenceState != null;
+    if (myLanguage2RainbowEnabled.containsKey(language)) {
+      return myLanguage2RainbowEnabled.get(language);
+    }
+    Boolean rainbowOn = RainbowHighlighter.isRainbowEnabled(language);
+    myReferenceState.myLanguage2RainbowEnabled.put(language, rainbowOn);
+    myLanguage2RainbowEnabled.put(language, rainbowOn);
+    return rainbowOn;
+  }
+
+  public boolean isRainbowOnWithInheritance(@Nullable Language language) {
+    Boolean value = isRainbowOn(language);
+    return value == null ? isRainbowOn(null) : value.booleanValue();
+  }
+
+  public void setRainbowOn(@Nullable Language language, @Nullable Boolean rainbowOn) {
+    assert myReferenceState != null;
+    myLanguage2RainbowEnabled.put(language, rainbowOn);
+  }
+
+  private ColorAndFontGlobalState(@SuppressWarnings("UnusedParameters") boolean unused) {
+    myReferenceState = null;
+  }
+
+  public ColorAndFontGlobalState() {
+    myReferenceState = new ColorAndFontGlobalState(true);
+    copyFrom(myReferenceState); //be ready to global data extension
+  }
+
+  private void copyFrom(@NotNull ColorAndFontGlobalState state) {
+    assert this != state;
+    myLanguage2RainbowEnabled = new HashMap<>(state.myLanguage2RainbowEnabled);
+  }
+
+  public void apply() {
+    for (Map.Entry<Language, Boolean> entry : myLanguage2RainbowEnabled.entrySet()) {
+      RainbowHighlighter.setRainbowEnabled(entry.getKey(), entry.getValue());
+    }
+    Editor[] allEditors = EditorFactory.getInstance().getAllEditors();
+    for (Editor editor : allEditors) {
+      final Project project = editor.getProject();
+      if (project != null) {
+        PsiFile file = PsiDocumentManager.getInstance(project).getPsiFile(editor.getDocument());
+        if (file != null) {
+          DaemonCodeAnalyzer.getInstance(project).restart(file);
+        }
+      }
+    }
+    myReferenceState.copyFrom(this);
+  }
+
+  public void addListener(@NotNull ColorAndFontSettingsListener listener) {
+    myDispatcher.addListener(listener);
+  }
+
+  public void stateChanged() {
+    myDispatcher.getMulticaster().settingsChanged();
+  }
+
+  public boolean isModified() {
+    return !myLanguage2RainbowEnabled.equals(myReferenceState.myLanguage2RainbowEnabled);
+  }
+
+  public boolean isModified(@Nullable Language language) {
+    return myLanguage2RainbowEnabled.get(language) != myReferenceState.myLanguage2RainbowEnabled.get(language);
+  }
+
+  public void reset() {
+    copyFrom(myReferenceState);
+  }
+}
index 5bb1e1e11a40be20f0f796f9a16f8e8da5cf550d..e090a1f2e08bdf40720e2f74d32a48a5a36b0cc1 100644 (file)
@@ -27,10 +27,7 @@ import com.intellij.ide.util.PropertiesComponent;
 import com.intellij.openapi.Disposable;
 import com.intellij.openapi.application.ApplicationBundle;
 import com.intellij.openapi.application.ApplicationNamesInfo;
-import com.intellij.openapi.editor.colors.ColorKey;
-import com.intellij.openapi.editor.colors.EditorColorsManager;
-import com.intellij.openapi.editor.colors.EditorColorsScheme;
-import com.intellij.openapi.editor.colors.TextAttributesKey;
+import com.intellij.openapi.editor.colors.*;
 import com.intellij.openapi.editor.colors.impl.*;
 import com.intellij.openapi.editor.markup.EffectType;
 import com.intellij.openapi.editor.markup.TextAttributes;
@@ -77,6 +74,9 @@ public class ColorAndFontOptions extends SearchableConfigurable.Parent.Abstract
 
   private Map<String, MyColorScheme> mySchemes;
   private MyColorScheme mySelectedScheme;
+
+  private final ColorAndFontGlobalState myColorAndFontGlobalState = new ColorAndFontGlobalState();
+
   public static final String FILE_STATUS_GROUP = ApplicationBundle.message("title.file.status");
   public static final String SCOPES_GROUP = ApplicationBundle.message("title.scope.based");
 
@@ -94,6 +94,10 @@ public class ColorAndFontOptions extends SearchableConfigurable.Parent.Abstract
   private boolean myDisposeCompleted = false;
   private final Disposable myDisposable = Disposer.newDisposable();
 
+  public ColorAndFontGlobalState getColorAndFontGlobalState() {
+    return myColorAndFontGlobalState;
+  }
+
   @Override
   public boolean isModified() {
     boolean listModified = isSchemeListModified();
@@ -106,7 +110,7 @@ public class ColorAndFontOptions extends SearchableConfigurable.Parent.Abstract
     return listModified;
   }
 
-  private boolean isSchemeListModified(){
+  private boolean isSchemeListModified() {
     if (mySomeSchemesDeleted) return true;
 
     if (!mySelectedScheme.getName().equals(EditorColorsManager.getInstance().getGlobalScheme().getName())) return true;
@@ -196,7 +200,7 @@ public class ColorAndFontOptions extends SearchableConfigurable.Parent.Abstract
 
     clone.setName(name);
     MyColorScheme newScheme = new MyColorScheme(clone);
-    initScheme(newScheme);
+    initScheme(myColorAndFontGlobalState, newScheme);
 
     newScheme.setIsNew();
 
@@ -207,7 +211,7 @@ public class ColorAndFontOptions extends SearchableConfigurable.Parent.Abstract
 
   public void addImportedScheme(@NotNull EditorColorsScheme imported) {
     MyColorScheme newScheme = new MyColorScheme(imported);
-    initScheme(newScheme);
+    initScheme(myColorAndFontGlobalState, newScheme);
 
     mySchemes.put(imported.getName(), newScheme);
     selectScheme(newScheme.getName());
@@ -240,6 +244,8 @@ public class ColorAndFontOptions extends SearchableConfigurable.Parent.Abstract
     }
 
     try {
+      myColorAndFontGlobalState.apply();
+
       EditorColorsManager myColorsManager = EditorColorsManager.getInstance();
       SchemeManager<EditorColorsScheme> schemeManager = ((EditorColorsManagerImpl)myColorsManager).getSchemeManager();
 
@@ -488,10 +494,11 @@ public class ColorAndFontOptions extends SearchableConfigurable.Parent.Abstract
    }
 
   private void initAll() {
+    myColorAndFontGlobalState.reset();
     mySchemes = new THashMap<>();
     for (EditorColorsScheme allScheme : EditorColorsManager.getInstance().getAllSchemes()) {
       MyColorScheme schemeDelegate = new MyColorScheme(allScheme);
-      initScheme(schemeDelegate);
+      initScheme(myColorAndFontGlobalState, schemeDelegate);
       mySchemes.put(schemeDelegate.getName(), schemeDelegate);
     }
 
@@ -499,32 +506,55 @@ public class ColorAndFontOptions extends SearchableConfigurable.Parent.Abstract
     assert mySelectedScheme != null : EditorColorsManager.getInstance().getGlobalScheme().getName() + "; myschemes=" + mySchemes;
   }
 
-  private static void initScheme(@NotNull MyColorScheme scheme) {
+  private static void initScheme(@NotNull ColorAndFontGlobalState colorAndFontGlobalState, @NotNull MyColorScheme scheme) {
     List<EditorSchemeAttributeDescriptor> descriptions = new ArrayList<>();
-    initPluggedDescriptions(descriptions, scheme);
+    initPluggedDescriptions(colorAndFontGlobalState, descriptions, scheme);
     initFileStatusDescriptors(descriptions, scheme);
     initScopesDescriptors(descriptions, scheme);
 
     scheme.setDescriptors(descriptions.toArray(new EditorSchemeAttributeDescriptor[descriptions.size()]));
   }
 
-  private static void initPluggedDescriptions(@NotNull List<EditorSchemeAttributeDescriptor> descriptions, @NotNull MyColorScheme scheme) {
+  private static void initPluggedDescriptions(@NotNull ColorAndFontGlobalState colorAndFontGlobalState,
+                                              @NotNull List<EditorSchemeAttributeDescriptor> descriptions,
+                                              @NotNull MyColorScheme scheme) {
     ColorSettingsPage[] pages = ColorSettingsPages.getInstance().getRegisteredPages();
     for (ColorSettingsPage page : pages) {
-      initDescriptions(page, descriptions, scheme);
+      initDescriptions(colorAndFontGlobalState, page, descriptions, scheme);
     }
     for (ColorAndFontDescriptorsProvider provider : Extensions.getExtensions(ColorAndFontDescriptorsProvider.EP_NAME)) {
-      initDescriptions(provider, descriptions, scheme);
+      initDescriptions(colorAndFontGlobalState, provider, descriptions, scheme);
     }
   }
 
-  private static void initDescriptions(@NotNull ColorAndFontDescriptorsProvider provider,
+  private static void initDescriptions(@NotNull ColorAndFontGlobalState colorAndFontGlobalState,
+                                       @NotNull ColorAndFontDescriptorsProvider provider,
                                        @NotNull List<EditorSchemeAttributeDescriptor> descriptions,
                                        @NotNull MyColorScheme scheme) {
     String group = provider.getDisplayName();
     List<AttributesDescriptor> attributeDescriptors = ColorSettingsUtil.getAllAttributeDescriptors(provider);
+    //todo: single point configuration?
+    if (provider instanceof RainbowColorSettingsPage) {
+      descriptions.add(new RainbowAttributeDescriptor(((RainbowColorSettingsPage)provider).getLanguage(),
+                                                      colorAndFontGlobalState,
+                                                      group,
+                                                      ApplicationBundle.message("rainbow.option.panel.display.name"),
+                                                      scheme,
+                                                      scheme.getRainbowState()));
+    }
     for (AttributesDescriptor descriptor : attributeDescriptors) {
       addSchemedDescription(descriptions, descriptor.getDisplayName(), group, descriptor.getKey(), scheme, null, null);
+    //  if (provider instanceof RainbowColorSettingsPage
+    //      && ((RainbowColorSettingsPage)provider).isRainbowType(descriptor.getKey())) {
+    //    //todo: joined sub-descriptor?
+    //    descriptions.add(new RainbowAttributeDescriptor(group,
+    //                                                    descriptor.getDisplayName()
+    //                                                    + EditorSchemeAttributeDescriptorWithPath.NAME_SEPARATOR
+    //                                                    + ApplicationBundle.message("rainbow.option.panel.display.name"),
+    //                                                    scheme,
+    //                                                    scheme.getInitRainbowState(),
+    //                                                    scheme.getCurrentRainbowState()));
+    //  }
     }
 
     ColorDescriptor[] colorDescriptors = provider.getColorDescriptors();
@@ -984,6 +1014,7 @@ public class ColorAndFontOptions extends SearchableConfigurable.Parent.Abstract
     private EditorSchemeAttributeDescriptor[] myDescriptors;
     private String                            myName;
     private boolean myIsNew = false;
+    private RainbowColorsInSchemeState myRainbowState;
 
     private MyColorScheme(@NotNull EditorColorsScheme parentScheme) {
       super(parentScheme);
@@ -1113,6 +1144,13 @@ public class ColorAndFontOptions extends SearchableConfigurable.Parent.Abstract
       }
       return false;
     }
+
+    public RainbowColorsInSchemeState getRainbowState() {
+      if (myRainbowState == null) {
+        myRainbowState = new RainbowColorsInSchemeState(this);
+      }
+      return myRainbowState;
+    }
   }
 
   @Override
index 07507167eb6a5f1003c7b2f644da8423643dfbae..d9d216bcaf5c16876a9f875021f86d8343d230fd 100644 (file)
@@ -15,6 +15,8 @@
  */
 package com.intellij.application.options.colors;
 
+import com.intellij.openapi.editor.colors.EditorSchemeAttributeDescriptor;
+import com.intellij.openapi.editor.colors.EditorSchemeAttributeDescriptorWithPath;
 import com.intellij.openapi.util.text.StringUtil;
 import com.intellij.ui.TreeSpeedSearch;
 import com.intellij.ui.treeStructure.Tree;
@@ -26,6 +28,8 @@ import org.jetbrains.annotations.Nullable;
 import javax.swing.tree.*;
 import java.util.*;
 
+import static com.intellij.openapi.editor.colors.EditorSchemeAttributeDescriptorWithPath.NAME_SEPARATOR;
+
 /**
  * @author Rustam Vishnyakov
  */
@@ -33,8 +37,6 @@ public class ColorOptionsTree extends Tree {
   private final String myCategoryName;
   private final DefaultTreeModel myTreeModel;
 
-  public final static String NAME_SEPARATOR = "//";
-
   private static final Comparator<EditorSchemeAttributeDescriptor> ATTR_COMPARATOR =
     (o1, o2) -> StringUtil.naturalCompare(o1.toString(), o2.toString());
 
@@ -78,9 +80,9 @@ public class ColorOptionsTree extends Tree {
   }
 
   @Nullable
-  public ColorAndFontDescription getSelectedDescriptor() {
+  public EditorSchemeAttributeDescriptor getSelectedDescriptor() {
     Object selectedValue = getSelectedValue();
-    return selectedValue instanceof ColorAndFontDescription ? (ColorAndFontDescription)selectedValue : null;
+    return selectedValue instanceof EditorSchemeAttributeDescriptor ? (EditorSchemeAttributeDescriptor)selectedValue : null;
   }
 
   @Nullable
@@ -138,7 +140,7 @@ public class ColorOptionsTree extends Tree {
 
   @Nullable
   private static List<String> extractPath(@NotNull EditorSchemeAttributeDescriptor descriptor) {
-    if (descriptor instanceof ColorAndFontDescription) {
+    if (descriptor instanceof EditorSchemeAttributeDescriptorWithPath) {
       String name = descriptor.toString();
       List<String> path = new ArrayList<>();
       int separatorStart = name.indexOf(NAME_SEPARATOR);
index 0084ff8cc51335d51a94114c393fb55b9be651b2..17654f1e3516ec5c247973c9824f79ced4972715 100644 (file)
@@ -72,10 +72,6 @@ public class ColorSettingsUtil {
     return true;        
   }
 
-  static boolean isSharedScheme(EditorColorsScheme selected) {
-      return false;
-  }
-
   private static void addInspectionSeverityAttributes(List<AttributesDescriptor> descriptors) {
     descriptors.add(new AttributesDescriptor(OptionsBundle.message("options.java.attribute.descriptor.unknown.symbol"), CodeInsightColors.WRONG_REFERENCES_ATTRIBUTES));
     descriptors.add(new AttributesDescriptor(OptionsBundle.message("options.java.attribute.descriptor.deprecated.symbol"), CodeInsightColors.DEPRECATED_ATTRIBUTES));
diff --git a/platform/lang-impl/src/com/intellij/application/options/colors/CustomizedSwitcherPanel.java b/platform/lang-impl/src/com/intellij/application/options/colors/CustomizedSwitcherPanel.java
new file mode 100644 (file)
index 0000000..48d7d30
--- /dev/null
@@ -0,0 +1,254 @@
+/*
+ * Copyright 2000-2016 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.intellij.application.options.colors;
+
+import com.intellij.application.options.colors.highlighting.HighlightData;
+import com.intellij.codeHighlighting.RainbowHighlighter;
+import com.intellij.openapi.application.ApplicationManager;
+import com.intellij.openapi.editor.colors.EditorColorsScheme;
+import com.intellij.openapi.editor.colors.EditorSchemeAttributeDescriptor;
+import com.intellij.openapi.editor.colors.TextAttributesKey;
+import com.intellij.openapi.editor.ex.DocumentEx;
+import com.intellij.openapi.editor.ex.EditorEx;
+import com.intellij.openapi.options.colors.ColorSettingsPage;
+import com.intellij.openapi.options.colors.RainbowColorSettingsPage;
+import com.intellij.openapi.util.Pair;
+import com.intellij.openapi.util.TextRange;
+import com.intellij.util.ui.UIUtil;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+
+import javax.swing.*;
+import java.awt.*;
+import java.util.*;
+import java.util.List;
+
+class CustomizedSwitcherPanel extends JPanel implements OptionsPanelImpl.ColorDescriptionPanel {
+  private ColorAndFontGlobalState myColorAndFontGlobalState;
+  private ColorSettingsPage myPage;
+
+  private PreviewPanel myPreviewPanel;
+  private ColorAndFontDescriptionPanel myColorAndFontPanel;
+  private RainbowDescriptionPanel myRainbowPanel;
+
+  private OptionsPanelImpl.ColorDescriptionPanel myActive;
+
+  public CustomizedSwitcherPanel(@NotNull ColorAndFontGlobalState colorAndFontGlobalState,
+                                 @Nullable PreviewPanel previewPanel,
+                                 @Nullable ColorSettingsPage page) {
+    super();
+    myColorAndFontGlobalState = colorAndFontGlobalState;
+    myPage = page;
+    myPreviewPanel = previewPanel;
+
+    myRainbowPanel = new RainbowDescriptionPanel();
+    myColorAndFontPanel = new ColorAndFontDescriptionPanel();
+
+    Dimension sizeR = myRainbowPanel.getPreferredSize();
+    Dimension sizeC = myColorAndFontPanel.getPreferredSize();
+    Dimension preferredSize = new Dimension();
+    preferredSize.setSize(Math.max(sizeR.getWidth(), sizeC.getWidth()),
+                          Math.max(sizeR.getHeight(), sizeC.getHeight()));
+    setPreferredSize(preferredSize);
+  }
+
+  @NotNull
+  @Override
+  public JComponent getPanel() {
+    return this;
+  }
+
+  @Override
+  public void resetDefault() {
+    if (myActive != null) {
+      final PaintLocker locker = new PaintLocker(this);
+      try {
+        setPreferredSize(getSize());// froze [this] size
+        remove(myActive.getPanel());
+        myActive = null;
+      }
+      finally {
+        locker.release();
+      }
+    }
+  }
+
+  @Override
+  public void reset(@NotNull EditorSchemeAttributeDescriptor descriptor) {
+    JComponent oldPanel = myActive == null ? null : myActive.getPanel();
+    myActive = getPanelForDescriptor(descriptor);
+    JComponent newPanel = myActive == null ? null : myActive.getPanel();
+
+    if (oldPanel != newPanel) {
+      final PaintLocker locker = new PaintLocker(this);
+      try {
+        if (oldPanel != null) {
+          remove(oldPanel);
+        }
+        if (newPanel != null) {
+          setPreferredSize(null);// make [this] resizable
+          add(newPanel);
+        }
+      }
+      finally {
+        locker.release();
+      }
+    }
+    if (myActive != null) {
+      myActive.reset(descriptor);
+    }
+    updatePreviewPanel(descriptor);
+  }
+
+  protected OptionsPanelImpl.ColorDescriptionPanel getPanelForDescriptor(@NotNull EditorSchemeAttributeDescriptor descriptor) {
+    if (descriptor instanceof RainbowAttributeDescriptor) {
+      return myRainbowPanel;
+    }
+    else if (descriptor instanceof ColorAndFontDescription) {
+      return myColorAndFontPanel;
+    }
+    return null;
+  }
+
+  private void addRainbowHighlighting(@NotNull DocumentEx document,
+                                      @Nullable List<HighlightData> showLineData,
+                                      @NotNull List<HighlightData> data,
+                                      @NotNull TextAttributesKey[] rainbowTempKeys) {
+    int colorCount = rainbowTempKeys.length;
+    if (colorCount != 0) {
+      List<HighlightData> newData = new ArrayList<>();
+      if (showLineData != null) newData.addAll(showLineData);
+
+      int[] index2usage = new int[colorCount];
+      for (HighlightData d : data) {
+        if (((RainbowColorSettingsPage)myPage).isRainbowType(d.getHighlightKey())) {
+          String id = document.getText(TextRange.create(d.getStartOffset(), d.getEndOffset()));
+
+          int index = RainbowHighlighter.getColorIndex(index2usage, RainbowHighlighter.hashColor(id, colorCount), colorCount);
+          ++index2usage[index];
+          HighlightData rainbow = new HighlightData(d.getStartOffset(), d.getEndOffset(), rainbowTempKeys[index]);
+
+          //fixme: twisted coloring in editor. We need add rainbow-tag twice.
+          newData.add(rainbow);
+          newData.add(d);
+          newData.add(rainbow);
+        }
+        else {
+          newData.add(d);
+        }
+      }
+      data.clear();
+      data.addAll(newData);
+    }
+  }
+
+  @Override
+  public void apply(@NotNull EditorSchemeAttributeDescriptor descriptor, EditorColorsScheme scheme) {
+    if (myActive != null) {
+      myActive.apply(descriptor, scheme);
+      updatePreviewPanel(descriptor);
+    }
+  }
+
+  protected void updatePreviewPanel(@NotNull EditorSchemeAttributeDescriptor descriptor) {
+    if (!(myPreviewPanel instanceof SimpleEditorPreview)) return;
+      UIUtil.invokeAndWaitIfNeeded((Runnable)() -> ApplicationManager.getApplication().runWriteAction(() -> {
+        SimpleEditorPreview simpleEditorPreview = (SimpleEditorPreview)myPreviewPanel;
+        try {
+          simpleEditorPreview.setNavigationBlocked(true);
+          String demoText = (myPage instanceof RainbowColorSettingsPage
+                             && descriptor instanceof RainbowAttributeDescriptor)
+                            ? ((RainbowColorSettingsPage)myPage).getRainbowDemoText()
+                            : myPage.getDemoText();
+          List<HighlightData> showLineData = null;
+
+          if (myPage instanceof RainbowColorSettingsPage
+              && myColorAndFontGlobalState.isRainbowOnWithInheritance(((RainbowColorSettingsPage)myPage).getLanguage())) {
+            RainbowHighlighter highlighter = new RainbowHighlighter(descriptor.getScheme());
+            TextAttributesKey[] tempKeys = highlighter.getRainbowTempKeys();
+            EditorEx editor = simpleEditorPreview.getEditor();
+            if (myActive == myRainbowPanel) {
+              Pair<String, List<HighlightData>> demo = getColorDemoLine(highlighter, tempKeys);
+              simpleEditorPreview.setDemoText(demo.first + "\n" + demoText);
+              showLineData = demo.second;
+            }
+            else {
+              simpleEditorPreview.setDemoText(demoText);
+            }
+            addRainbowHighlighting(editor.getDocument(),
+                                   showLineData,
+                                   simpleEditorPreview.getHighlightDataForExtension(),
+                                   tempKeys);
+          }
+          else {
+            simpleEditorPreview.setDemoText(demoText);
+          }
+
+          simpleEditorPreview.updateView();
+          if (descriptor instanceof RainbowAttributeDescriptor) {
+            simpleEditorPreview.scrollHighlightInView(showLineData);
+          }
+        } finally {
+          simpleEditorPreview.setNavigationBlocked(false);
+        }
+      }));
+  }
+
+  @NotNull
+  private static Pair<String, List<HighlightData>> getColorDemoLine(RainbowHighlighter highlighter, TextAttributesKey[] tempKeys) {
+    int colorsCount = highlighter.getColorsCount();
+    int stopCount = RainbowHighlighter.RAINBOW_COLOR_KEYS.length;
+    List<HighlightData> markup = new ArrayList<>(colorsCount);
+    StringBuilder sb = new StringBuilder();
+    int pos = 0;
+    int i = 0;
+    for (TextAttributesKey key : tempKeys) {
+      String toAdd = (i % stopCount == 0) ? "Stop#" + String.valueOf(i / stopCount + 1) : "T";
+      int end = pos + toAdd.length();
+      markup.add(new HighlightData(pos, end, key));
+      if (sb.length() != 0) {
+        sb.append(" ");
+      }
+      sb.append(toAdd);
+      pos = end + 1;
+      ++i;
+    }
+    return Pair.create(sb.toString(), markup);
+  }
+
+  @Override
+  public void addListener(@NotNull Listener listener) {
+    myRainbowPanel.addListener(listener);
+    myColorAndFontPanel.addListener(listener);
+  }
+
+  private static class PaintLocker {
+    private Container myPaintHolder;
+    private boolean myPaintState;
+
+    public PaintLocker(@NotNull JComponent component) {
+      myPaintHolder = component.getParent();
+      myPaintState = myPaintHolder.getIgnoreRepaint();
+      myPaintHolder.setIgnoreRepaint(true);
+    }
+
+    public void release() {
+      myPaintHolder.validate();
+      myPaintHolder.setIgnoreRepaint(myPaintState);
+      myPaintHolder.repaint();
+    }
+  }
+}
index 35c49f0653eb1729650bdbd78b295594c1970384..6e43fa0c730659613a812eae0d64433ca469400a 100644 (file)
@@ -325,7 +325,7 @@ public class FontOptions extends JPanel implements OptionsPanel{
   public boolean updateDescription(boolean modified) {
     EditorColorsScheme scheme = myOptions.getSelectedScheme();
 
-    if (modified && (ColorAndFontOptions.isReadOnly(scheme) || ColorSettingsUtil.isSharedScheme(scheme))) {
+    if (modified && ColorAndFontOptions.isReadOnly(scheme)) {
       return false;
     }
 
index 101ef5ec47974d40a9f934f1c47fba99287a9ba6..b7388831cd6c29d3a56a1acc202ea1bbcc57cff6 100644 (file)
@@ -20,6 +20,7 @@ import com.intellij.openapi.application.ApplicationBundle;
 import com.intellij.openapi.application.ApplicationManager;
 import com.intellij.openapi.editor.colors.EditorColorsScheme;
 import com.intellij.openapi.options.colors.ColorSettingsPage;
+import com.intellij.openapi.editor.colors.EditorSchemeAttributeDescriptor;
 import com.intellij.openapi.util.text.StringUtil;
 import com.intellij.ui.GuiUtils;
 import org.jetbrains.annotations.NotNull;
@@ -100,10 +101,8 @@ public class NewColorAndFontPanel extends JPanel {
     optionsPanel.addListener(new ColorAndFontSettingsListener.Abstract() {
       @Override
       public void settingsChanged() {
-        if (schemesPanel.updateDescription(true)) {
-          optionsPanel.applyChangesToScheme();
-          previewPanel.updateView();
-        }
+        optionsPanel.applyChangesToScheme();
+        previewPanel.updateView();
       }
 
       @Override
@@ -133,8 +132,9 @@ public class NewColorAndFontPanel extends JPanel {
                                             Collection<String> optionList, ColorSettingsPage page) {
     final SchemesPanel schemesPanel = new SchemesPanel(options);
 
-    final OptionsPanel optionsPanel = new OptionsPanelImpl(options, schemesPanel, category);
-
+    final OptionsPanel optionsPanel = new OptionsPanelImpl(
+      options, schemesPanel, category,
+      new CustomizedSwitcherPanel(options.getColorAndFontGlobalState(), previewPanel, page));
 
     return new NewColorAndFontPanel(schemesPanel, optionsPanel, previewPanel, category, optionList, page);
   }
index 5f4075c9abc56a7e8a339a47c207ed23d4c3f4c1..fe9bf12d27b0548b3d1341c49b059839305a4231 100644 (file)
@@ -20,11 +20,11 @@ import com.intellij.ide.DataManager;
 import com.intellij.ide.util.PropertiesComponent;
 import com.intellij.openapi.editor.colors.EditorColorsScheme;
 import com.intellij.openapi.options.SearchableConfigurable;
+import com.intellij.openapi.editor.colors.EditorSchemeAttributeDescriptor;
 import com.intellij.openapi.options.ex.Settings;
 import com.intellij.openapi.util.ActionCallback;
 import com.intellij.ui.ScrollPaneFactory;
 import com.intellij.util.EventDispatcher;
-import com.intellij.util.ui.JBUI;
 import org.jetbrains.annotations.NotNull;
 
 import javax.swing.*;
@@ -74,6 +74,7 @@ public class OptionsPanelImpl extends JPanel implements OptionsPanel {
       @Override
       public void onSettingsChanged(ActionEvent e) {
         myDispatcher.getMulticaster().settingsChanged();
+        myOptions.getColorAndFontGlobalState().stateChanged();
       }
 
       @Override
@@ -99,6 +100,17 @@ public class OptionsPanelImpl extends JPanel implements OptionsPanel {
       }
     });
 
+    myOptions.getColorAndFontGlobalState().addListener(new ColorAndFontSettingsListener.Abstract() {
+      @Override
+      public void settingsChanged() {
+        if (!mySchemesProvider.areSchemesLoaded()) return;
+        if (myOptionsTree.getSelectedValue() != null) {
+          // update options & preview after global state change
+          processListValueChanged();
+        }
+      }
+    });
+
     myOptionsTree = new ColorOptionsTree(myCategoryName);
 
     myOptionsTree.addTreeSelectionListener(new TreeSelectionListener() {
@@ -122,7 +134,9 @@ public class OptionsPanelImpl extends JPanel implements OptionsPanel {
 
   private void processListValueChanged() {
     Object selectedValue = myOptionsTree.getSelectedValue();
-    ColorAndFontDescription description = selectedValue instanceof ColorAndFontDescription ? (ColorAndFontDescription)selectedValue : null;
+    EditorSchemeAttributeDescriptor description = selectedValue instanceof EditorSchemeAttributeDescriptor
+                                                  ? (EditorSchemeAttributeDescriptor)selectedValue
+                                                  : null;
     if (description == null) {
       if (selectedValue == null) {
         String preselectedType = myProperties.getValue(SELECTED_COLOR_OPTION_PROPERTY);
@@ -164,7 +178,7 @@ public class OptionsPanelImpl extends JPanel implements OptionsPanel {
 
   @Override
   public void applyChangesToScheme() {
-    ColorAndFontDescription descriptor = myOptionsTree.getSelectedDescriptor();
+    EditorSchemeAttributeDescriptor descriptor = myOptionsTree.getSelectedDescriptor();
     if (descriptor != null) {
       myOptionsPanel.apply(descriptor, myOptions.getSelectedScheme());
     }
@@ -193,9 +207,9 @@ public class OptionsPanelImpl extends JPanel implements OptionsPanel {
 
     void resetDefault();
 
-    void reset(@NotNull ColorAndFontDescription description);
+    void reset(@NotNull EditorSchemeAttributeDescriptor description);
 
-    void apply(@NotNull ColorAndFontDescription descriptor, EditorColorsScheme scheme);
+    void apply(@NotNull EditorSchemeAttributeDescriptor descriptor, EditorColorsScheme scheme);
 
     void addListener(@NotNull Listener listener);
 
diff --git a/platform/lang-impl/src/com/intellij/application/options/colors/RainbowAttributeDescriptor.java b/platform/lang-impl/src/com/intellij/application/options/colors/RainbowAttributeDescriptor.java
new file mode 100644 (file)
index 0000000..59d1b9e
--- /dev/null
@@ -0,0 +1,100 @@
+/*
+ * Copyright 2000-2016 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.intellij.application.options.colors;
+
+import com.intellij.codeHighlighting.RainbowHighlighter;
+import com.intellij.lang.Language;
+import com.intellij.openapi.editor.colors.EditorColorsScheme;
+import com.intellij.openapi.editor.colors.EditorSchemeAttributeDescriptorWithPath;
+import com.intellij.openapi.util.Pair;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+
+import java.awt.*;
+import java.util.List;
+
+class RainbowAttributeDescriptor implements EditorSchemeAttributeDescriptorWithPath {
+  private final String myGroup;
+  private final ColorAndFontGlobalState myColorAndFontGlobalState;
+  private final String myDisplayName;
+  private final EditorColorsScheme myScheme;
+  private final Language myLanguage;
+  private final RainbowColorsInSchemeState myRainbowColorsInSchemaState;
+
+  public ColorAndFontGlobalState getColorAndFontGlobalState() {
+    return myColorAndFontGlobalState;
+  }
+
+  public RainbowAttributeDescriptor(@Nullable Language language,
+                                    @NotNull ColorAndFontGlobalState colorAndFontGlobalState,
+                                    @NotNull String group,
+                                    @NotNull String displayNameWithPath,
+                                    @NotNull EditorColorsScheme scheme,
+                                    @NotNull RainbowColorsInSchemeState rainbowState) {
+    myLanguage = language;
+    myColorAndFontGlobalState = colorAndFontGlobalState;
+    myDisplayName = displayNameWithPath;
+    myRainbowColorsInSchemaState = rainbowState;
+    myScheme = scheme;
+    myGroup = group;
+  }
+
+  @Override
+  public String toString() {
+    return myDisplayName;
+  }
+
+  @Override
+  public String getGroup() {
+    return myGroup;
+  }
+
+  @Override
+  public String getType() {
+    return RainbowHighlighter.RAINBOW_TYPE;
+  }
+
+  @Override
+  public EditorColorsScheme getScheme() {
+    return myScheme;
+  }
+
+  @Override
+  public void apply(@NotNull EditorColorsScheme scheme) {
+    if (myLanguage == null) {
+      myRainbowColorsInSchemaState.apply(scheme);
+    }
+    // see myColorAndFontGlobalState apply
+  }
+
+  @Override
+  public boolean isModified() {
+    return (myLanguage == null && myRainbowColorsInSchemaState.isModified())
+           || myColorAndFontGlobalState.isModified(myLanguage);
+  }
+
+  public List<Pair<Boolean, Color>> getRainbowColorsInSchemaState() {
+    return myRainbowColorsInSchemaState.getInheritanceAndColors();
+  }
+
+  public Color getDefaultColor(int index) {
+    return RainbowHighlighter.RAINBOW_COLOR_KEYS[index].getDefaultAttributes().getForegroundColor();
+  }
+
+  public Language getLanguage() {
+    return myLanguage;
+  }
+}
diff --git a/platform/lang-impl/src/com/intellij/application/options/colors/RainbowColorsInSchemeState.java b/platform/lang-impl/src/com/intellij/application/options/colors/RainbowColorsInSchemeState.java
new file mode 100644 (file)
index 0000000..3b486c4
--- /dev/null
@@ -0,0 +1,90 @@
+/*
+ * Copyright 2000-2016 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.intellij.application.options.colors;
+
+import com.intellij.codeHighlighting.RainbowHighlighter;
+import com.intellij.openapi.editor.colors.EditorColorsScheme;
+import com.intellij.openapi.editor.colors.TextAttributesKey;
+import com.intellij.openapi.editor.markup.TextAttributes;
+import com.intellij.openapi.util.Pair;
+import org.jetbrains.annotations.NotNull;
+
+import java.awt.*;
+import java.util.*;
+import java.util.List;
+
+public class RainbowColorsInSchemeState {
+  private final RainbowColorsInSchemeState myReferenceState;
+  private final List<Pair<Boolean, Color>> myInheritanceAndColors = new ArrayList<>();
+
+  public List<Pair<Boolean, Color>> getInheritanceAndColors() {
+    return myInheritanceAndColors;
+  }
+
+  private RainbowColorsInSchemeState(@NotNull EditorColorsScheme scheme,
+                                     @SuppressWarnings("UnusedParameters") boolean unused) {
+    myReferenceState = null;
+    for (TextAttributesKey rainbowKey : RainbowHighlighter.RAINBOW_COLOR_KEYS) {
+      myInheritanceAndColors.add(getColorStateFromScheme(scheme, rainbowKey));
+    }
+  }
+
+  public RainbowColorsInSchemeState(@NotNull EditorColorsScheme scheme) {
+    myReferenceState = new RainbowColorsInSchemeState(scheme, true);
+    copyFrom(myReferenceState);
+  }
+
+  private void copyFrom(@NotNull RainbowColorsInSchemeState state) {
+    assert this != state;
+    myInheritanceAndColors.clear();
+    myInheritanceAndColors.addAll(state.myInheritanceAndColors);
+  }
+
+  public void apply(@NotNull EditorColorsScheme scheme) {
+    int i = 0;
+    for (TextAttributesKey rainbowKey : RainbowHighlighter.RAINBOW_COLOR_KEYS) {
+      Pair<Boolean, Color> pair = myInheritanceAndColors.get(i);
+      scheme.setAttributes(rainbowKey, pair.first ? new TextAttributes(pair.second, null, null, null, Font.PLAIN)
+                                                  : rainbowKey.getDefaultAttributes());
+      ++i;
+    }
+    //myReferenceState.copyFrom(this);
+  }
+
+  @NotNull
+  private static Pair<Boolean, Color> getColorStateFromScheme(@NotNull EditorColorsScheme scheme, TextAttributesKey rainbowKey) {
+    TextAttributes schemeAttributes = scheme.getAttributes(rainbowKey);
+    @NotNull Color defaultRainbow = rainbowKey.getDefaultAttributes().getForegroundColor();
+    Pair<Boolean, Color> pair;
+    if (schemeAttributes == null) {
+      pair = Pair.create(false, defaultRainbow);
+    }
+    else {
+      Color schemeColor = schemeAttributes.getForegroundColor();
+      if (schemeColor == null) {
+        pair = Pair.create(false, defaultRainbow);
+      }
+      else {
+        pair = Pair.create(!defaultRainbow.equals(schemeColor), schemeColor);
+      }
+    }
+    return pair;
+  }
+
+  public boolean isModified() {
+    return !myInheritanceAndColors.equals(myReferenceState.myInheritanceAndColors);
+  }
+}
diff --git a/platform/lang-impl/src/com/intellij/application/options/colors/RainbowDescriptionPanel.form b/platform/lang-impl/src/com/intellij/application/options/colors/RainbowDescriptionPanel.form
new file mode 100644 (file)
index 0000000..163b460
--- /dev/null
@@ -0,0 +1,135 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<form xmlns="http://www.intellij.com/uidesigner/form/" version="1" bind-to-class="com.intellij.application.options.colors.RainbowDescriptionPanel">
+  <grid id="27dc6" binding="myPanel" layout-manager="GridLayoutManager" row-count="9" column-count="4" same-size-horizontally="false" same-size-vertically="false" hgap="-1" vgap="-1">
+    <margin top="0" left="10" bottom="10" right="10"/>
+    <constraints>
+      <xy x="20" y="20" width="378" height="417"/>
+    </constraints>
+    <properties/>
+    <border type="none"/>
+    <children>
+      <component id="fcf61" class="com.intellij.ui.components.JBCheckBox" binding="myRainbow">
+        <constraints>
+          <grid row="0" column="0" row-span="1" col-span="3" vsize-policy="0" hsize-policy="0" anchor="9" fill="0" indent="0" use-parent-layout="false"/>
+        </constraints>
+        <properties>
+          <text resource-bundle="messages/ApplicationBundle" key="checkbox.rainbow"/>
+        </properties>
+      </component>
+      <component id="5556e" class="javax.swing.JTextPane" binding="myGradientLabel">
+        <constraints>
+          <grid row="1" column="0" row-span="1" col-span="3" vsize-policy="0" hsize-policy="0" anchor="9" fill="0" indent="0" use-parent-layout="false"/>
+        </constraints>
+        <properties>
+          <text resource-bundle="messages/ApplicationBundle" key="label.override.gradient"/>
+        </properties>
+      </component>
+      <vspacer id="1f6f2">
+        <constraints>
+          <grid row="8" column="1" row-span="1" col-span="2" vsize-policy="6" hsize-policy="1" anchor="0" fill="2" indent="0" use-parent-layout="false"/>
+        </constraints>
+      </vspacer>
+      <component id="11363" class="com.intellij.ui.ColorPanel" binding="myStop1">
+        <constraints>
+          <grid row="2" column="2" row-span="1" col-span="1" vsize-policy="0" hsize-policy="0" anchor="4" fill="2" indent="0" use-parent-layout="false"/>
+        </constraints>
+        <properties/>
+      </component>
+      <component id="a303b" class="com.intellij.ui.ColorPanel" binding="myStop2">
+        <constraints>
+          <grid row="3" column="2" row-span="1" col-span="1" vsize-policy="0" hsize-policy="0" anchor="4" fill="2" indent="0" use-parent-layout="false"/>
+        </constraints>
+        <properties/>
+      </component>
+      <component id="1c10d" class="com.intellij.ui.ColorPanel" binding="myStop3">
+        <constraints>
+          <grid row="4" column="2" row-span="1" col-span="1" vsize-policy="0" hsize-policy="0" anchor="4" fill="2" indent="0" use-parent-layout="false"/>
+        </constraints>
+        <properties/>
+      </component>
+      <component id="8db13" class="com.intellij.ui.ColorPanel" binding="myStop4">
+        <constraints>
+          <grid row="5" column="2" row-span="1" col-span="1" vsize-policy="0" hsize-policy="0" anchor="4" fill="2" indent="0" use-parent-layout="false"/>
+        </constraints>
+        <properties/>
+      </component>
+      <component id="1b18c" class="com.intellij.ui.ColorPanel" binding="myStop5">
+        <constraints>
+          <grid row="6" column="2" row-span="1" col-span="1" vsize-policy="0" hsize-policy="0" anchor="4" fill="2" indent="0" use-parent-layout="false"/>
+        </constraints>
+        <properties/>
+      </component>
+      <hspacer id="13e59">
+        <constraints>
+          <grid row="7" column="3" row-span="1" col-span="1" vsize-policy="1" hsize-policy="6" anchor="0" fill="1" indent="0" use-parent-layout="false"/>
+        </constraints>
+      </hspacer>
+      <grid id="cf0d3" layout-manager="GridLayoutManager" row-count="2" column-count="2" same-size-horizontally="false" same-size-vertically="false" hgap="-1" vgap="-1">
+        <margin top="30" left="0" bottom="0" right="0"/>
+        <constraints>
+          <grid row="7" column="0" row-span="1" col-span="3" vsize-policy="0" hsize-policy="0" anchor="0" fill="3" indent="0" use-parent-layout="true"/>
+        </constraints>
+        <properties/>
+        <border type="none"/>
+        <children>
+          <component id="cf61c" class="com.intellij.ui.components.JBCheckBox" binding="myInheritAttributesBox">
+            <constraints>
+              <grid row="0" column="1" row-span="1" col-span="1" vsize-policy="0" hsize-policy="0" anchor="8" fill="0" indent="0" use-parent-layout="false"/>
+            </constraints>
+            <properties>
+              <text resource-bundle="messages/ApplicationBundle" key="label.inherit.attributes"/>
+            </properties>
+          </component>
+          <component id="6fbd2" class="javax.swing.JTextPane" binding="myInheritanceLabel">
+            <constraints>
+              <grid row="1" column="1" row-span="1" col-span="1" vsize-policy="0" hsize-policy="0" anchor="0" fill="3" indent="0" use-parent-layout="false"/>
+            </constraints>
+            <properties>
+              <text value="labl"/>
+            </properties>
+          </component>
+        </children>
+      </grid>
+      <component id="f26f6" class="com.intellij.ui.components.JBCheckBox" binding="myCbStop1">
+        <constraints>
+          <grid row="2" column="1" row-span="1" col-span="1" vsize-policy="0" hsize-policy="0" anchor="8" fill="0" indent="0" use-parent-layout="false"/>
+        </constraints>
+        <properties>
+          <text resource-bundle="messages/ApplicationBundle" key="checkbox.stop.1"/>
+        </properties>
+      </component>
+      <component id="e998a" class="com.intellij.ui.components.JBCheckBox" binding="myCbStop2">
+        <constraints>
+          <grid row="3" column="1" row-span="1" col-span="1" vsize-policy="0" hsize-policy="0" anchor="8" fill="0" indent="0" use-parent-layout="false"/>
+        </constraints>
+        <properties>
+          <text resource-bundle="messages/ApplicationBundle" key="checkbox.stop.2"/>
+        </properties>
+      </component>
+      <component id="f929a" class="com.intellij.ui.components.JBCheckBox" binding="myCbStop3">
+        <constraints>
+          <grid row="4" column="1" row-span="1" col-span="1" vsize-policy="0" hsize-policy="0" anchor="8" fill="0" indent="0" use-parent-layout="false"/>
+        </constraints>
+        <properties>
+          <text resource-bundle="messages/ApplicationBundle" key="checkbox.stop.3"/>
+        </properties>
+      </component>
+      <component id="6dc1" class="com.intellij.ui.components.JBCheckBox" binding="myCbStop4">
+        <constraints>
+          <grid row="5" column="1" row-span="1" col-span="1" vsize-policy="0" hsize-policy="0" anchor="8" fill="0" indent="0" use-parent-layout="false"/>
+        </constraints>
+        <properties>
+          <text resource-bundle="messages/ApplicationBundle" key="checkbox.stop.4"/>
+        </properties>
+      </component>
+      <component id="bce0f" class="com.intellij.ui.components.JBCheckBox" binding="myCbStop5">
+        <constraints>
+          <grid row="6" column="1" row-span="1" col-span="1" vsize-policy="0" hsize-policy="0" anchor="8" fill="0" indent="0" use-parent-layout="false"/>
+        </constraints>
+        <properties>
+          <text resource-bundle="messages/ApplicationBundle" key="checkbox.stop.5"/>
+        </properties>
+      </component>
+    </children>
+  </grid>
+</form>
diff --git a/platform/lang-impl/src/com/intellij/application/options/colors/RainbowDescriptionPanel.java b/platform/lang-impl/src/com/intellij/application/options/colors/RainbowDescriptionPanel.java
new file mode 100644 (file)
index 0000000..77d65a3
--- /dev/null
@@ -0,0 +1,181 @@
+/*
+ * Copyright 2000-2016 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.intellij.application.options.colors;
+
+import com.intellij.openapi.application.ApplicationBundle;
+import com.intellij.openapi.editor.colors.EditorColorsScheme;
+import com.intellij.openapi.editor.colors.EditorSchemeAttributeDescriptor;
+import com.intellij.openapi.options.OptionsBundle;
+import com.intellij.openapi.ui.Messages;
+import com.intellij.openapi.util.Pair;
+import com.intellij.ui.ColorPanel;
+import com.intellij.ui.components.JBCheckBox;
+import com.intellij.util.EventDispatcher;
+import com.intellij.util.ui.JBUI;
+import org.jetbrains.annotations.NotNull;
+
+import javax.swing.*;
+import javax.swing.event.HyperlinkListener;
+import java.awt.*;
+import java.awt.event.ActionEvent;
+import java.awt.event.ActionListener;
+import java.util.List;
+
+
+public class RainbowDescriptionPanel extends JPanel implements OptionsPanelImpl.ColorDescriptionPanel {
+  private final EventDispatcher<Listener> myDispatcher = EventDispatcher.create(Listener.class);
+
+  protected JPanel myPanel;
+
+  private JTextPane myGradientLabel;
+  private JBCheckBox myCbStop1;
+  private JBCheckBox myCbStop2;
+  private JBCheckBox myCbStop3;
+  private JBCheckBox myCbStop4;
+  private JBCheckBox myCbStop5;
+  private JBCheckBox[] myCbStops = new JBCheckBox[]{myCbStop1, myCbStop2, myCbStop3, myCbStop4, myCbStop5};
+
+  protected ColorPanel myStop1;
+  protected ColorPanel myStop2;
+  protected ColorPanel myStop3;
+  protected ColorPanel myStop4;
+  protected ColorPanel myStop5;
+  private ColorPanel[] myStops = new ColorPanel[]{myStop1, myStop2, myStop3, myStop4, myStop5};
+
+  private JBCheckBox myRainbow;
+  private JTextPane myInheritanceLabel;
+  private JBCheckBox myInheritAttributesBox;
+
+  private final String myInheritedMessage;
+  private final String myOverrideMessage;
+  private final String myInheritedMessageTooltip;
+
+  public RainbowDescriptionPanel() {
+    super(new BorderLayout());
+    add(myPanel, BorderLayout.CENTER);
+
+    setBorder(JBUI.Borders.empty(4, 0, 4, 4));
+
+    ActionListener actionListener = e -> myDispatcher.getMulticaster().onSettingsChanged(e);
+    for (JBCheckBox c : new JBCheckBox[]{myRainbow, myCbStop1, myCbStop2, myCbStop3, myCbStop4, myCbStop5, myInheritAttributesBox}) {
+      c.addActionListener(actionListener);
+    }
+    for (ColorPanel c : new ColorPanel[]{myStop1, myStop2, myStop3, myStop4, myStop5}) {
+      c.addActionListener(actionListener);
+    }
+
+    String languageDefaultPageID = OptionsBundle.message("options.language.defaults.display.name");
+    String rainbowOptionsID = ApplicationBundle.message("rainbow.option.panel.display.name");
+    myInheritedMessage = ApplicationBundle.message("label.inherited.gradient",
+                                                   rainbowOptionsID,
+                                                   languageDefaultPageID);
+    myInheritedMessageTooltip = ApplicationBundle.message("label.inherited.gradient.tooltip",
+                                                          rainbowOptionsID,
+                                                          languageDefaultPageID);
+    myOverrideMessage = ApplicationBundle.message("label.override.gradient");
+    HyperlinkListener listener = e -> myDispatcher.getMulticaster().onHyperLinkClicked(e);
+
+    Messages.configureMessagePaneUi(myGradientLabel, myOverrideMessage, null);
+    myGradientLabel.addHyperlinkListener(listener);
+
+    Messages.configureMessagePaneUi(myInheritanceLabel, ApplicationBundle.message("label.rainbow.inheritance",
+                                                                                  rainbowOptionsID,
+                                                                                  rainbowOptionsID,
+                                                                                  languageDefaultPageID), null);
+    myInheritanceLabel.setToolTipText(ApplicationBundle.message("label.rainbow.inheritance.tooltip",
+                                                                rainbowOptionsID,
+                                                                languageDefaultPageID));
+    myInheritanceLabel.addHyperlinkListener(listener);
+    myInheritanceLabel.setBorder(JBUI.Borders.empty(4, 0, 4, 4));
+  }
+
+  @NotNull
+  @Override
+  public JComponent getPanel() {
+    return this;
+  }
+
+  @Override
+  public void resetDefault() {
+  }
+
+  @Override
+  public void reset(@NotNull EditorSchemeAttributeDescriptor attributeDescriptor) {
+    if (!(attributeDescriptor instanceof RainbowAttributeDescriptor)) return;
+    RainbowAttributeDescriptor descriptor = (RainbowAttributeDescriptor)attributeDescriptor;
+
+    List<Pair<Boolean, Color>> rainbowState = descriptor.getRainbowColorsInSchemaState();
+    if (rainbowState.size() < myCbStops.length) return;
+    Boolean rainbowOn = descriptor.getColorAndFontGlobalState().isRainbowOn(descriptor.getLanguage());
+    boolean isInherited = false;
+    if (rainbowOn == null) {
+      isInherited = true;
+      rainbowOn = descriptor.getColorAndFontGlobalState().isRainbowOn(null);
+    }
+    myRainbow.setEnabled(!isInherited);
+    myRainbow.setSelected(rainbowOn);
+
+    // the colors are editable only for default language
+    boolean isDefaultLanguage = descriptor.getLanguage() == null;
+    boolean isEnable = !ColorAndFontOptions.isReadOnly(attributeDescriptor.getScheme()) && isDefaultLanguage;
+    //myGradientLabel.setEnabled(isEnable);
+    for (int i = 0; i < myCbStops.length; ++i) {
+      Pair<Boolean, Color> state = rainbowState.get(i);
+      myCbStops[i].setEnabled(isEnable);
+
+      boolean isOverride = state.first;
+      myCbStops[i].setSelected(isOverride);
+
+      myStops[i].setEditable(isEnable && isOverride);
+      myStops[i].setSelectedColor(state.second);
+    }
+
+    myInheritanceLabel.setVisible(!isDefaultLanguage);
+    myInheritAttributesBox.setSelected(isInherited);
+    myInheritAttributesBox.setVisible(!isDefaultLanguage);
+    myGradientLabel.setText(isDefaultLanguage ? myOverrideMessage : myInheritedMessage);
+    myGradientLabel.setToolTipText(isDefaultLanguage ? null : myInheritedMessageTooltip);
+  }
+
+  @Override
+  public void apply(@NotNull EditorSchemeAttributeDescriptor attributeDescriptor, EditorColorsScheme scheme) {
+    if (!(attributeDescriptor instanceof RainbowAttributeDescriptor)) return;
+    RainbowAttributeDescriptor descriptor = (RainbowAttributeDescriptor)attributeDescriptor;
+
+    List<Pair<Boolean, Color>> rainbowCurState = descriptor.getRainbowColorsInSchemaState();
+    if (rainbowCurState.size() < myCbStops.length) return;
+
+    boolean isDefaultLanguage = descriptor.getLanguage() == null;
+    descriptor
+      .getColorAndFontGlobalState()
+      .setRainbowOn(descriptor.getLanguage(),
+                    isDefaultLanguage ? Boolean.valueOf(myRainbow.isSelected())
+                                      : myInheritAttributesBox.isSelected() ? null
+                                                                            : Boolean.valueOf(myRainbow.isSelected()));
+    for (int i = 0; i < myCbStops.length; ++i) {
+      boolean isOverride = myCbStops[i].isSelected();
+      rainbowCurState.set(i, Pair.create(isOverride,
+                                         isOverride ? myStops[i].getSelectedColor() : descriptor.getDefaultColor(i)));
+    }
+
+    descriptor.apply(scheme);
+  }
+
+  @Override
+  public void addListener(@NotNull Listener listener) {
+    myDispatcher.addListener(listener);
+  }
+}
index 48f387d791799e895415069f2945a727aed51874..36d55d7038ab6fa2c2c79a5d8f83f4b27ca31c7d 100644 (file)
@@ -171,14 +171,11 @@ public class SchemesPanel extends JPanel implements SkipSelfSearchComponent {
     }
   }
 
-  private void changeToScheme() {
-    updateDescription(false);
-  }
-
+  @Deprecated
   public boolean updateDescription(boolean modified) {
     EditorColorsScheme scheme = myOptions.getSelectedScheme();
 
-    if (modified && (ColorAndFontOptions.isReadOnly(scheme) || ColorSettingsUtil.isSharedScheme(scheme))) {
+    if (modified && ColorAndFontOptions.isReadOnly(scheme)) {
       return false;
     }
 
@@ -200,8 +197,6 @@ public class SchemesPanel extends JPanel implements SkipSelfSearchComponent {
       mySchemeComboBox.setSelectedItem(selectedSchemeBackup);
       setListLoaded(true);
 
-      changeToScheme();
-
       myDispatcher.getMulticaster().schemeChanged(this);
     }
   }
index afe88048f6b482bef7a24e8ec3bcf6abde9ee32b..5ee4253663c464693d2b528871f186b3b915dc66 100644 (file)
@@ -18,6 +18,7 @@ package com.intellij.application.options.colors;
 
 import com.intellij.application.options.colors.highlighting.HighlightData;
 import com.intellij.application.options.colors.highlighting.HighlightsExtractor;
+import com.intellij.codeHighlighting.RainbowHighlighter;
 import com.intellij.ide.highlighter.HighlighterFactory;
 import com.intellij.openapi.editor.Editor;
 import com.intellij.openapi.editor.EditorFactory;
@@ -25,10 +26,10 @@ import com.intellij.openapi.editor.LogicalPosition;
 import com.intellij.openapi.editor.ScrollType;
 import com.intellij.openapi.editor.colors.CodeInsightColors;
 import com.intellij.openapi.editor.colors.EditorColorsScheme;
+import com.intellij.openapi.editor.colors.EditorSchemeAttributeDescriptor;
 import com.intellij.openapi.editor.colors.TextAttributesKey;
 import com.intellij.openapi.editor.event.CaretAdapter;
 import com.intellij.openapi.editor.event.CaretEvent;
-import com.intellij.openapi.editor.event.CaretListener;
 import com.intellij.openapi.editor.ex.EditorEx;
 import com.intellij.openapi.editor.highlighter.EditorHighlighter;
 import com.intellij.openapi.editor.highlighter.HighlighterIterator;
@@ -40,54 +41,71 @@ import com.intellij.util.Alarm;
 import com.intellij.util.EventDispatcher;
 import com.intellij.util.ui.UIUtil;
 import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
 
 import javax.swing.*;
 import java.awt.*;
 import java.awt.event.MouseEvent;
 import java.awt.event.MouseMotionAdapter;
-import java.util.*;
+import java.util.ArrayList;
+import java.util.Collections;
 import java.util.List;
+import java.util.Map;
 
-public class SimpleEditorPreview implements PreviewPanel{
+public class SimpleEditorPreview implements PreviewPanel {
   private final ColorSettingsPage myPage;
 
   private final EditorEx myEditor;
   private final Alarm myBlinkingAlarm;
-  private final HighlightData[] myHighlightData;
+  private final List<HighlightData> myHighlightData = new ArrayList<>();
 
   private final ColorAndFontOptions myOptions;
 
   private final EventDispatcher<ColorAndFontSettingsListener> myDispatcher = EventDispatcher.create(ColorAndFontSettingsListener.class);
+  private final HighlightsExtractor myHighlightsExtractor;
+
+  public void setNavigationBlocked(boolean isNavigationBlocked) {
+    myIsNavigationBlocked = isNavigationBlocked;
+  }
+  private boolean myIsNavigationBlocked = false;
 
   public SimpleEditorPreview(final ColorAndFontOptions options, final ColorSettingsPage page) {
     this(options, page, true);
   }
 
+  @NotNull
+  public List<HighlightData> getHighlightDataForExtension() {
+    return myHighlightData;
+  }
+
   public SimpleEditorPreview(final ColorAndFontOptions options, final ColorSettingsPage page, final boolean navigatable) {
     myOptions = options;
     myPage = page;
 
-    String text = page.getDemoText();
-
-    HighlightsExtractor extractant2 = new HighlightsExtractor(page.getAdditionalHighlightingTagToDescriptorMap());
-    List<HighlightData> highlights = new ArrayList<>();
-    String stripped = extractant2.extractHighlights(text, highlights);
-    myHighlightData = highlights.toArray(new HighlightData[highlights.size()]);
-    int selectedLine = -1;
-    myEditor = (EditorEx)FontEditorPreview.createPreviewEditor(stripped, 10, 3, selectedLine, myOptions, false);
+    myHighlightsExtractor = new HighlightsExtractor(page.getAdditionalHighlightingTagToDescriptorMap());
+    myEditor = (EditorEx)FontEditorPreview.createPreviewEditor(
+      myHighlightsExtractor.extractHighlights(page.getDemoText(), myHighlightData), // text without tags
+      10, 3, -1, myOptions, false);
 
     FontEditorPreview.installTrafficLights(myEditor);
     myBlinkingAlarm = new Alarm().setActivationComponent(myEditor.getComponent());
     if (navigatable) {
-      addMouseMotionListener(myEditor, page.getHighlighter(), myHighlightData, false);
+      myEditor.getContentComponent().addMouseMotionListener(new MouseMotionAdapter() {
+        @Override
+        public void mouseMoved(MouseEvent e) {
+          LogicalPosition pos = myEditor.xyToLogicalPosition(new Point(e.getX(), e.getY()));
+          navigate(myEditor, false, pos, page.getHighlighter(), false);
+        }
+      });
 
-      CaretListener listener = new CaretAdapter() {
+      myEditor.getCaretModel().addCaretListener(new CaretAdapter() {
         @Override
         public void caretPositionChanged(CaretEvent e) {
-          navigate(myEditor, true, e.getNewPosition(), page.getHighlighter(), myHighlightData, false);
+          if (!myIsNavigationBlocked) {
+            navigate(myEditor, true, e.getNewPosition(), page.getHighlighter(), false);
+          }
         }
-      };
-      myEditor.getCaretModel().addCaretListener(listener);
+      });
     }
   }
 
@@ -95,22 +113,16 @@ public class SimpleEditorPreview implements PreviewPanel{
     return myEditor;
   }
 
-  private void addMouseMotionListener(final Editor view,
-                                      final SyntaxHighlighter highlighter,
-                                      final HighlightData[] data, final boolean isBackgroundImportant) {
-    view.getContentComponent().addMouseMotionListener(new MouseMotionAdapter() {
-      @Override
-      public void mouseMoved(MouseEvent e) {
-        LogicalPosition pos = view.xyToLogicalPosition(new Point(e.getX(), e.getY()));
-        navigate(view, false, pos, highlighter, data, isBackgroundImportant);
-      }
-    });
+  public void setDemoText(final String text) {
+    myEditor.getSelectionModel().removeSelection();
+    myHighlightData.clear();
+    myEditor.getDocument().setText(myHighlightsExtractor.extractHighlights(text, myHighlightData));
   }
 
   private void navigate(final Editor editor, boolean select,
                         LogicalPosition pos,
                         final SyntaxHighlighter highlighter,
-                        final HighlightData[] data, final boolean isBackgroundImportant) {
+                        final boolean isBackgroundImportant) {
     int offset = editor.logicalPositionToOffset(pos);
 
     if (!isBackgroundImportant && editor.offsetToLogicalPosition(offset).column != pos.column) {
@@ -120,17 +132,18 @@ public class SimpleEditorPreview implements PreviewPanel{
       }
     }
 
-    if (data != null) {
-      for (HighlightData highlightData : data) {
-        if (ClickNavigator.highlightDataContainsOffset(highlightData, editor.logicalPositionToOffset(pos))) {
-          if (!select) {
-            ClickNavigator.setCursor(editor, Cursor.HAND_CURSOR);
-          }
-          else {
-            myDispatcher.getMulticaster().selectionInPreviewChanged(highlightData.getHighlightType());
-          }
-          return;
+    for (HighlightData highlightData : myHighlightData) {
+      if (ClickNavigator.highlightDataContainsOffset(highlightData, editor.logicalPositionToOffset(pos))) {
+        if (!select) {
+          ClickNavigator.setCursor(editor, Cursor.HAND_CURSOR);
+        }
+        else {
+          myDispatcher.getMulticaster().selectionInPreviewChanged(
+            RainbowHighlighter.isRainbowTempKey(highlightData.getHighlightKey())
+            ? RainbowHighlighter.RAINBOW_TYPE
+            : highlightData.getHighlightType());
         }
+        return;
       }
     }
 
@@ -174,16 +187,14 @@ public class SimpleEditorPreview implements PreviewPanel{
     updateHighlighters();
 
     myEditor.reinitSettings();
-
   }
 
   private void updateHighlighters() {
     UIUtil.invokeLaterIfNeeded(() -> {
       if (myEditor.isDisposed()) return;
       myEditor.getMarkupModel().removeAllHighlighters();
-      HighlightData[] datum = myHighlightData;
       final Map<TextAttributesKey, String> displayText = ColorSettingsUtil.keyToDisplayTextMap(myPage);
-      for (final HighlightData data : datum) {
+      for (final HighlightData data : myHighlightData) {
         data.addHighlToView(myEditor, myOptions.getSelectedScheme(), displayText);
       }
     });
@@ -193,46 +204,48 @@ public class SimpleEditorPreview implements PreviewPanel{
 
   @Override
   public void blinkSelectedHighlightType(Object description) {
-    if (description instanceof EditorSchemeAttributeDescriptor){
+    if (description instanceof EditorSchemeAttributeDescriptor) {
       String type = ((EditorSchemeAttributeDescriptor)description).getType();
 
       List<HighlightData> highlights = startBlinkingHighlights(myEditor,
-                                                               myHighlightData, type,
+                                                               type,
                                                                myPage.getHighlighter(), true,
                                                                myBlinkingAlarm, BLINK_COUNT, myPage);
 
-      scrollHighlightInView(highlights, myEditor);
+      scrollHighlightInView(highlights);
     }
   }
 
-  private static void scrollHighlightInView(final List<HighlightData> highlightDatas, final Editor editor) {
+  void scrollHighlightInView(@Nullable final List<HighlightData> highlightDatas) {
+    if (highlightDatas == null) return;
+
     boolean needScroll = true;
     int minOffset = Integer.MAX_VALUE;
-    for(HighlightData data: highlightDatas) {
-      if (isOffsetVisible(editor, data.getStartOffset())) {
+    for (HighlightData data : highlightDatas) {
+      if (isOffsetVisible(data.getStartOffset())) {
         needScroll = false;
         break;
       }
       minOffset = Math.min(minOffset, data.getStartOffset());
     }
     if (needScroll && minOffset != Integer.MAX_VALUE) {
-      LogicalPosition pos = editor.offsetToLogicalPosition(minOffset);
-      editor.getScrollingModel().scrollTo(pos, ScrollType.MAKE_VISIBLE);
+      LogicalPosition pos = myEditor.offsetToLogicalPosition(minOffset);
+      myEditor.getScrollingModel().scrollTo(pos, ScrollType.MAKE_VISIBLE);
     }
   }
 
-  private static boolean isOffsetVisible(final Editor editor, final int startOffset) {
-    Rectangle visibleArea = editor.getScrollingModel().getVisibleArea();
-    Point point = editor.logicalPositionToXY(editor.offsetToLogicalPosition(startOffset));
-    return point.y >= visibleArea.y && point.y < (visibleArea.y + visibleArea.height);
+  private boolean isOffsetVisible(final int startOffset) {
+    return myEditor
+      .getScrollingModel()
+      .getVisibleArea()
+      .contains(myEditor.logicalPositionToXY(myEditor.offsetToLogicalPosition(startOffset)));
   }
 
-  private void stopBlinking() {
+  public void stopBlinking() {
     myBlinkingAlarm.cancelAllRequests();
   }
 
   private List<HighlightData> startBlinkingHighlights(final EditorEx editor,
-                                                      final HighlightData[] highlightDatum,
                                                       final String attrKey,
                                                       final SyntaxHighlighter highlighter,
                                                       final boolean show,
@@ -244,14 +257,13 @@ public class SimpleEditorPreview implements PreviewPanel{
     boolean found = false;
     List<HighlightData> highlights = new ArrayList<>();
     List<HighlightData> matchingHighlights = new ArrayList<>();
-    for (int i = 0; highlightDatum != null && i < highlightDatum.length; i++) {
-      HighlightData highlightData = highlightDatum[i];
+    for (HighlightData highlightData : myHighlightData) {
       String type = highlightData.getHighlightType();
       highlights.add(highlightData);
       if (show && type.equals(attrKey)) {
         highlightData =
-        new HighlightData(highlightData.getStartOffset(), highlightData.getEndOffset(),
-                          CodeInsightColors.BLINKING_HIGHLIGHTS_ATTRIBUTES);
+          new HighlightData(highlightData.getStartOffset(), highlightData.getEndOffset(),
+                            CodeInsightColors.BLINKING_HIGHLIGHTS_ATTRIBUTES);
         highlights.add(highlightData);
         matchingHighlights.add(highlightData);
         found = true;
@@ -294,7 +306,7 @@ public class SimpleEditorPreview implements PreviewPanel{
       }
     }
     alarm.cancelAllRequests();
-    alarm.addComponentRequest(() -> startBlinkingHighlights(editor, highlightDatum, attrKey, highlighter, !show, alarm, count - 1, page), 400);
+    alarm.addComponentRequest(() -> startBlinkingHighlights(editor, attrKey, highlighter, !show, alarm, count - 1, page), 400);
     return matchingHighlights;
   }
 
@@ -309,6 +321,5 @@ public class SimpleEditorPreview implements PreviewPanel{
     EditorFactory editorFactory = EditorFactory.getInstance();
     editorFactory.releaseEditor(myEditor);
     stopBlinking();
-
   }
 }
index 7d64bc12bd649db436694734499de9cd1f92883d..499605ab18b9a75d7c486c6e0123dc7cdb1878e1 100644 (file)
@@ -92,4 +92,8 @@ public final class HighlightData {
   public String getHighlightType() {
     return myHighlightType.getExternalName();
   }
+
+  public TextAttributesKey getHighlightKey() {
+    return myHighlightType;
+  }
 }
index ce5dd89fec4e2f5e140ee4f308722ab3374b7911..97207ef41378db2fdff51cbd1e56ddf5c0315039 100644 (file)
@@ -21,6 +21,7 @@ import com.intellij.application.options.colors.ColorAndFontOptions;
 import com.intellij.application.options.colors.OptionsPanelImpl;
 import com.intellij.diff.util.TextDiffTypeFactory;
 import com.intellij.openapi.editor.colors.EditorColorsScheme;
+import com.intellij.openapi.editor.colors.EditorSchemeAttributeDescriptor;
 import com.intellij.openapi.editor.markup.TextAttributes;
 import com.intellij.ui.ColorPanel;
 import com.intellij.ui.JBColor;
@@ -95,7 +96,10 @@ class DiffColorDescriptionPanel extends JPanel implements OptionsPanelImpl.Color
     myInheritIgnoredCheckBox.setSelected(false);
   }
 
-  public void reset(@NotNull ColorAndFontDescription description) {
+  public void reset(@NotNull EditorSchemeAttributeDescriptor attrDescription) {
+    if (!(attrDescription instanceof ColorAndFontDescription)) return;
+    ColorAndFontDescription description = (ColorAndFontDescription)attrDescription;
+
     Color backgroundColor = getBackgroundColor(description);
     Color ignoredColor = getIgnoredColor(description);
     Color stripeMarkColor = getStripeMarkColor(description);
@@ -112,7 +116,10 @@ class DiffColorDescriptionPanel extends JPanel implements OptionsPanelImpl.Color
     myInheritIgnoredCheckBox.setSelected(inheritIgnored);
   }
 
-  public void apply(@NotNull ColorAndFontDescription description, EditorColorsScheme scheme) {
+  public void apply(@NotNull EditorSchemeAttributeDescriptor attrDescription, EditorColorsScheme scheme) {
+    if (!(attrDescription instanceof ColorAndFontDescription)) return;
+    ColorAndFontDescription description = (ColorAndFontDescription)attrDescription;
+
     description.setBackgroundChecked(true);
     description.setForegroundChecked(true);
     description.setErrorStripeChecked(true);
index 6fe557e2cad255d4211d714ba2a0911d9956434e..f655dcfc1bb70057ccee4b8691e4f64679f1861a 100644 (file)
@@ -15,6 +15,7 @@
  */
 package com.intellij.openapi.options.colors.pages;
 
+import com.intellij.lang.Language;
 import com.intellij.openapi.editor.DefaultLanguageHighlighterColors;
 import com.intellij.openapi.editor.HighlighterColors;
 import com.intellij.openapi.editor.colors.TextAttributesKey;
@@ -25,6 +26,7 @@ import com.intellij.openapi.options.OptionsBundle;
 import com.intellij.openapi.options.colors.AttributesDescriptor;
 import com.intellij.openapi.options.colors.ColorDescriptor;
 import com.intellij.openapi.options.colors.ColorSettingsPage;
+import com.intellij.openapi.options.colors.RainbowColorSettingsPage;
 import com.intellij.psi.codeStyle.DisplayPriority;
 import com.intellij.psi.codeStyle.DisplayPrioritySortable;
 import org.jetbrains.annotations.NonNls;
@@ -40,7 +42,7 @@ import java.util.Map;
  *
  * @author Rustam Vishnyakov
  */
-public class DefaultLanguageColorsPage implements ColorSettingsPage, DisplayPrioritySortable {
+public class DefaultLanguageColorsPage implements RainbowColorSettingsPage, DisplayPrioritySortable {
 
   @NonNls private static final Map<String, TextAttributesKey> TAG_HIGHLIGHTING_MAP = new HashMap<>();
 
@@ -256,4 +258,45 @@ public class DefaultLanguageColorsPage implements ColorSettingsPage, DisplayPrio
   public DisplayPriority getPriority() {
     return DisplayPriority.GENERAL_SETTINGS;
   }
+
+  @Override
+  public boolean isRainbowType(TextAttributesKey type) {
+    return DefaultLanguageHighlighterColors.LOCAL_VARIABLE.equals(type)
+           || DefaultLanguageHighlighterColors.PARAMETER.equals(type)
+           || DefaultLanguageHighlighterColors.DOC_COMMENT_TAG_VALUE.equals(type);
+  }
+
+  @NotNull
+  @Override
+  public String getRainbowDemoText() {
+    return
+      "Global <global_var>variable1</global_var>\n" +
+      "Global <global_var>variable2</global_var>\n" +
+      "<doc_comment>/** \n" +
+      " * Doc comment\n" +
+      " * <doc_tag>@tag</doc_tag> <doc_markup><code>Markup</code></doc_markup>\n" +
+      " * <doc_tag>@param</doc_tag> <doc_tag_value>parameter1</doc_tag_value> documentation\n" +
+      " * <doc_tag>@param</doc_tag> <doc_tag_value>parameter2</doc_tag_value> documentation\n" +
+      " * <doc_tag>@param</doc_tag> <doc_tag_value>parameter3</doc_tag_value> documentation\n" +
+      " * <doc_tag>@param</doc_tag> <doc_tag_value>parameter4</doc_tag_value> documentation\n" +
+      " * <doc_tag>@param</doc_tag> <doc_tag_value>parameter5</doc_tag_value> documentation\n" +
+      " */</doc_comment>\n" +
+      "Function <func_decl>declaration</func_decl> (<param>parameter1</param>\n" +
+      "                      <param>parameter2</param>\n" +
+      "                      <param>parameter3</param>\n" +
+      "                      <param>parameter4</param>\n" +
+      "                      <param>parameter5</param>)\n" +
+      "    Local <local_var>variable1</local_var>\n" +
+      "    Local <local_var>variable2</local_var>\n" +
+      "    Local <local_var>variable3</local_var>\n" +
+      "    Local <local_var>variable4</local_var>\n" +
+      "    Local <local_var>variable5</local_var>\n" +
+      "Function <func_call>call</func_call>()";
+  }
+
+  @Nullable
+  @Override
+  public Language getLanguage() {
+    return null;
+  }
 }
index 02c16408a64a6200fdbd87d01314b09594db221f..0f0638e649834c19c454ebf6a137a9f90f57baf7 100644 (file)
@@ -741,4 +741,17 @@ code.style.other.label=Text files and unsupported file types\:
 
 remote.desktop.detected.title=Remote desktop detected
 remote.desktop.detected.message=Animation disabled
-checkbox.line.comment.add.space=Add a space at comment start
\ No newline at end of file
+checkbox.line.comment.add.space=Add a space at comment start
+
+rainbow.option.panel.display.name=Semantic highlighting
+label.override.gradient=<html>Override gradient:</html>
+label.inherited.gradient=<html>Inherited from <a href="{0}">{1}</a> gradient:</html>
+label.inherited.gradient.tooltip=<html>''{0}\u2192Override gradient'' from<br>''{1}'' section</html>
+checkbox.stop.1=Stop #1
+checkbox.stop.2=Stop #2
+checkbox.stop.3=Stop #3
+checkbox.stop.4=Stop #4
+checkbox.stop.5=Stop #5
+checkbox.rainbow=<html>Unique color for each parameter<br>and local variable<br><font color=gray><sub>Chosen from generated gradient</sub></font></html>
+label.rainbow.inheritance=<html><div style="text-align:right" vertical-align="top">''{0}\u2192Unique color''<br>of <a href="{1}">{2}</html>
+label.rainbow.inheritance.tooltip=<html>''{0}\u2192Unique color'' from<br>''{1}'' section</html>
\ No newline at end of file