diff --git a/platform/lang-impl/src/com/intellij/application/options/colors/FontOptions.java b/platform/lang-impl/src/com/intellij/application/options/colors/FontOptions.java index ebe94f5bac8a..985520b091e0 100644 --- a/platform/lang-impl/src/com/intellij/application/options/colors/FontOptions.java +++ b/platform/lang-impl/src/com/intellij/application/options/colors/FontOptions.java @@ -264,7 +264,7 @@ public class FontOptions extends JPanel implements OptionsPanel{ myLineSpacingField.setText(Float.toString(getLineSpacing())); mySelectedFontsModel.clear(); FontPreferences fontPreferences = getFontPreferences(); - List fontFamilies = fontPreferences.getFontFamilies(); + List fontFamilies = fontPreferences.getEffectiveFontFamilies(); Set selectedFonts = ContainerUtilRt.newHashSet(); Object selectedValue = mySelectedFontsList.getSelectedValue(); mySelectedFontsModel.clear(); diff --git a/platform/platform-api/src/com/intellij/openapi/editor/colors/FontPreferences.java b/platform/platform-api/src/com/intellij/openapi/editor/colors/FontPreferences.java index bc384e7b5bd7..ced2bf6867c4 100644 --- a/platform/platform-api/src/com/intellij/openapi/editor/colors/FontPreferences.java +++ b/platform/platform-api/src/com/intellij/openapi/editor/colors/FontPreferences.java @@ -21,6 +21,7 @@ import com.intellij.util.containers.ContainerUtilRt; import gnu.trove.TObjectIntHashMap; import org.jetbrains.annotations.NonNls; import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; import java.awt.*; import java.util.List; @@ -41,7 +42,8 @@ public class FontPreferences { public static final int DEFAULT_FONT_SIZE = FontSize.SMALL.getSize(); @NotNull private final TObjectIntHashMap myFontSizes = new TObjectIntHashMap(); - @NotNull private final List myFontFamilies = ContainerUtilRt.newArrayList(); + @NotNull private final List myEffectiveFontFamilies = ContainerUtilRt.newArrayList(); + @NotNull private final List myRealFontFamilies = ContainerUtilRt.newArrayList(); /** * Font size to use by default. Default value is {@link #DEFAULT_FONT_SIZE}. @@ -49,12 +51,14 @@ public class FontPreferences { private int myTemplateFontSize = DEFAULT_FONT_SIZE; public void clear() { - myFontFamilies.clear(); + myEffectiveFontFamilies.clear(); + myRealFontFamilies.clear(); myFontSizes.clear(); } public void clearFonts() { - myFontFamilies.clear(); + myEffectiveFontFamilies.clear(); + myRealFontFamilies.clear(); } public boolean hasSize(@NotNull String fontName) { @@ -74,38 +78,69 @@ public class FontPreferences { myTemplateFontSize = size; } + /** + * This method might return results different from {@link #getRealFontFamilies()} when + * {@link #getFallbackName(String, int, EditorColorsScheme) a font family unavailable at current environment} + * has been {@link #register(String, int) registered} at the current font preferences object. + *

+ * Effective fonts will hold fallback values for such font families then (exposed by the current method), 'real fonts' will + * be available via {@link #getRealFontFamilies()}. + * + * @return effective font families to use + */ @NotNull - public List getFontFamilies() { - return myFontFamilies; + public List getEffectiveFontFamilies() { + return myEffectiveFontFamilies; } + /** + * @return 'real' font families + * @see #getEffectiveFontFamilies() + */ + @NotNull + public List getRealFontFamilies() { + return myRealFontFamilies; + } + public void register(@NotNull String fontFamily, int size) { - if (!myFontFamilies.contains(fontFamily)) { - myFontFamilies.add(fontFamily); + String fallbackFontFamily = getFallbackName(fontFamily, size, null); + if (!myRealFontFamilies.contains(fontFamily)) { + myRealFontFamilies.add(fontFamily); + } + String effectiveFontFamily = fallbackFontFamily == null ? fontFamily : fallbackFontFamily; + if (!myEffectiveFontFamilies.contains(effectiveFontFamily)) { + myEffectiveFontFamilies.add(effectiveFontFamily); } setSize(fontFamily, size); } /** - * @return first element of the {@link #getFontFamilies() registered font families} (if any); + * @return first element of the {@link #getEffectiveFontFamilies() registered font families} (if any); * {@link #DEFAULT_FONT_NAME} otherwise */ @NotNull public String getFontFamily() { - return myFontFamilies.isEmpty() ? DEFAULT_FONT_NAME : myFontFamilies.get(0); + return myEffectiveFontFamilies.isEmpty() ? DEFAULT_FONT_NAME : myEffectiveFontFamilies.get(0); } public void addFontFamily(@NotNull String fontFamily) { - if (!myFontFamilies.contains(fontFamily)) { - myFontFamilies.add(fontFamily); + String fallbackFontFamily = getFallbackName(fontFamily, DEFAULT_FONT_SIZE, null); + if (!myRealFontFamilies.contains(fontFamily)) { + myRealFontFamilies.add(fontFamily); + } + String effectiveFontFamily = fallbackFontFamily == null ? fontFamily : fallbackFontFamily; + if (!myEffectiveFontFamilies.contains(effectiveFontFamily)) { + myEffectiveFontFamilies.add(effectiveFontFamily); } } public void copyTo(@NotNull final FontPreferences preferences) { - preferences.myFontFamilies.clear(); - preferences.myFontFamilies.addAll(myFontFamilies); + preferences.myEffectiveFontFamilies.clear(); + preferences.myEffectiveFontFamilies.addAll(myEffectiveFontFamilies); + preferences.myRealFontFamilies.clear(); + preferences.myRealFontFamilies.addAll(myRealFontFamilies); preferences.myFontSizes.clear(); - for (String fontFamily : myFontFamilies) { + for (String fontFamily : myRealFontFamilies) { if (myFontSizes.containsKey(fontFamily)) { preferences.myFontSizes.put(fontFamily, myFontSizes.get(fontFamily)); } @@ -114,7 +149,7 @@ public class FontPreferences { @Override public int hashCode() { - return myFontFamilies.hashCode(); + return myRealFontFamilies.hashCode(); } @Override @@ -124,8 +159,8 @@ public class FontPreferences { FontPreferences that = (FontPreferences)o; - if (!myFontFamilies.equals(that.myFontFamilies)) return false; - for (String fontFamily : myFontFamilies) { + if (!myRealFontFamilies.equals(that.myRealFontFamilies)) return false; + for (String fontFamily : myRealFontFamilies) { if (myFontSizes.get(fontFamily) != that.myFontSizes.get(fontFamily)) { return false; } @@ -147,4 +182,25 @@ public class FontPreferences { return "Monospaced"; } + /** + * There is a possible case that particular font family is not available at particular environment (e.g. Monaco under *nix). + * However, java environment tries to mask that via 'Dialog' fonts, i.e. when we try to create font like + * {@code new Font("Monaco", style, size)}, it creates a font object which has font family "Monaco" but is a "Dialog" font. + *

+ * That's why we have a special check for such a situation. + * + * @param fontName font family name to check + * @param fontSize target font size + * @param fallbackScheme colors scheme to use for fallback fonts retrieval (if necessary); + * @return fallback font family to use if font family with the given name is not registered at current environment; + * null if font family with the given name is registered at the current environment + */ + @Nullable + public static String getFallbackName(@NotNull String fontName, int fontSize, @Nullable EditorColorsScheme fallbackScheme) { + Font plainFont = new Font(fontName, Font.PLAIN, fontSize); + if (plainFont.getFamily().equals("Dialog") && !"Dialog".equals(fontName)) { + return fallbackScheme == null ? DEFAULT_FONT_NAME : fallbackScheme.getEditorFontName(); + } + return fontName; + } } diff --git a/platform/platform-impl/src/com/intellij/openapi/editor/colors/impl/AbstractColorsScheme.java b/platform/platform-impl/src/com/intellij/openapi/editor/colors/impl/AbstractColorsScheme.java index 9104b6fa4a56..d41e826c268c 100644 --- a/platform/platform-impl/src/com/intellij/openapi/editor/colors/impl/AbstractColorsScheme.java +++ b/platform/platform-impl/src/com/intellij/openapi/editor/colors/impl/AbstractColorsScheme.java @@ -208,17 +208,12 @@ public abstract class AbstractColorsScheme implements EditorColorsScheme { protected void initFonts() { String editorFontName = getEditorFontName(); int editorFontSize = getEditorFontSize(); - + + myFallbackFontName = FontPreferences.getFallbackName(editorFontName, editorFontSize, myParentScheme); + if (myFallbackFontName != null) { + editorFontName = myFallbackFontName; + } Font plainFont = new Font(editorFontName, Font.PLAIN, editorFontSize); - if (plainFont.getFamily().equals("Dialog") && !editorFontName.equals("Dialog")) { - editorFontName = myParentScheme != null ? myParentScheme.getEditorFontName() : FontPreferences.DEFAULT_FONT_NAME; - myFallbackFontName = editorFontName; - plainFont = new Font(editorFontName, Font.PLAIN, editorFontSize); - } - else { - myFallbackFontName = null; - } - Font boldFont = new Font(editorFontName, Font.BOLD, editorFontSize); Font italicFont = new Font(editorFontName, Font.ITALIC, editorFontSize); Font boldItalicFont = new Font(editorFontName, Font.BOLD | Font.ITALIC, editorFontSize); @@ -305,7 +300,7 @@ public abstract class AbstractColorsScheme implements EditorColorsScheme { } } - if (myConsoleFontPreferences.getFontFamilies().isEmpty()) { + if (myConsoleFontPreferences.getEffectiveFontFamilies().isEmpty()) { myFontPreferences.copyTo(myConsoleFontPreferences); } @@ -442,7 +437,7 @@ public abstract class AbstractColorsScheme implements EditorColorsScheme { // IJ has used a 'single customizable font' mode for ages. That's why we want to support that format now, when it's possible // to specify fonts sequence (see getFontPreferences()), there are big chances that many clients still will use a single font. // That's why we want to use old format when zero or one font is selected and 'extended' format otherwise. - boolean useOldFontFormat = myFontPreferences.getFontFamilies().size() <= 1; + boolean useOldFontFormat = myFontPreferences.getEffectiveFontFamilies().size() <= 1; if (useOldFontFormat) { element = new Element(OPTION_ELEMENT); element.setAttribute(NAME_ATTR, EDITOR_FONT_SIZE); @@ -454,7 +449,7 @@ public abstract class AbstractColorsScheme implements EditorColorsScheme { } if (!myFontPreferences.equals(myConsoleFontPreferences)) { - if (myConsoleFontPreferences.getFontFamilies().size() <= 1) { + if (myConsoleFontPreferences.getEffectiveFontFamilies().size() <= 1) { element = new Element(OPTION_ELEMENT); element.setAttribute(NAME_ATTR, CONSOLE_FONT_NAME); element.setAttribute(VALUE_ELEMENT, getConsoleFontName()); @@ -504,7 +499,7 @@ public abstract class AbstractColorsScheme implements EditorColorsScheme { } private static void writeFontPreferences(@NotNull String key, @NotNull Element parent, @NotNull FontPreferences preferences) { - for (String fontFamily : preferences.getFontFamilies()) { + for (String fontFamily : preferences.getRealFontFamilies()) { Element element = new Element(key); Element e = new Element(OPTION_ELEMENT); e.setAttribute(NAME_ATTR, EDITOR_FONT_NAME); diff --git a/platform/platform-impl/src/com/intellij/openapi/editor/impl/ComplementaryFontsRegistry.java b/platform/platform-impl/src/com/intellij/openapi/editor/impl/ComplementaryFontsRegistry.java index bf951719f926..1a9343f82a67 100644 --- a/platform/platform-impl/src/com/intellij/openapi/editor/impl/ComplementaryFontsRegistry.java +++ b/platform/platform-impl/src/com/intellij/openapi/editor/impl/ComplementaryFontsRegistry.java @@ -146,7 +146,7 @@ public class ComplementaryFontsRegistry { @NotNull public static FontInfo getFontAbleToDisplay(char c, @JdkConstants.FontStyle int style, @NotNull FontPreferences preferences) { boolean tryDefaultFont = true; - List fontFamilies = preferences.getFontFamilies(); + List fontFamilies = preferences.getEffectiveFontFamilies(); FontInfo result; for (String fontFamily : fontFamilies) { result = doGetFontAbleToDisplay(c, preferences.getSize(fontFamily), style, fontFamily); diff --git a/platform/platform-impl/src/com/intellij/openapi/editor/impl/EditorImpl.java b/platform/platform-impl/src/com/intellij/openapi/editor/impl/EditorImpl.java index abcf5c5333e9..09e75b3f70f2 100644 --- a/platform/platform-impl/src/com/intellij/openapi/editor/impl/EditorImpl.java +++ b/platform/platform-impl/src/com/intellij/openapi/editor/impl/EditorImpl.java @@ -83,7 +83,6 @@ import com.intellij.util.Producer; import com.intellij.util.containers.ContainerUtil; import com.intellij.util.containers.ContainerUtilRt; import com.intellij.util.containers.Convertor; -import com.intellij.util.containers.HashMap; import com.intellij.util.messages.MessageBusConnection; import com.intellij.util.text.CharArrayUtil; import com.intellij.util.ui.ButtonlessScrollBarUI; @@ -5805,7 +5804,7 @@ public final class EditorImpl extends UserDataHolderBase implements EditorEx, Hi @NotNull @Override public FontPreferences getFontPreferences() { - return myFontPreferences.getFontFamilies().isEmpty() ? getGlobal().getFontPreferences() : myFontPreferences; + return myFontPreferences.getEffectiveFontFamilies().isEmpty() ? getGlobal().getFontPreferences() : myFontPreferences; } @Override