Application-level default editor font [IDEA-CR-19148]

This commit is contained in:
Rustam Vishnyakov
2017-04-18 17:59:04 +03:00
parent c152723b23
commit 0b70cdebcd
16 changed files with 940 additions and 411 deletions
@@ -18,67 +18,61 @@ package com.intellij.openapi.editor.colors;
import org.jetbrains.annotations.NotNull;
import java.util.List;
import java.util.function.Supplier;
public class DelegatingFontPreferences implements FontPreferences {
private FontPreferences myDelegate;
private Supplier<FontPreferences> myDelegateSupplier;
public DelegatingFontPreferences(FontPreferences delegate) {
myDelegate = delegate;
public DelegatingFontPreferences(@NotNull Supplier<FontPreferences> delegateSupplier) {
myDelegateSupplier = delegateSupplier;
}
@NotNull
@Override
public List<String> getEffectiveFontFamilies() {
return myDelegate.getEffectiveFontFamilies();
return myDelegateSupplier.get().getEffectiveFontFamilies();
}
@NotNull
@Override
public List<String> getRealFontFamilies() {
return myDelegate.getRealFontFamilies();
return myDelegateSupplier.get().getRealFontFamilies();
}
@NotNull
@Override
public String getFontFamily() {
return myDelegate.getFontFamily();
return myDelegateSupplier.get().getFontFamily();
}
@Override
public int getSize(@NotNull String fontFamily) {
return myDelegate.getSize(fontFamily);
return myDelegateSupplier.get().getSize(fontFamily);
}
@Override
public void copyTo(@NotNull FontPreferences preferences) {
myDelegate.copyTo(preferences);
myDelegateSupplier.get().copyTo(preferences);
}
@Override
public boolean useLigatures() {
return myDelegate.useLigatures();
return myDelegateSupplier.get().useLigatures();
}
@Override
public boolean hasSize(@NotNull String fontName) {
return myDelegate.hasSize(fontName);
return myDelegateSupplier.get().hasSize(fontName);
}
@Override
public float getLineSpacing() {
return myDelegate.getLineSpacing();
return myDelegateSupplier.get().getLineSpacing();
}
@Override
public void setLineSpacing(float lineSpacing) {
myDelegate.setLineSpacing(lineSpacing);
myDelegateSupplier.get().setLineSpacing(lineSpacing);
}
@Override
public boolean equals(Object obj) {
if (obj instanceof DelegatingFontPreferences) {
return myDelegate.equals(((DelegatingFontPreferences)obj).myDelegate);
}
return false;
}
}
@@ -77,7 +77,14 @@ public interface EditorColorsScheme extends Cloneable, TextAttributesScheme, Sch
@Deprecated
void setQuickDocFontSize(@NotNull FontSize fontSize);
@NotNull
Font getFont(EditorFontType key);
/**
* @deprecated Use {@link #getFontPreferences()} and {@link ModifiableFontPreferences}
* to change fonts.
*/
@Deprecated
void setFont(EditorFontType key, Font font);
float getLineSpacing();
@@ -103,6 +110,9 @@ public interface EditorColorsScheme extends Cloneable, TextAttributesScheme, Sch
default void setUseEditorFontPreferencesInConsole() {}
default boolean isUseEditorFontPreferencesInConsole() {return false;}
default void setUseAppFontPreferencesInEditor() {}
default boolean isUseAppFontPreferencesInEditor() {return false;}
String getConsoleFontName();
void setConsoleFontName(String fontName);
@@ -0,0 +1,32 @@
/*
* Copyright 2000-2017 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 org.jetbrains.annotations.NotNull;
import java.awt.*;
public abstract class EditorFontCache {
public static EditorFontCache getInstance() {
return ServiceManager.getService(EditorFontCache.class);
}
@NotNull
public abstract Font getFont(EditorFontType key);
public abstract void reset();
}
@@ -34,6 +34,7 @@ import com.intellij.util.JdomKt;
import com.intellij.util.PlatformUtils;
import com.intellij.util.containers.ContainerUtilRt;
import com.intellij.util.containers.HashMap;
import com.intellij.util.ui.JBUI;
import gnu.trove.THashMap;
import org.jdom.Element;
import org.jetbrains.annotations.NonNls;
@@ -53,7 +54,7 @@ import static com.intellij.openapi.util.Couple.of;
import static com.intellij.ui.ColorUtil.fromHex;
@SuppressWarnings("UseJBColor")
public abstract class AbstractColorsScheme implements EditorColorsScheme, SerializableScheme {
public abstract class AbstractColorsScheme extends EditorFontCacheImpl implements EditorColorsScheme, SerializableScheme {
private static final int CURR_VERSION = 142;
private static final FontSize DEFAULT_FONT_SIZE = FontSize.SMALL;
@@ -62,12 +63,11 @@ public abstract class AbstractColorsScheme implements EditorColorsScheme, Serial
protected FontSize myQuickDocFontSize = DEFAULT_FONT_SIZE;
@NotNull private final Map<EditorFontType, Font> myFonts = new EnumMap<>(EditorFontType.class);
@NotNull private FontPreferencesImpl myFontPreferences = new FontPreferencesImpl();
@NotNull private FontPreferences myConsoleFontPreferences = new DelegatingFontPreferences(myFontPreferences);
@NotNull private FontPreferences myFontPreferences
= new DelegatingFontPreferences(() -> AppEditorFontOptions.getInstance().getFontPreferences());
@NotNull private FontPreferences myConsoleFontPreferences = new DelegatingFontPreferences(() -> myFontPreferences);
private final ValueElementReader myValueReader = new TextAttributesReader();
private String myFallbackFontName;
private String mySchemeName;
private boolean myIsSaveNeeded;
@@ -124,7 +124,6 @@ public abstract class AbstractColorsScheme implements EditorColorsScheme, Serial
protected AbstractColorsScheme(EditorColorsScheme parentScheme) {
myParentScheme = parentScheme;
myFontPreferences.setChangeListener(() -> initFonts());
}
public AbstractColorsScheme() {
@@ -161,14 +160,12 @@ public abstract class AbstractColorsScheme implements EditorColorsScheme, Serial
@Override
public void setFont(EditorFontType key, Font font) {
myFonts.put(key, font);
}
@Override
public abstract Object clone();
public void copyTo(AbstractColorsScheme newScheme) {
myFontPreferences.copyTo(newScheme.myFontPreferences);
newScheme.myQuickDocFontSize = myQuickDocFontSize;
if (myConsoleFontPreferences instanceof DelegatingFontPreferences) {
newScheme.setUseEditorFontPreferencesInConsole();
@@ -176,11 +173,11 @@ public abstract class AbstractColorsScheme implements EditorColorsScheme, Serial
else {
newScheme.setConsoleFontPreferences(myConsoleFontPreferences);
}
final Set<EditorFontType> types = myFonts.keySet();
for (EditorFontType type : types) {
Font font = myFonts.get(type);
newScheme.setFont(type, font);
if (myFontPreferences instanceof DelegatingFontPreferences) {
newScheme.setUseAppFontPreferencesInEditor();
}
else {
newScheme.setFontPreferences(myFontPreferences);
}
newScheme.myAttributesMap = new THashMap<>(myAttributesMap);
@@ -191,18 +188,29 @@ public abstract class AbstractColorsScheme implements EditorColorsScheme, Serial
@Override
public void setEditorFontName(String fontName) {
int editorFontSize = getEditorFontSize();
myFontPreferences.clear();
myFontPreferences.register(fontName, editorFontSize);
ensureEditableFontPreferences().clear();
ensureEditableFontPreferences().register(fontName, editorFontSize);
initFonts();
}
@Override
public void setEditorFontSize(int fontSize) {
fontSize = EditorFontsConstants.checkAndFixEditorFontSize(fontSize);
myFontPreferences.register(getEditorFontName(), fontSize);
ensureEditableFontPreferences().register(myFontPreferences.getFontFamily(), fontSize);
initFonts();
}
@Override
public void setUseAppFontPreferencesInEditor() {
myFontPreferences = new DelegatingFontPreferences(()-> AppEditorFontOptions.getInstance().getFontPreferences());
initFonts();
}
@Override
public boolean isUseAppFontPreferencesInEditor() {
return myFontPreferences instanceof DelegatingFontPreferences;
}
@Override
public void setQuickDocFontSize(@NotNull FontSize fontSize) {
if (myQuickDocFontSize != fontSize) {
@@ -216,14 +224,10 @@ public abstract class AbstractColorsScheme implements EditorColorsScheme, Serial
myFontPreferences.setLineSpacing(lineSpacing);
}
@NotNull
@Override
public Font getFont(EditorFontType key) {
UISettings uiSettings = UISettings.getInstance();
if (uiSettings.getPresentationMode()) {
final Font font = myFonts.get(key);
return new Font(font.getName(), font.getStyle(), uiSettings.getPresentationModeFontSize());
}
return myFonts.get(key);
return myFontPreferences instanceof DelegatingFontPreferences ? EditorFontCache.getInstance().getFont(key) : super.getFont(key);
}
@Override
@@ -239,21 +243,18 @@ public abstract class AbstractColorsScheme implements EditorColorsScheme, Serial
@Override
public void setFontPreferences(@NotNull FontPreferences preferences) {
preferences.copyTo(myFontPreferences);
preferences.copyTo(ensureEditableFontPreferences());
initFonts();
}
@Override
public String getEditorFontName() {
if (myFallbackFontName != null) {
return myFallbackFontName;
}
return myFontPreferences.getFontFamily();
return getFont(EditorFontType.PLAIN).getFontName();
}
@Override
public int getEditorFontSize() {
return myFontPreferences.getSize(getEditorFontName());
return myFontPreferences.getSize(myFontPreferences.getFontFamily());
}
@NotNull
@@ -268,35 +269,12 @@ public abstract class AbstractColorsScheme implements EditorColorsScheme, Serial
}
protected void initFonts() {
String editorFontName = getEditorFontName();
int editorFontSize = getEditorFontSize();
reset();
}
myFallbackFontName = FontPreferences.getFallbackName(editorFontName, editorFontSize, myParentScheme);
if (myFallbackFontName != null) {
editorFontName = myFallbackFontName;
}
Font plainFont = new Font(editorFontName, Font.PLAIN, editorFontSize);
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);
myFonts.put(EditorFontType.PLAIN, plainFont);
myFonts.put(EditorFontType.BOLD, boldFont);
myFonts.put(EditorFontType.ITALIC, italicFont);
myFonts.put(EditorFontType.BOLD_ITALIC, boldItalicFont);
String consoleFontName = getConsoleFontName();
int consoleFontSize = getConsoleFontSize();
Font consolePlainFont = new Font(consoleFontName, Font.PLAIN, consoleFontSize);
Font consoleBoldFont = new Font(consoleFontName, Font.BOLD, consoleFontSize);
Font consoleItalicFont = new Font(consoleFontName, Font.ITALIC, consoleFontSize);
Font consoleBoldItalicFont = new Font(consoleFontName, Font.BOLD | Font.ITALIC, consoleFontSize);
myFonts.put(EditorFontType.CONSOLE_PLAIN, consolePlainFont);
myFonts.put(EditorFontType.CONSOLE_BOLD, consoleBoldFont);
myFonts.put(EditorFontType.CONSOLE_ITALIC, consoleItalicFont);
myFonts.put(EditorFontType.CONSOLE_BOLD_ITALIC, consoleBoldItalicFont);
@Override
protected EditorColorsScheme getFontCacheScheme() {
return this;
}
public String toString() {
@@ -508,7 +486,7 @@ public abstract class AbstractColorsScheme implements EditorColorsScheme, Serial
}
case EDITOR_LIGATURES: {
Boolean value = myValueReader.read(Boolean.class, childNode);
if (value != null) myFontPreferences.setUseLigatures(value);
if (value != null) ensureEditableFontPreferences().setUseLigatures(value);
break;
}
case CONSOLE_LIGATURES: {
@@ -531,7 +509,7 @@ public abstract class AbstractColorsScheme implements EditorColorsScheme, Serial
}
return UISettings.restoreFontSize(intSize, fontScale);
}
private FontPreferencesImpl readFontSettings(@NotNull Element element,
boolean isDefaultScheme,
@Nullable Float fontScale) {
@@ -571,7 +549,9 @@ public abstract class AbstractColorsScheme implements EditorColorsScheme, Serial
* will be able to restore the font size according to its scale and the IDE HiDPI mode. The default
* FONT_SCALE value should also be written by that reason.
*/
JdomKt.addOptionTag(parentNode, FONT_SCALE, String.valueOf(UISettings.getNormalizingScale())); // must precede font options
if (!(myFontPreferences instanceof DelegatingFontPreferences) || !(myConsoleFontPreferences instanceof DelegatingFontPreferences)) {
JdomKt.addOptionTag(parentNode, FONT_SCALE, String.valueOf(JBUI.scale(1f))); // must precede font options
}
if (myParentScheme != null && myParentScheme != EmptyColorScheme.INSTANCE) {
parentNode.setAttribute(PARENT_SCHEME_ATTR, myParentScheme.getName());
@@ -589,13 +569,16 @@ public abstract class AbstractColorsScheme implements EditorColorsScheme, Serial
// 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.getEffectiveFontFamilies().size() <= 1;
if (useOldFontFormat) {
JdomKt.addOptionTag(parentNode, EDITOR_FONT_SIZE, String.valueOf(getEditorFontSize()));
if (!(myFontPreferences instanceof DelegatingFontPreferences)) {
if (useOldFontFormat) {
JdomKt.addOptionTag(parentNode, EDITOR_FONT_SIZE, String.valueOf(getEditorFontSize()));
JdomKt.addOptionTag(parentNode, EDITOR_FONT_NAME, myFontPreferences.getFontFamily());
}
else {
writeFontPreferences(EDITOR_FONT, parentNode, myFontPreferences);
}
writeLigaturesPreferences(parentNode, myFontPreferences, EDITOR_LIGATURES);
}
else {
writeFontPreferences(EDITOR_FONT, parentNode, myFontPreferences);
}
writeLigaturesPreferences(parentNode, myFontPreferences, EDITOR_LIGATURES);
if (!(myConsoleFontPreferences instanceof DelegatingFontPreferences)) {
if (myConsoleFontPreferences.getEffectiveFontFamilies().size() <= 1) {
@@ -619,7 +602,7 @@ public abstract class AbstractColorsScheme implements EditorColorsScheme, Serial
}
if (useOldFontFormat) {
JdomKt.addOptionTag(parentNode, EDITOR_FONT_NAME, getEditorFontName());
JdomKt.addOptionTag(parentNode, EDITOR_FONT_NAME, myFontPreferences.getFontFamily());
}
Element colorElements = new Element(COLORS_ELEMENT);
@@ -762,6 +745,16 @@ public abstract class AbstractColorsScheme implements EditorColorsScheme, Serial
return true;
}
private ModifiableFontPreferences ensureEditableFontPreferences() {
if (!(myFontPreferences instanceof ModifiableFontPreferences)) {
ModifiableFontPreferences editablePrefs = new FontPreferencesImpl();
myFontPreferences.copyTo(editablePrefs);
myFontPreferences = editablePrefs;
((FontPreferencesImpl)myFontPreferences).setChangeListener(() -> initFonts());
}
return (ModifiableFontPreferences)myFontPreferences;
}
@NotNull
@Override
public FontPreferences getConsoleFontPreferences() {
@@ -770,7 +763,7 @@ public abstract class AbstractColorsScheme implements EditorColorsScheme, Serial
@Override
public void setUseEditorFontPreferencesInConsole() {
myConsoleFontPreferences = new DelegatingFontPreferences(myFontPreferences);
myConsoleFontPreferences = new DelegatingFontPreferences(() -> myFontPreferences);
initFonts();
}
@@ -939,13 +932,18 @@ public abstract class AbstractColorsScheme implements EditorColorsScheme, Serial
}
}
return myFontPreferences.equals(otherScheme.getFontPreferences()) &&
myConsoleFontPreferences.equals(otherScheme.getConsoleFontPreferences()) &&
return areDelegatingOrEqual(myFontPreferences, otherScheme.getFontPreferences()) &&
areDelegatingOrEqual(myConsoleFontPreferences, otherScheme.getConsoleFontPreferences()) &&
attributesEqual(otherScheme) &&
colorsEqual(otherScheme) &&
myFontPreferences.equals(otherScheme.myFontPreferences);
colorsEqual(otherScheme);
}
protected static boolean areDelegatingOrEqual(@NotNull FontPreferences preferences1, @NotNull FontPreferences preferences2) {
boolean isDelegating1 = preferences1 instanceof DelegatingFontPreferences;
boolean isDelegating2 = preferences2 instanceof DelegatingFontPreferences;
return isDelegating1 || isDelegating2 ? isDelegating1 && isDelegating2 : preferences1.equals(preferences2);
}
protected boolean attributesEqual(AbstractColorsScheme otherScheme) {
return myAttributesMap.equals(otherScheme.myAttributesMap);
}
@@ -0,0 +1,71 @@
/*
* Copyright 2000-2017 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.impl;
import com.intellij.openapi.components.PersistentStateComponent;
import com.intellij.openapi.components.ServiceManager;
import com.intellij.openapi.components.State;
import com.intellij.openapi.components.Storage;
import com.intellij.openapi.editor.colors.EditorFontCache;
import com.intellij.openapi.editor.colors.FontPreferences;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
@State(name = "DefaultFont", storages = @Storage("editor.xml"))
public class AppEditorFontOptions implements PersistentStateComponent<AppEditorFontOptions.PersistentFontPreferences> {
private final FontPreferencesImpl myFontPreferences = new FontPreferencesImpl();
public static class PersistentFontPreferences {
/**
* Serialization constructor.
*/
@SuppressWarnings("unused")
private PersistentFontPreferences() {
}
public PersistentFontPreferences(FontPreferences fontPreferences) {
FONT_FAMILY = fontPreferences.getFontFamily();
FONT_SIZE = fontPreferences.getSize(FONT_FAMILY);
}
public int FONT_SIZE;
public String FONT_FAMILY;
}
public static AppEditorFontOptions getInstance() {
return ServiceManager.getService(AppEditorFontOptions.class);
}
@Nullable
@Override
public PersistentFontPreferences getState() {
return new PersistentFontPreferences(myFontPreferences);
}
@Override
public void loadState(PersistentFontPreferences state) {
myFontPreferences.clear();
myFontPreferences.register(state.FONT_FAMILY, state.FONT_SIZE);
myFontPreferences.setChangeListener(() -> EditorFontCache.getInstance().reset());
}
@NotNull
public FontPreferences getFontPreferences() {
return myFontPreferences;
}
}
@@ -0,0 +1,100 @@
/*
* Copyright 2000-2017 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.impl;
import com.intellij.ide.ui.UISettings;
import com.intellij.openapi.editor.colors.*;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.awt.*;
import java.util.EnumMap;
import java.util.Map;
public class EditorFontCacheImpl extends EditorFontCache {
@NotNull private final Map<EditorFontType, Font> myFonts = new EnumMap<>(EditorFontType.class);
@Override
@NotNull
public Font getFont(EditorFontType key) {
synchronized (myFonts) {
if (myFonts.isEmpty()) {
initFonts();
}
final Font font = myFonts.get(key);
assert font != null : "Font " + key + " not found.";
UISettings uiSettings = UISettings.getInstance();
if (uiSettings.getPresentationMode()) {
return new Font(font.getName(), font.getStyle(), uiSettings.getPresentationModeFontSize());
}
return font;
}
}
@Override
public void reset() {
synchronized (myFonts) {
myFonts.clear();
}
}
protected EditorColorsScheme getFontCacheScheme() {
return EditorColorsManager.getInstance().getGlobalScheme();
}
private void initFonts() {
EditorColorsScheme scheme = getFontCacheScheme();
String editorFontName = scheme.getFontPreferences().getFontFamily();
int editorFontSize = scheme.getEditorFontSize();
String fallbackName = getFallbackName(editorFontName, editorFontSize);
if (fallbackName != null) {
editorFontName = fallbackName;
}
Font plainFont = new Font(editorFontName, Font.PLAIN, editorFontSize);
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);
myFonts.put(EditorFontType.PLAIN, plainFont);
myFonts.put(EditorFontType.BOLD, boldFont);
myFonts.put(EditorFontType.ITALIC, italicFont);
myFonts.put(EditorFontType.BOLD_ITALIC, boldItalicFont);
String consoleFontName = scheme.getConsoleFontName();
int consoleFontSize = scheme.getConsoleFontSize();
Font consolePlainFont = new Font(consoleFontName, Font.PLAIN, consoleFontSize);
Font consoleBoldFont = new Font(consoleFontName, Font.BOLD, consoleFontSize);
Font consoleItalicFont = new Font(consoleFontName, Font.ITALIC, consoleFontSize);
Font consoleBoldItalicFont = new Font(consoleFontName, Font.BOLD | Font.ITALIC, consoleFontSize);
myFonts.put(EditorFontType.CONSOLE_PLAIN, consolePlainFont);
myFonts.put(EditorFontType.CONSOLE_BOLD, consoleBoldFont);
myFonts.put(EditorFontType.CONSOLE_ITALIC, consoleItalicFont);
myFonts.put(EditorFontType.CONSOLE_BOLD_ITALIC, consoleBoldItalicFont);
}
@Nullable
private static String getFallbackName(@NotNull String fontName, int fontSize) {
Font plainFont = new Font(fontName, Font.PLAIN, fontSize);
if (plainFont.getFamily().equals("Dialog") && !("Dialog".equals(fontName) || fontName.startsWith("Dialog."))) {
FontPreferences appPrefs = AppEditorFontOptions.getInstance().getFontPreferences();
return appPrefs.getFontFamily();
}
return null;
}
}
@@ -0,0 +1,357 @@
/*
* Copyright 2000-2017 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.EditorFontsConstants;
import com.intellij.icons.AllIcons;
import com.intellij.ide.IdeTooltipManager;
import com.intellij.openapi.application.ApplicationBundle;
import com.intellij.openapi.application.ApplicationNamesInfo;
import com.intellij.openapi.editor.colors.EditorColorsManager;
import com.intellij.openapi.editor.colors.FontPreferences;
import com.intellij.openapi.editor.colors.ModifiableFontPreferences;
import com.intellij.openapi.ui.MessageType;
import com.intellij.openapi.util.SystemInfo;
import com.intellij.ui.DocumentAdapter;
import com.intellij.ui.FontComboBox;
import com.intellij.ui.FontInfoRenderer;
import com.intellij.ui.TooltipWithClickableLinks;
import com.intellij.ui.components.JBCheckBox;
import com.intellij.util.EventDispatcher;
import com.intellij.util.ui.JBUI;
import net.miginfocom.swing.MigLayout;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import javax.swing.*;
import javax.swing.event.DocumentEvent;
import java.awt.*;
import java.awt.event.ActionListener;
import java.awt.event.ItemListener;
import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent;
import java.util.HashSet;
import java.util.List;
import java.util.Locale;
import java.util.Set;
public abstract class AbstractFontOptionsPanel extends JPanel implements OptionsPanel {
private static final FontInfoRenderer RENDERER = new FontInfoRenderer() {
@Override
protected boolean isEditorFont() {
return true;
}
};
private final EventDispatcher<ColorAndFontSettingsListener> myDispatcher = EventDispatcher.create(ColorAndFontSettingsListener.class);
@NotNull private final JTextField myEditorFontSizeField = new JTextField(4);
@NotNull private final JTextField myLineSpacingField = new JTextField(4);
private final FontComboBox myPrimaryCombo = new FontComboBox();
private final JCheckBox myUseSecondaryFontCheckbox = new JCheckBox(ApplicationBundle.message("secondary.font"));
private final JCheckBox myEnableLigaturesCheckbox = new JCheckBox(ApplicationBundle.message("use.ligatures"));
private final FontComboBox mySecondaryCombo = new FontComboBox(false, false);
@NotNull private final JBCheckBox myOnlyMonospacedCheckBox =
new JBCheckBox(ApplicationBundle.message("checkbox.show.only.monospaced.fonts"));
private boolean myIsInSchemeChange;
private JLabel myPrimaryLabel;
private JLabel mySizeLabel;
protected AbstractFontOptionsPanel() {
setLayout(new MigLayout("ins 0, gap 5, flowx"));
initControls();
}
@SuppressWarnings("unchecked")
protected void initControls() {
add(myOnlyMonospacedCheckBox, "newline 10, sgx b, sx 2");
myPrimaryLabel = new JLabel(ApplicationBundle.message("primary.font"));
add(myPrimaryLabel, "newline, ax right");
add(myPrimaryCombo, "sgx b");
mySizeLabel = new JLabel(ApplicationBundle.message("editbox.font.size"));
add(mySizeLabel, "gapleft 20");
add(myEditorFontSizeField);
add(new JLabel(ApplicationBundle.message("editbox.line.spacing")), "gapleft 20");
add(myLineSpacingField);
add(new JLabel(ApplicationBundle.message("label.fallback.fonts.list.description"),
MessageType.INFO.getDefaultIcon(),
SwingConstants.LEFT), "newline, sx 5");
add(myUseSecondaryFontCheckbox, "newline, ax right");
add(mySecondaryCombo, "sgx b");
JPanel panel = new JPanel(new FlowLayout(FlowLayout.CENTER, 0, 0));
myEnableLigaturesCheckbox.setBorder(null);
panel.add(myEnableLigaturesCheckbox);
JLabel warningIcon = new JLabel(AllIcons.General.BalloonWarning);
IdeTooltipManager.getInstance().setCustomTooltip(
warningIcon,
new TooltipWithClickableLinks.ForBrowser(warningIcon,
ApplicationBundle.message("ligatures.jre.warning",
ApplicationNamesInfo.getInstance().getFullProductName())));
warningIcon.setBorder(JBUI.Borders.emptyLeft(5));
warningIcon.setVisible(!SystemInfo.isJetbrainsJvm);
panel.add(warningIcon);
add(panel, "newline, sx 2");
myOnlyMonospacedCheckBox.setBorder(null);
myUseSecondaryFontCheckbox.setBorder(null);
mySecondaryCombo.setEnabled(false);
myOnlyMonospacedCheckBox.setSelected(EditorColorsManager.getInstance().isUseOnlyMonospacedFonts());
myOnlyMonospacedCheckBox.addActionListener(e -> {
EditorColorsManager.getInstance().setUseOnlyMonospacedFonts(myOnlyMonospacedCheckBox.isSelected());
myPrimaryCombo.setMonospacedOnly(myOnlyMonospacedCheckBox.isSelected());
mySecondaryCombo.setMonospacedOnly(myOnlyMonospacedCheckBox.isSelected());
});
myPrimaryCombo.setMonospacedOnly(myOnlyMonospacedCheckBox.isSelected());
myPrimaryCombo.setRenderer(RENDERER);
mySecondaryCombo.setMonospacedOnly(myOnlyMonospacedCheckBox.isSelected());
mySecondaryCombo.setRenderer(RENDERER);
myUseSecondaryFontCheckbox.addActionListener(e -> {
mySecondaryCombo.setEnabled(myUseSecondaryFontCheckbox.isSelected());
syncFontFamilies();
});
ItemListener itemListener = this::syncFontFamilies;
myPrimaryCombo.addItemListener(itemListener);
mySecondaryCombo.addItemListener(itemListener);
ActionListener actionListener = this::syncFontFamilies;
myPrimaryCombo.addActionListener(actionListener);
mySecondaryCombo.addActionListener(actionListener);
myEditorFontSizeField.getDocument().addDocumentListener(new DocumentAdapter() {
@Override
public void textChanged(DocumentEvent event) {
if (myIsInSchemeChange || !SwingUtilities.isEventDispatchThread()) return;
String selectedFont = myPrimaryCombo.getFontName();
if (selectedFont != null) {
setFontSize(getFontSizeFromField());
}
updateDescription(true);
}
});
myEditorFontSizeField.addKeyListener(new KeyAdapter() {
@Override
public void keyPressed(KeyEvent e) {
if (e.getKeyCode() != KeyEvent.VK_UP && e.getKeyCode() != KeyEvent.VK_DOWN) return;
boolean up = e.getKeyCode() == KeyEvent.VK_UP;
try {
int value = Integer.parseInt(myEditorFontSizeField.getText());
value += (up ? 1 : -1);
value = Math.min(EditorFontsConstants.getMaxEditorFontSize(), Math.max(EditorFontsConstants.getMinEditorFontSize(), value));
myEditorFontSizeField.setText(String.valueOf(value));
}
catch (NumberFormatException ignored) {
}
}
});
myLineSpacingField.getDocument().addDocumentListener(new DocumentAdapter() {
@Override
public void textChanged(DocumentEvent event) {
if (myIsInSchemeChange) return;
float lineSpacing = getLineSpacingFromField();
if (getLineSpacing() != lineSpacing) {
setCurrentLineSpacing(lineSpacing);
}
updateDescription(true);
}
});
myLineSpacingField.addKeyListener(new KeyAdapter() {
@Override
public void keyPressed(KeyEvent e) {
if (e.getKeyCode() != KeyEvent.VK_UP && e.getKeyCode() != KeyEvent.VK_DOWN) return;
boolean up = e.getKeyCode() == KeyEvent.VK_UP;
try {
float value = Float.parseFloat(myLineSpacingField.getText());
value += (up ? 1 : -1) * .1F;
value = Math.min(EditorFontsConstants.getMaxEditorLineSpacing(), Math.max(EditorFontsConstants.getMinEditorLineSpacing(), value));
myLineSpacingField.setText(String.format(Locale.ENGLISH, "%.1f", value));
}
catch (NumberFormatException ignored) {
}
}
});
myEnableLigaturesCheckbox.addActionListener(e -> {
FontPreferences preferences = getFontPreferences();
if (preferences instanceof ModifiableFontPreferences) {
((ModifiableFontPreferences)preferences).setUseLigatures(myEnableLigaturesCheckbox.isSelected());
updateDescription(true);
}
});
}
protected void setDelegatingPreferences(boolean isDelegating) {
}
private int getFontSizeFromField() {
try {
return Math.min(EditorFontsConstants.getMaxEditorFontSize(),
Math.max(EditorFontsConstants.getMinEditorFontSize(), Integer.parseInt(myEditorFontSizeField.getText())));
}
catch (NumberFormatException e) {
return EditorFontsConstants.getDefaultEditorFontSize();
}
}
private float getLineSpacingFromField() {
try {
return Math.min(EditorFontsConstants.getMaxEditorLineSpacing(),
Math.max(EditorFontsConstants.getMinEditorLineSpacing(), Float.parseFloat(myLineSpacingField.getText())));
}
catch (NumberFormatException e) {
return EditorFontsConstants.getDefaultEditorLineSpacing();
}
}
/**
* Processes an event from {@code FontComboBox}
* if it is enabled and its item is selected.
*
* @param event the event to process
*/
private void syncFontFamilies(AWTEvent event) {
Object source = event.getSource();
if (source instanceof FontComboBox) {
FontComboBox combo = (FontComboBox)source;
if (combo.isEnabled() && combo.isShowing() && combo.getSelectedItem() != null) {
syncFontFamilies();
}
}
}
private void syncFontFamilies() {
if (myIsInSchemeChange) {
return;
}
FontPreferences fontPreferences = getFontPreferences();
if (fontPreferences instanceof ModifiableFontPreferences) {
ModifiableFontPreferences modifiableFontPreferences = (ModifiableFontPreferences)fontPreferences;
modifiableFontPreferences.clearFonts();
String primaryFontFamily = myPrimaryCombo.getFontName();
String secondaryFontFamily = mySecondaryCombo.isEnabled() ? mySecondaryCombo.getFontName() : null;
int fontSize = getFontSizeFromField();
if (primaryFontFamily != null) {
if (!FontPreferences.DEFAULT_FONT_NAME.equals(primaryFontFamily)) {
modifiableFontPreferences.addFontFamily(primaryFontFamily);
}
modifiableFontPreferences.register(primaryFontFamily, fontSize);
}
if (secondaryFontFamily != null) {
if (!FontPreferences.DEFAULT_FONT_NAME.equals(secondaryFontFamily)) {
modifiableFontPreferences.addFontFamily(secondaryFontFamily);
}
modifiableFontPreferences.register(secondaryFontFamily, fontSize);
}
updateDescription(true);
}
}
@Override
public void updateOptionsList() {
myIsInSchemeChange = true;
myLineSpacingField.setText(Float.toString(getLineSpacing()));
FontPreferences fontPreferences = getFontPreferences();
List<String> fontFamilies = fontPreferences.getEffectiveFontFamilies();
myPrimaryCombo.setFontName(fontPreferences.getFontFamily());
boolean isThereSecondaryFont = fontFamilies.size() > 1;
myUseSecondaryFontCheckbox.setSelected(isThereSecondaryFont);
mySecondaryCombo.setFontName(isThereSecondaryFont ? fontFamilies.get(1) : null);
myEditorFontSizeField.setText(String.valueOf(fontPreferences.getSize(fontPreferences.getFontFamily())));
boolean isReadOnlyColorScheme = isReadOnly();
updateCustomOptions();
boolean readOnly = isReadOnlyColorScheme || !(getFontPreferences() instanceof ModifiableFontPreferences);
myPrimaryCombo.setEnabled(!readOnly);
myPrimaryLabel.setEnabled(!readOnly);
mySecondaryCombo.setEnabled(isThereSecondaryFont && !readOnly);
myOnlyMonospacedCheckBox.setEnabled(!readOnly);
myLineSpacingField.setEnabled(!readOnly);
myEditorFontSizeField.setEnabled(!readOnly);
mySizeLabel.setEnabled(!readOnly);
myUseSecondaryFontCheckbox.setEnabled(!readOnly);
myEnableLigaturesCheckbox.setEnabled(!readOnly && SystemInfo.isJetbrainsJvm);
myEnableLigaturesCheckbox.setSelected(fontPreferences.useLigatures());
myIsInSchemeChange = false;
}
protected void updateCustomOptions() {
}
protected abstract boolean isReadOnly();
protected abstract boolean isDelegating();
@NotNull
protected abstract FontPreferences getFontPreferences();
protected abstract void setFontSize(int fontSize);
protected abstract float getLineSpacing();
protected abstract void setCurrentLineSpacing(float lineSpacing);
@Override
@Nullable
public Runnable showOption(final String option) {
return null;
}
@Override
public void applyChangesToScheme() {
}
@Override
public void selectOption(final String typeToSelect) {
}
public boolean updateDescription(boolean modified) {
if (modified && isReadOnly()) {
return false;
}
fireFontChanged();
return true;
}
@Override
public void addListener(ColorAndFontSettingsListener listener) {
myDispatcher.addListener(listener);
}
public void fireFontChanged() {
myDispatcher.getMulticaster().fontChanged();
}
@Override
public JPanel getPanel() {
return this;
}
@Override
public Set<String> processListOptions() {
return new HashSet<>();
}
}
@@ -512,7 +512,7 @@ public class ColorAndFontOptions extends SearchableConfigurable.Parent.Abstract
@Override
@NotNull
public NewColorAndFontPanel createPanel(@NotNull ColorAndFontOptions options) {
FontEditorPreview previewPanel = new FontEditorPreview(options, true);
FontEditorPreview previewPanel = new FontEditorPreview(()->options.getSelectedScheme(), true);
return new NewColorAndFontPanel(new SchemesPanel(options), new FontOptions(options), previewPanel, "Font", null, null){
@Override
public boolean containsFontOptions() {
@@ -532,7 +532,7 @@ public class ColorAndFontOptions extends SearchableConfigurable.Parent.Abstract
@Override
@NotNull
public NewColorAndFontPanel createPanel(@NotNull ColorAndFontOptions options) {
FontEditorPreview previewPanel = new FontEditorPreview(options, false) {
FontEditorPreview previewPanel = new FontEditorPreview(()->options.getSelectedScheme(), false) {
@Override
protected EditorColorsScheme updateOptionsScheme(EditorColorsScheme selectedScheme) {
return ConsoleViewUtil.updateConsoleColorScheme(selectedScheme);
@@ -1082,8 +1082,6 @@ public class ColorAndFontOptions extends SearchableConfigurable.Parent.Abstract
private MyColorScheme(@NotNull EditorColorsScheme parentScheme) {
super(parentScheme);
parentScheme.getFontPreferences().copyTo(getFontPreferences());
if (parentScheme.isUseEditorFontPreferencesInConsole()) {
setUseEditorFontPreferencesInConsole();
}
@@ -1092,6 +1090,13 @@ public class ColorAndFontOptions extends SearchableConfigurable.Parent.Abstract
}
setConsoleLineSpacing(parentScheme.getConsoleLineSpacing());
if (parentScheme.isUseAppFontPreferencesInEditor()) {
setUseAppFontPreferencesInEditor();
}
else {
setFontPreferences(parentScheme.getFontPreferences());
}
setQuickDocFontSize(parentScheme.getQuickDocFontSize());
myName = parentScheme.getName();
@@ -1149,11 +1154,11 @@ public class ColorAndFontOptions extends SearchableConfigurable.Parent.Abstract
}
private boolean isFontModified() {
return !getFontPreferences().equals(myParentScheme.getFontPreferences());
return !areDelegatingOrEqual(getFontPreferences(), myParentScheme.getFontPreferences());
}
private boolean isConsoleFontModified() {
return !getConsoleFontPreferences().equals(myParentScheme.getConsoleFontPreferences());
return !areDelegatingOrEqual(getConsoleFontPreferences(), myParentScheme.getConsoleFontPreferences());
}
private boolean apply() {
@@ -1166,7 +1171,12 @@ public class ColorAndFontOptions extends SearchableConfigurable.Parent.Abstract
private boolean apply(@NotNull EditorColorsScheme scheme) {
boolean isModified = isFontModified() || isConsoleFontModified();
scheme.setFontPreferences(getFontPreferences());
if (isUseAppFontPreferencesInEditor()) {
scheme.setUseAppFontPreferencesInEditor();
}
else {
scheme.setFontPreferences(getFontPreferences());
}
if (isUseEditorFontPreferencesInConsole()) {
scheme.setUseEditorFontPreferencesInConsole();
@@ -18,13 +18,18 @@ package com.intellij.application.options.colors;
import com.intellij.openapi.editor.colors.DelegatingFontPreferences;
import com.intellij.openapi.editor.colors.FontPreferences;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
/**
* User: anna
*/
public class ConsoleFontOptions extends FontOptions {
public ConsoleFontOptions(ColorAndFontOptions options) {
super(options, "Use editor font preferences");
super(options);
}
@Nullable
@Override
protected String getInheritFontTitle() {
return "Use editor font preferences";
}
@NotNull
@@ -24,28 +24,27 @@ import com.intellij.openapi.editor.*;
import com.intellij.openapi.editor.colors.EditorColorsScheme;
import com.intellij.openapi.editor.ex.EditorEx;
import com.intellij.openapi.editor.ex.EditorMarkupModel;
import com.intellij.openapi.editor.impl.EditorImpl;
import com.intellij.openapi.util.Disposer;
import com.intellij.util.EventDispatcher;
import com.intellij.util.ui.JBUI;
import org.jetbrains.annotations.Nls;
import org.jetbrains.annotations.NotNull;
import java.awt.*;
import java.util.function.Supplier;
public class FontEditorPreview implements PreviewPanel{
private final EditorEx myEditor;
private final ColorAndFontOptions myOptions;
private final Supplier<EditorColorsScheme> mySchemeSupplier;
private final EventDispatcher<ColorAndFontSettingsListener> myDispatcher = EventDispatcher.create(ColorAndFontSettingsListener.class);
FontEditorPreview(final ColorAndFontOptions options, boolean editable) {
myOptions = options;
public FontEditorPreview(final Supplier<EditorColorsScheme> schemeSupplier, boolean editable) {
mySchemeSupplier = schemeSupplier;
@Nls String text = getIDEDemoText();
myEditor = (EditorEx)createPreviewEditor(text, 10, 3, -1, myOptions, editable);
myEditor = (EditorEx)createPreviewEditor(text, 10, 3, -1, mySchemeSupplier.get(), editable);
installTrafficLights(myEditor);
}
@@ -82,11 +81,11 @@ public class FontEditorPreview implements PreviewPanel{
((EditorMarkupModel)editor.getMarkupModel()).setErrorStripeVisible(true);
}
static Editor createPreviewEditor(String text, int column, int line, int selectedLine, ColorAndFontOptions options, boolean editable) {
static Editor createPreviewEditor(String text, int column, int line, int selectedLine, EditorColorsScheme scheme, boolean editable) {
EditorFactory editorFactory = EditorFactory.getInstance();
Document editorDocument = editorFactory.createDocument(text);
EditorEx editor = (EditorEx) (editable ? editorFactory.createEditor(editorDocument) : editorFactory.createViewer(editorDocument));
editor.setColorsScheme(options.getSelectedScheme());
editor.setColorsScheme(scheme);
EditorSettings settings = editor.getSettings();
settings.setLineNumbersShown(true);
settings.setWhitespacesShown(true);
@@ -115,7 +114,7 @@ public class FontEditorPreview implements PreviewPanel{
@Override
public void updateView() {
EditorColorsScheme scheme = updateOptionsScheme(myOptions.getSelectedScheme());
EditorColorsScheme scheme = updateOptionsScheme(mySchemeSupplier.get());
myEditor.setColorsScheme(scheme);
myEditor.reinitSettings();
@@ -16,74 +16,36 @@
package com.intellij.application.options.colors;
import com.intellij.application.options.EditorFontsConstants;
import com.intellij.icons.AllIcons;
import com.intellij.ide.IdeTooltipManager;
import com.intellij.openapi.application.ApplicationBundle;
import com.intellij.openapi.application.ApplicationNamesInfo;
import com.intellij.openapi.editor.colors.*;
import com.intellij.openapi.ui.MessageType;
import com.intellij.openapi.util.SystemInfo;
import com.intellij.ui.DocumentAdapter;
import com.intellij.ui.FontComboBox;
import com.intellij.ui.FontInfoRenderer;
import com.intellij.ui.TooltipWithClickableLinks;
import com.intellij.ui.components.JBCheckBox;
import com.intellij.util.EventDispatcher;
import com.intellij.util.ui.JBUI;
import net.miginfocom.swing.MigLayout;
import com.intellij.openapi.editor.colors.DelegatingFontPreferences;
import com.intellij.openapi.editor.colors.EditorColorsScheme;
import com.intellij.openapi.editor.colors.FontPreferences;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import javax.swing.*;
import javax.swing.event.DocumentEvent;
import java.awt.*;
import java.awt.event.*;
import java.util.HashSet;
import java.util.List;
import java.util.Locale;
import java.util.Set;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
public class FontOptions extends JPanel implements OptionsPanel{
private static final FontInfoRenderer RENDERER = new FontInfoRenderer() {
@Override
protected boolean isEditorFont() {
return true;
}
};
private final EventDispatcher<ColorAndFontSettingsListener> myDispatcher = EventDispatcher.create(ColorAndFontSettingsListener.class);
public class FontOptions extends AbstractFontOptionsPanel {
@NotNull private final ColorAndFontOptions myOptions;
@NotNull private final JTextField myEditorFontSizeField = new JTextField(4);
@NotNull private final JTextField myLineSpacingField = new JTextField(4);
private final FontComboBox myPrimaryCombo = new FontComboBox();
private final JCheckBox myUseSecondaryFontCheckbox = new JCheckBox(ApplicationBundle.message("secondary.font"));
private final JCheckBox myEnableLigaturesCheckbox = new JCheckBox(ApplicationBundle.message("use.ligatures"));
private final FontComboBox mySecondaryCombo = new FontComboBox(false, false);
private @Nullable JCheckBox myInheritFontCheckbox;
private final JCheckBox myInheritFontCheckbox;
@NotNull private final JBCheckBox myOnlyMonospacedCheckBox =
new JBCheckBox(ApplicationBundle.message("checkbox.show.only.monospaced.fonts"));
private boolean myIsInSchemeChange;
private JLabel myPrimaryLabel;
private JLabel mySizeLabel;
public FontOptions(@NotNull ColorAndFontOptions options) {
this(options, null);
}
public FontOptions(@NotNull ColorAndFontOptions options, @Nullable String inheritFontTitle) {
setLayout(new MigLayout("ins 0, gap 5, flowx"));
myOptions = options;
myInheritFontCheckbox = inheritFontTitle != null ? new JCheckBox(inheritFontTitle) : null;
}
@Nullable
protected String getInheritFontTitle() {
return "Use default font preferences";
}
@Override
protected void initControls() {
myInheritFontCheckbox = getInheritFontTitle() != null ? new JCheckBox(getInheritFontTitle()) : null;
if (myInheritFontCheckbox != null) {
add(myInheritFontCheckbox, "newline, sx 2");
myInheritFontCheckbox.setSelected(getFontPreferences() instanceof DelegatingFontPreferences);
myInheritFontCheckbox.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
@@ -92,284 +54,63 @@ public class FontOptions extends JPanel implements OptionsPanel{
});
add(new JSeparator(), "newline, growx, span");
}
add(myOnlyMonospacedCheckBox, "newline 10, sgx b, sx 2");
myPrimaryLabel = new JLabel(ApplicationBundle.message("primary.font"));
add(myPrimaryLabel, "newline, ax right");
add(myPrimaryCombo, "sgx b");
mySizeLabel = new JLabel(ApplicationBundle.message("editbox.font.size"));
add(mySizeLabel, "gapleft 20");
add(myEditorFontSizeField);
add(new JLabel(ApplicationBundle.message("editbox.line.spacing")), "gapleft 20");
add(myLineSpacingField);
add(new JLabel(ApplicationBundle.message("label.fallback.fonts.list.description"),
MessageType.INFO.getDefaultIcon(),
SwingConstants.LEFT), "newline, sx 5");
add(myUseSecondaryFontCheckbox, "newline, ax right");
add(mySecondaryCombo, "sgx b");
JPanel panel = new JPanel(new FlowLayout(FlowLayout.CENTER, 0, 0));
myEnableLigaturesCheckbox.setBorder(null);
panel.add(myEnableLigaturesCheckbox);
JLabel warningIcon = new JLabel(AllIcons.General.BalloonWarning);
IdeTooltipManager.getInstance().setCustomTooltip(
warningIcon,
new TooltipWithClickableLinks.ForBrowser(warningIcon,
ApplicationBundle.message("ligatures.jre.warning",
ApplicationNamesInfo.getInstance().getFullProductName())));
warningIcon.setBorder(JBUI.Borders.emptyLeft(5));
warningIcon.setVisible(!SystemInfo.isJetbrainsJvm);
panel.add(warningIcon);
add(panel, "newline, sx 2");
myOnlyMonospacedCheckBox.setBorder(null);
myUseSecondaryFontCheckbox.setBorder(null);
mySecondaryCombo.setEnabled(false);
myOnlyMonospacedCheckBox.setSelected(EditorColorsManager.getInstance().isUseOnlyMonospacedFonts());
myOnlyMonospacedCheckBox.addActionListener(e -> {
EditorColorsManager.getInstance().setUseOnlyMonospacedFonts(myOnlyMonospacedCheckBox.isSelected());
myPrimaryCombo.setMonospacedOnly(myOnlyMonospacedCheckBox.isSelected());
mySecondaryCombo.setMonospacedOnly(myOnlyMonospacedCheckBox.isSelected());
});
myPrimaryCombo.setMonospacedOnly(myOnlyMonospacedCheckBox.isSelected());
myPrimaryCombo.setRenderer(RENDERER);
mySecondaryCombo.setMonospacedOnly(myOnlyMonospacedCheckBox.isSelected());
mySecondaryCombo.setRenderer(RENDERER);
myUseSecondaryFontCheckbox.addActionListener(e -> {
mySecondaryCombo.setEnabled(myUseSecondaryFontCheckbox.isSelected());
syncFontFamilies();
});
ItemListener itemListener = this::syncFontFamilies;
myPrimaryCombo.addItemListener(itemListener);
mySecondaryCombo.addItemListener(itemListener);
ActionListener actionListener = this::syncFontFamilies;
myPrimaryCombo.addActionListener(actionListener);
mySecondaryCombo.addActionListener(actionListener);
myEditorFontSizeField.getDocument().addDocumentListener(new DocumentAdapter() {
@Override
public void textChanged(DocumentEvent event) {
if (myIsInSchemeChange || !SwingUtilities.isEventDispatchThread()) return;
String selectedFont = myPrimaryCombo.getFontName();
if (selectedFont != null) {
setFontSize(getFontSizeFromField());
}
updateDescription(true);
}
});
myEditorFontSizeField.addKeyListener(new KeyAdapter() {
@Override
public void keyPressed(KeyEvent e) {
if (e.getKeyCode() != KeyEvent.VK_UP && e.getKeyCode() != KeyEvent.VK_DOWN) return;
boolean up = e.getKeyCode() == KeyEvent.VK_UP;
try {
int value = Integer.parseInt(myEditorFontSizeField.getText());
value += (up ? 1 : -1);
value = Math.min(EditorFontsConstants.getMaxEditorFontSize(), Math.max(EditorFontsConstants.getMinEditorFontSize(), value));
myEditorFontSizeField.setText(String.valueOf(value));
}
catch (NumberFormatException ignored) {
}
}
});
myLineSpacingField.getDocument().addDocumentListener(new DocumentAdapter() {
@Override
public void textChanged(DocumentEvent event) {
if (myIsInSchemeChange) return;
float lineSpacing = getLineSpacingFromField();
if (getLineSpacing() != lineSpacing) {
setCurrentLineSpacing(lineSpacing);
}
updateDescription(true);
}
});
myLineSpacingField.addKeyListener(new KeyAdapter() {
@Override
public void keyPressed(KeyEvent e) {
if (e.getKeyCode() != KeyEvent.VK_UP && e.getKeyCode() != KeyEvent.VK_DOWN) return;
boolean up = e.getKeyCode() == KeyEvent.VK_UP;
try {
float value = Float.parseFloat(myLineSpacingField.getText());
value += (up ? 1 : -1) * .1F;
value = Math.min(EditorFontsConstants.getMaxEditorLineSpacing(), Math.max(EditorFontsConstants.getMinEditorLineSpacing(), value));
myLineSpacingField.setText(String.format(Locale.ENGLISH, "%.1f", value));
}
catch (NumberFormatException ignored) {
}
}
});
myEnableLigaturesCheckbox.addActionListener(e -> {
FontPreferences preferences = getFontPreferences();
if (preferences instanceof ModifiableFontPreferences) {
((ModifiableFontPreferences)preferences).setUseLigatures(myEnableLigaturesCheckbox.isSelected());
updateDescription(true);
}
});
super.initControls();
}
protected void setDelegatingPreferences(boolean isDelegating) {
}
private int getFontSizeFromField() {
try {
return Math.min(EditorFontsConstants.getMaxEditorFontSize(),
Math.max(EditorFontsConstants.getMinEditorFontSize(), Integer.parseInt(myEditorFontSizeField.getText())));
FontPreferences currPrefs = getCurrentScheme().getFontPreferences();
if (currPrefs instanceof DelegatingFontPreferences == isDelegating) return;
if (isDelegating) {
getCurrentScheme().setUseAppFontPreferencesInEditor();
}
catch (NumberFormatException e) {
return EditorFontsConstants.getDefaultEditorFontSize();
}
}
private float getLineSpacingFromField() {
try {
return Math.min(EditorFontsConstants.getMaxEditorLineSpacing(), Math.max(EditorFontsConstants.getMinEditorLineSpacing(), Float.parseFloat(myLineSpacingField.getText())));
} catch (NumberFormatException e){
return EditorFontsConstants.getDefaultEditorLineSpacing();
}
}
/**
* Processes an event from {@code FontComboBox}
* if it is enabled and its item is selected.
*
* @param event the event to process
*/
private void syncFontFamilies(AWTEvent event) {
Object source = event.getSource();
if (source instanceof FontComboBox) {
FontComboBox combo = (FontComboBox)source;
if (combo.isEnabled() && combo.isShowing() && combo.getSelectedItem() != null) {
syncFontFamilies();
}
}
}
private void syncFontFamilies() {
if (myIsInSchemeChange) {
return;
}
FontPreferences fontPreferences = getFontPreferences();
if (fontPreferences instanceof ModifiableFontPreferences) {
ModifiableFontPreferences modifiableFontPreferences = (ModifiableFontPreferences)fontPreferences;
modifiableFontPreferences.clearFonts();
String primaryFontFamily = myPrimaryCombo.getFontName();
String secondaryFontFamily = mySecondaryCombo.isEnabled() ? mySecondaryCombo.getFontName() : null;
int fontSize = getFontSizeFromField();
if (primaryFontFamily != null) {
if (!FontPreferences.DEFAULT_FONT_NAME.equals(primaryFontFamily)) {
modifiableFontPreferences.addFontFamily(primaryFontFamily);
}
modifiableFontPreferences.register(primaryFontFamily, fontSize);
}
if (secondaryFontFamily != null) {
if (!FontPreferences.DEFAULT_FONT_NAME.equals(secondaryFontFamily)) {
modifiableFontPreferences.addFontFamily(secondaryFontFamily);
}
modifiableFontPreferences.register(secondaryFontFamily, fontSize);
}
updateDescription(true);
else {
getCurrentScheme().setFontPreferences(getFontPreferences());
}
updateOptionsList();
updateDescription(true);
}
@Override
public void updateOptionsList() {
myIsInSchemeChange = true;
protected boolean isReadOnly() {
return ColorAndFontOptions.isReadOnly(myOptions.getSelectedScheme());
}
myLineSpacingField.setText(Float.toString(getLineSpacing()));
FontPreferences fontPreferences = getFontPreferences();
List<String> fontFamilies = fontPreferences.getEffectiveFontFamilies();
myPrimaryCombo.setFontName(fontPreferences.getFontFamily());
boolean isThereSecondaryFont = fontFamilies.size() > 1;
myUseSecondaryFontCheckbox.setSelected(isThereSecondaryFont);
mySecondaryCombo.setFontName(isThereSecondaryFont ? fontFamilies.get(1) : null);
myEditorFontSizeField.setText(String.valueOf(fontPreferences.getSize(fontPreferences.getFontFamily())));
boolean isReadOnlyColorScheme = ColorAndFontOptions.isReadOnly(myOptions.getSelectedScheme());
if (myInheritFontCheckbox != null) {
myInheritFontCheckbox.setEnabled(!isReadOnlyColorScheme);
myInheritFontCheckbox.setSelected(myOptions.getSelectedScheme().getConsoleFontPreferences() instanceof DelegatingFontPreferences);
}
boolean readOnly = isReadOnlyColorScheme || !(getFontPreferences() instanceof ModifiableFontPreferences);
myPrimaryCombo.setEnabled(!readOnly);
myPrimaryLabel.setEnabled(!readOnly);
mySecondaryCombo.setEnabled(isThereSecondaryFont && !readOnly);
myOnlyMonospacedCheckBox.setEnabled(!readOnly);
myLineSpacingField.setEnabled(!readOnly);
myEditorFontSizeField.setEnabled(!readOnly);
mySizeLabel.setEnabled(!readOnly);
myUseSecondaryFontCheckbox.setEnabled(!readOnly);
myEnableLigaturesCheckbox.setEnabled(!readOnly && SystemInfo.isJetbrainsJvm);
myEnableLigaturesCheckbox.setSelected(fontPreferences.useLigatures());
myIsInSchemeChange = false;
@Override
protected boolean isDelegating() {
return getFontPreferences() instanceof DelegatingFontPreferences;
}
@NotNull
@Override
protected FontPreferences getFontPreferences() {
return getCurrentScheme().getFontPreferences();
}
@Override
protected void setFontSize(int fontSize) {
getCurrentScheme().setEditorFontSize(fontSize);
}
@Override
protected float getLineSpacing() {
return getCurrentScheme().getLineSpacing();
}
@Override
protected void setCurrentLineSpacing(float lineSpacing) {
getCurrentScheme().setLineSpacing(lineSpacing);
}
@Override
@Nullable
public Runnable showOption(final String option) {
return null;
}
@Override
public void applyChangesToScheme() {
}
@Override
public void selectOption(final String typeToSelect) {
}
protected EditorColorsScheme getCurrentScheme() {
return myOptions.getSelectedScheme();
}
public boolean updateDescription(boolean modified) {
EditorColorsScheme scheme = myOptions.getSelectedScheme();
if (modified && ColorAndFontOptions.isReadOnly(scheme)) {
return false;
@Override
protected void updateCustomOptions() {
if (myInheritFontCheckbox != null) {
myInheritFontCheckbox.setEnabled(!isReadOnly());
myInheritFontCheckbox.setSelected(isDelegating());
}
myDispatcher.getMulticaster().fontChanged();
return true;
}
@Override
public void addListener(ColorAndFontSettingsListener listener) {
myDispatcher.addListener(listener);
}
@Override
public JPanel getPanel() {
return this;
}
@Override
public Set<String> processListOptions() {
return new HashSet<>();
}
}
@@ -80,7 +80,7 @@ public class SimpleEditorPreview implements PreviewPanel {
myHighlightsExtractor = new HighlightsExtractor(page.getAdditionalHighlightingTagToDescriptorMap(), INLINE_ELEMENTS);
myEditor = (EditorEx)FontEditorPreview.createPreviewEditor(
myHighlightsExtractor.extractHighlights(page.getDemoText(), myHighlightData), // text without tags
10, 3, -1, myOptions, false);
10, 3, -1, myOptions.getSelectedScheme(), false);
FontEditorPreview.installTrafficLights(myEditor);
myBlinkingAlarm = new Alarm().setActivationComponent(myEditor.getComponent());
@@ -0,0 +1,84 @@
/*
* Copyright 2000-2017 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.editor.fonts;
import com.intellij.application.options.editor.EditorOptionsPanel;
import com.intellij.openapi.editor.colors.EditorColorsManager;
import com.intellij.openapi.editor.colors.EditorFontCache;
import com.intellij.openapi.editor.colors.FontPreferences;
import com.intellij.openapi.editor.colors.impl.AppEditorFontOptions;
import com.intellij.openapi.editor.colors.impl.EditorColorsManagerImpl;
import com.intellij.openapi.options.ConfigurationException;
import com.intellij.openapi.options.SearchableConfigurable;
import org.jetbrains.annotations.Nls;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import javax.swing.*;
public class AppEditorFontConfigurable implements SearchableConfigurable {
private AppEditorFontPanel myFontPanel;
@NotNull
@Override
public String getId() {
return "editor.preferences.fonts.default";
}
@Nullable
@Override
public JComponent createComponent() {
myFontPanel = new AppEditorFontPanel();
return myFontPanel;
}
@Override
public boolean isModified() {
return !getStoredPreferences().equals(getUIFontPreferences());
}
@Override
public void apply() throws ConfigurationException {
FontPreferences fontPreferences = getUIFontPreferences();
fontPreferences.copyTo(getStoredPreferences());
EditorFontCache.getInstance().reset();
((EditorColorsManagerImpl)EditorColorsManager.getInstance()).schemeChangedOrSwitched(null);
EditorOptionsPanel.reinitAllEditors();
}
@NotNull
private FontPreferences getUIFontPreferences() {
return myFontPanel.getOptionsPanel().getFontPreferences();
}
@Override
public void reset() {
getStoredPreferences().copyTo(getUIFontPreferences());
myFontPanel.getOptionsPanel().updateOptionsList();
}
@NotNull
private static FontPreferences getStoredPreferences() {
return AppEditorFontOptions.getInstance().getFontPreferences();
}
@Nls
@Override
public String getDisplayName() {
return "Default Font";
}
}
@@ -0,0 +1,61 @@
/*
* Copyright 2000-2017 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.editor.fonts;
import com.intellij.application.options.colors.AbstractFontOptionsPanel;
import com.intellij.openapi.editor.colors.EditorColorsScheme;
import com.intellij.openapi.editor.colors.FontPreferences;
import org.jetbrains.annotations.NotNull;
public class AppEditorFontOptionsPanel extends AbstractFontOptionsPanel {
private final EditorColorsScheme myScheme;
protected AppEditorFontOptionsPanel(EditorColorsScheme scheme) {
myScheme = scheme;
updateOptionsList();
}
@Override
protected boolean isReadOnly() {
return false;
}
@Override
protected boolean isDelegating() {
return false;
}
@NotNull
@Override
protected FontPreferences getFontPreferences() {
return myScheme.getFontPreferences();
}
@Override
protected void setFontSize(int fontSize) {
myScheme.setEditorFontSize(fontSize);
}
@Override
protected float getLineSpacing() {
return getFontPreferences().getLineSpacing();
}
@Override
protected void setCurrentLineSpacing(float lineSpacing) {
getFontPreferences().setLineSpacing(lineSpacing);
}
}
@@ -0,0 +1,59 @@
/*
* Copyright 2000-2017 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.editor.fonts;
import com.intellij.application.options.colors.ColorAndFontSettingsListener;
import com.intellij.application.options.colors.FontEditorPreview;
import com.intellij.openapi.editor.colors.EditorColorsManager;
import com.intellij.openapi.editor.colors.EditorColorsScheme;
import com.intellij.openapi.editor.colors.impl.FontPreferencesImpl;
import javax.swing.*;
import java.awt.*;
public class AppEditorFontPanel extends JPanel {
private final AppEditorFontOptionsPanel myOptionsPanel;
private final FontEditorPreview myPreview;
private final EditorColorsScheme myPreviewScheme;
public AppEditorFontPanel() {
super(new BorderLayout(0,10));
myPreviewScheme = createPreviewScheme();
myOptionsPanel = new AppEditorFontOptionsPanel(myPreviewScheme);
add(myOptionsPanel, BorderLayout.NORTH);
myPreview = new FontEditorPreview(()-> myPreviewScheme, true);
add(myPreview.getPanel(), BorderLayout.CENTER);
myOptionsPanel.addListener(
new ColorAndFontSettingsListener.Abstract() {
@Override
public void fontChanged() {
myPreview.updateView();
}
}
);
}
private static EditorColorsScheme createPreviewScheme() {
EditorColorsScheme scheme = (EditorColorsScheme)EditorColorsManager.getInstance().getSchemeForCurrentUITheme().clone();
scheme.setFontPreferences(new FontPreferencesImpl());
return scheme;
}
public AppEditorFontOptionsPanel getOptionsPanel() {
return myOptionsPanel;
}
}
@@ -326,6 +326,14 @@
serviceImplementation="com.intellij.openapi.actionSystem.impl.AbbreviationManagerImpl"/>
<applicationService serviceImplementation="com.intellij.openapi.editor.ex.EditorSettingsExternalizable"/>
<applicationService serviceImplementation="com.intellij.openapi.editor.colors.impl.AppEditorFontOptions"/>
<applicationConfigurable
parentId="preferences.editor"
displayName="Default Font"
instance="com.intellij.application.options.editor.fonts.AppEditorFontConfigurable"/>
<applicationService serviceInterface="com.intellij.openapi.editor.colors.EditorFontCache"
serviceImplementation="com.intellij.openapi.editor.colors.impl.EditorFontCacheImpl"/>
<applicationService serviceImplementation="com.intellij.codeInsight.hints.settings.ParameterNameHintsSettings"/>
<applicationService serviceImplementation="com.intellij.openapi.keymap.KeyboardSettingsExternalizable"/>
<applicationService serviceImplementation="com.intellij.openapi.editor.SpellCheckingEditorCustomizationProvider"/>