blob: 807ee6102b7f5c66fa2b4e3d7d1a5b2b4009baba [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.
*/
package com.intellij.openapi.editor.colors;
import com.intellij.openapi.components.ServiceManager;
import com.intellij.openapi.editor.markup.TextAttributes;
import com.intellij.openapi.util.*;
import com.intellij.util.ConcurrencyUtil;
import com.intellij.util.containers.ConcurrentHashMap;
import org.jdom.Element;
import org.jetbrains.annotations.NonNls;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.concurrent.ConcurrentMap;
/**
* A type of item with a distinct highlighting in an editor or in other views.
*/
public final class TextAttributesKey implements Comparable<TextAttributesKey> {
private static final TextAttributes NULL_ATTRIBUTES = new TextAttributes();
private static final ConcurrentMap<String, TextAttributesKey> ourRegistry = new ConcurrentHashMap<String, TextAttributesKey>();
private static final NullableLazyValue<TextAttributeKeyDefaultsProvider> ourDefaultsProvider = new VolatileNullableLazyValue<TextAttributeKeyDefaultsProvider>() {
@Nullable
@Override
protected TextAttributeKeyDefaultsProvider compute() {
return ServiceManager.getService(TextAttributeKeyDefaultsProvider.class);
}
};
private final String myExternalName;
private TextAttributes myDefaultAttributes = NULL_ATTRIBUTES;
private TextAttributesKey myFallbackAttributeKey;
private TextAttributesKey(String externalName) {
myExternalName = externalName;
}
//read external only
public TextAttributesKey(@NotNull Element element) throws InvalidDataException {
this(JDOMExternalizerUtil.readField(element, "myExternalName"));
Element myDefaultAttributesElement = JDOMExternalizerUtil.getOption(element, "myDefaultAttributes");
if (myDefaultAttributesElement != null) {
myDefaultAttributes = new TextAttributes(myDefaultAttributesElement);
}
}
@NotNull
public static TextAttributesKey find(@NotNull @NonNls String externalName) {
return ConcurrencyUtil.cacheOrGet(ourRegistry, externalName, new TextAttributesKey(externalName));
}
public String toString() {
return myExternalName;
}
public String getExternalName() {
return myExternalName;
}
@Override
public int compareTo(@NotNull TextAttributesKey key) {
return myExternalName.compareTo(key.myExternalName);
}
/**
* Registers a text attribute key with the specified identifier.
*
* @param externalName the unique identifier of the key.
* @return the new key instance, or an existing instance if the key with the same
* identifier was already registered.
*/
@NotNull public static TextAttributesKey createTextAttributesKey(@NonNls @NotNull String externalName) {
return find(externalName);
}
public void writeExternal(Element element) throws WriteExternalException {
JDOMExternalizerUtil.writeField(element, "myExternalName", myExternalName);
if (myDefaultAttributes != NULL_ATTRIBUTES) {
Element option = JDOMExternalizerUtil.writeOption(element, "myDefaultAttributes");
myDefaultAttributes.writeExternal(option);
}
}
public boolean equals(final Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
final TextAttributesKey that = (TextAttributesKey)o;
if (!myExternalName.equals(that.myExternalName)) return false;
return true;
}
public int hashCode() {
return myExternalName.hashCode();
}
/**
* Returns the default text attributes associated with the key.
*
* @return the text attributes.
*/
public TextAttributes getDefaultAttributes() {
if (myDefaultAttributes == NULL_ATTRIBUTES) {
myDefaultAttributes = null;
final TextAttributeKeyDefaultsProvider provider = ourDefaultsProvider.getValue();
if (provider != null) {
myDefaultAttributes = provider.getDefaultAttributes(this);
}
}
else if (myDefaultAttributes == null) {
myDefaultAttributes = NULL_ATTRIBUTES;
}
return myDefaultAttributes;
}
/**
* Registers a text attribute key with the specified identifier and default attributes.
*
* @param externalName the unique identifier of the key.
* @param defaultAttributes the default text attributes associated with the key.
* @return the new key instance, or an existing instance if the key with the same
* identifier was already registered.
* @deprecated Use {@link #createTextAttributesKey(String, TextAttributesKey)} to guarantee compatibility with generic color schemes.
*/
@NotNull
@Deprecated
public static TextAttributesKey createTextAttributesKey(@NonNls @NotNull String externalName, TextAttributes defaultAttributes) {
TextAttributesKey key = find(externalName);
if (key.myDefaultAttributes == null || key.myDefaultAttributes == NULL_ATTRIBUTES) {
key.myDefaultAttributes = defaultAttributes;
}
return key;
}
/**
* Registers a text attribute key with the specified identifier and a fallback key. If text attributes for the key are not defined in
* a color scheme, they will be acquired by the fallback key if possible.
* <p>Fallback keys can be chained, for example, text attribute key
* A can depend on key B which in turn can depend on key C. So if text attributes neither for A nor for B are found, they will be
* acquired by the key C.
* <p>Fallback keys can be used from any place including language's own definitions. Note that there is a common set of keys called
* <code>DefaultLanguageHighlighterColors</code> which can be used as a base. Scheme designers are supposed to set colors for these
* keys primarily and using them guarantees that most (if not all) text attributes will be shown correctly for the language
* regardless of a color scheme.
*
* @param externalName the unique identifier of the key.
* @param fallbackAttributeKey the fallback key to use if text attributes for this key are not defined.
* @return the new key instance, or an existing instance if the key with the same
* identifier was already registered.
*/
@NotNull
public static TextAttributesKey createTextAttributesKey(@NonNls @NotNull String externalName, TextAttributesKey fallbackAttributeKey) {
TextAttributesKey key = find(externalName);
key.setFallbackAttributeKey(fallbackAttributeKey);
return key;
}
public TextAttributesKey getFallbackAttributeKey() {
return myFallbackAttributeKey;
}
public void setFallbackAttributeKey(TextAttributesKey fallbackAttributeKey) {
myFallbackAttributeKey = fallbackAttributeKey;
}
public interface TextAttributeKeyDefaultsProvider {
TextAttributes getDefaultAttributes(TextAttributesKey key);
}
}