blob: 8ef82d5f225f34c0dbe8f237bed855f097f3dcae [file] [log] [blame]
/*
* 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.StripedLockConcurrentHashMap;
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 = new StripedLockConcurrentHashMap<FlyweightKey, AttributesFlyweight>();
private static final ThreadLocal<FlyweightKey> ourKey = new ThreadLocal<FlyweightKey>();
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());
JDOMExternalizerUtil.writeField(element, "EFFECT_TYPE", String.valueOf(fromEffectType(getEffectType())));
}
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) {
int EFFECT_TYPE;
if (effectType == EffectType.BOXED) {
EFFECT_TYPE = EFFECT_BORDER;
}
else if (effectType == EffectType.LINE_UNDERSCORE) {
EFFECT_TYPE = EFFECT_LINE;
}
else if (effectType == EffectType.BOLD_LINE_UNDERSCORE) {
EFFECT_TYPE = EFFECT_BOLD_LINE;
}
else if (effectType == EffectType.STRIKEOUT) {
EFFECT_TYPE = EFFECT_STRIKEOUT;
}
else if (effectType == EffectType.WAVE_UNDERSCORE) {
EFFECT_TYPE = EFFECT_WAVE;
}
else if (effectType == EffectType.BOLD_DOTTED_LINE) {
EFFECT_TYPE = EFFECT_BOLD_DOTTED_LINE;
}
else {
EFFECT_TYPE = -1;
}
return EFFECT_TYPE;
}
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 + '}';
}
}