/* * Copyright 2000-2014 JetBrains s.r.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /* * @author max */ package com.intellij.openapi.editor.markup; import com.intellij.openapi.util.Comparing; import com.intellij.openapi.util.DefaultJDOMExternalizer; import com.intellij.openapi.util.InvalidDataException; import com.intellij.openapi.util.JDOMExternalizerUtil; import com.intellij.util.ConcurrencyUtil; import com.intellij.util.containers.ContainerUtil; import org.intellij.lang.annotations.JdkConstants; import org.jdom.Element; import org.jetbrains.annotations.NonNls; import org.jetbrains.annotations.NotNull; import java.awt.*; import java.util.concurrent.ConcurrentMap; public class AttributesFlyweight { private static final ConcurrentMap<FlyweightKey, AttributesFlyweight> entries = ContainerUtil.newConcurrentMap(); private static final ThreadLocal<FlyweightKey> ourKey = new ThreadLocal<>(); private final int myHashCode; private final Color myForeground; private final Color myBackground; @JdkConstants.FontStyle private final int myFontType; private final Color myEffectColor; private final EffectType myEffectType; private final Color myErrorStripeColor; private static class FlyweightKey implements Cloneable { private Color foreground; private Color background; @JdkConstants.FontStyle private int fontType; private Color effectColor; private EffectType effectType; private Color errorStripeColor; private FlyweightKey() { } @Override public boolean equals(Object o) { if (this == o) return true; if (!(o instanceof FlyweightKey)) return false; FlyweightKey key = (FlyweightKey)o; if (fontType != key.fontType) return false; if (background != null ? !background.equals(key.background) : key.background != null) return false; if (effectColor != null ? !effectColor.equals(key.effectColor) : key.effectColor != null) return false; if (effectType != key.effectType) return false; if (errorStripeColor != null ? !errorStripeColor.equals(key.errorStripeColor) : key.errorStripeColor != null) return false; if (foreground != null ? !foreground.equals(key.foreground) : key.foreground != null) return false; return true; } @Override public int hashCode() { return calcHashCode(foreground, background, fontType, effectColor, effectType, errorStripeColor); } @Override protected FlyweightKey clone() { try { return (FlyweightKey)super.clone(); } catch (CloneNotSupportedException e) { throw new RuntimeException(e); } } } @NotNull public static AttributesFlyweight create(Color foreground, Color background, @JdkConstants.FontStyle int fontType, Color effectColor, EffectType effectType, Color errorStripeColor) { FlyweightKey key = ourKey.get(); if (key == null) { ourKey.set(key = new FlyweightKey()); } key.foreground = foreground; key.background = background; key.fontType = fontType; key.effectColor = effectColor; key.effectType = effectType; key.errorStripeColor = errorStripeColor; AttributesFlyweight flyweight = entries.get(key); if (flyweight != null) { return flyweight; } AttributesFlyweight newValue = new AttributesFlyweight(foreground, background, fontType, effectColor, effectType, errorStripeColor); return ConcurrencyUtil.cacheOrGet(entries, key.clone(), newValue); } private AttributesFlyweight(Color foreground, Color background, @JdkConstants.FontStyle int fontType, Color effectColor, EffectType effectType, Color errorStripeColor) { myForeground = foreground; myBackground = background; myFontType = fontType; myEffectColor = effectColor; myEffectType = effectType; myErrorStripeColor = errorStripeColor; myHashCode = calcHashCode(foreground, background, fontType, effectColor, effectType, errorStripeColor); } @NotNull public static AttributesFlyweight create(@NotNull Element element) throws InvalidDataException { Color FOREGROUND = DefaultJDOMExternalizer.toColor(JDOMExternalizerUtil.readField(element, "FOREGROUND")); Color BACKGROUND = DefaultJDOMExternalizer.toColor(JDOMExternalizerUtil.readField(element, "BACKGROUND")); Color EFFECT_COLOR = DefaultJDOMExternalizer.toColor(JDOMExternalizerUtil.readField(element, "EFFECT_COLOR")); Color ERROR_STRIPE_COLOR = DefaultJDOMExternalizer.toColor(JDOMExternalizerUtil.readField(element, "ERROR_STRIPE_COLOR")); int fontType = DefaultJDOMExternalizer.toInt(JDOMExternalizerUtil.readField(element, "FONT_TYPE", "0")); if (fontType < 0 || fontType > 3) { fontType = 0; } int FONT_TYPE = fontType; int EFFECT_TYPE = DefaultJDOMExternalizer.toInt(JDOMExternalizerUtil.readField(element, "EFFECT_TYPE", "0")); return create(FOREGROUND, BACKGROUND, FONT_TYPE, EFFECT_COLOR, toEffectType(EFFECT_TYPE), ERROR_STRIPE_COLOR); } private static void writeColor(Element element, String fieldName, Color color) { if (color != null) { String string = Integer.toString(color.getRGB() & 0xFFFFFF, 16); JDOMExternalizerUtil.writeField(element, fieldName, string); } } void writeExternal(@NotNull Element element) { writeColor(element, "FOREGROUND", getForeground()); writeColor(element, "BACKGROUND", getBackground()); int fontType = getFontType(); if (fontType != 0) { JDOMExternalizerUtil.writeField(element, "FONT_TYPE", String.valueOf(fontType)); } writeColor(element, "EFFECT_COLOR", getEffectColor()); writeColor(element, "ERROR_STRIPE_COLOR", getErrorStripeColor()); int effectType = fromEffectType(getEffectType()); if (effectType != 0) { JDOMExternalizerUtil.writeField(element, "EFFECT_TYPE", String.valueOf(effectType)); } } private static final int EFFECT_BORDER = 0; private static final int EFFECT_LINE = 1; private static final int EFFECT_WAVE = 2; private static final int EFFECT_STRIKEOUT = 3; private static final int EFFECT_BOLD_LINE = 4; private static final int EFFECT_BOLD_DOTTED_LINE = 5; private static int fromEffectType(EffectType effectType) { if (effectType == null) return -1; switch (effectType) { case BOXED: return EFFECT_BORDER; case LINE_UNDERSCORE: return EFFECT_LINE; case BOLD_LINE_UNDERSCORE: return EFFECT_BOLD_LINE; case STRIKEOUT: return EFFECT_STRIKEOUT; case WAVE_UNDERSCORE: return EFFECT_WAVE; case BOLD_DOTTED_LINE: return EFFECT_BOLD_DOTTED_LINE; default: return -1; } } private static EffectType toEffectType(int effectType) { switch (effectType) { case EFFECT_BORDER: return EffectType.BOXED; case EFFECT_BOLD_LINE: return EffectType.BOLD_LINE_UNDERSCORE; case EFFECT_LINE: return EffectType.LINE_UNDERSCORE; case EFFECT_STRIKEOUT: return EffectType.STRIKEOUT; case EFFECT_WAVE: return EffectType.WAVE_UNDERSCORE; case EFFECT_BOLD_DOTTED_LINE: return EffectType.BOLD_DOTTED_LINE; default: return null; } } private static int calcHashCode(Color foreground, Color background, int fontType, Color effectColor, EffectType effectType, Color errorStripeColor) { int result = foreground != null ? foreground.hashCode() : 0; result = 31 * result + (background != null ? background.hashCode() : 0); result = 31 * result + fontType; result = 31 * result + (effectColor != null ? effectColor.hashCode() : 0); result = 31 * result + (effectType != null ? effectType.hashCode() : 0); result = 31 * result + (errorStripeColor != null ? errorStripeColor.hashCode() : 0); return result; } public Color getForeground() { return myForeground; } public Color getBackground() { return myBackground; } @JdkConstants.FontStyle public int getFontType() { return myFontType; } public Color getEffectColor() { return myEffectColor; } public EffectType getEffectType() { return myEffectType; } public Color getErrorStripeColor() { return myErrorStripeColor; } @NotNull public AttributesFlyweight withForeground(Color foreground) { return Comparing.equal(foreground, myForeground) ? this : create(foreground, myBackground, myFontType, myEffectColor, myEffectType, myErrorStripeColor); } @NotNull public AttributesFlyweight withBackground(Color background) { return Comparing.equal(background, myBackground) ? this : create(myForeground, background, myFontType, myEffectColor, myEffectType, myErrorStripeColor); } @NotNull public AttributesFlyweight withFontType(@JdkConstants.FontStyle int fontType) { return fontType == myFontType ? this : create(myForeground, myBackground, fontType, myEffectColor, myEffectType, myErrorStripeColor); } @NotNull public AttributesFlyweight withEffectColor(Color effectColor) { return Comparing.equal(effectColor, myEffectColor) ? this : create(myForeground, myBackground, myFontType, effectColor, myEffectType, myErrorStripeColor); } @NotNull public AttributesFlyweight withEffectType(EffectType effectType) { return Comparing.equal(effectType, myEffectType) ? this : create(myForeground, myBackground, myFontType, myEffectColor, effectType, myErrorStripeColor); } @NotNull public AttributesFlyweight withErrorStripeColor(Color stripeColor) { return Comparing.equal(stripeColor, myErrorStripeColor) ? this : create(myForeground, myBackground, myFontType, myEffectColor, myEffectType, stripeColor); } @Override public boolean equals(Object o) { if (this == o) return true; if (o == null || getClass() != o.getClass()) return false; AttributesFlyweight that = (AttributesFlyweight)o; if (myFontType != that.myFontType) return false; if (myBackground != null ? !myBackground.equals(that.myBackground) : that.myBackground != null) return false; if (myEffectColor != null ? !myEffectColor.equals(that.myEffectColor) : that.myEffectColor != null) return false; if (myEffectType != that.myEffectType) return false; if (myErrorStripeColor != null ? !myErrorStripeColor.equals(that.myErrorStripeColor) : that.myErrorStripeColor != null) return false; if (myForeground != null ? !myForeground.equals(that.myForeground) : that.myForeground != null) return false; return true; } @Override public int hashCode() { return myHashCode; } @NonNls @Override public String toString() { return "AttributesFlyweight{myForeground=" + myForeground + ", myBackground=" + myBackground + ", myFontType=" + myFontType + ", myEffectColor=" + myEffectColor + ", myEffectType=" + myEffectType + ", myErrorStripeColor=" + myErrorStripeColor + '}'; } }