/*
* Copyright 2003-2016 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 jetbrains.mps.nodeEditor;
import com.intellij.ide.PowerSaveMode;
import com.intellij.ide.ui.UISettings;
import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.components.ApplicationComponent;
import com.intellij.openapi.components.PersistentStateComponent;
import com.intellij.openapi.components.State;
import com.intellij.openapi.components.Storage;
import com.intellij.openapi.editor.EditorFactory;
import com.intellij.openapi.editor.colors.EditorColors;
import com.intellij.openapi.editor.colors.EditorColorsManager;
import com.intellij.openapi.editor.colors.EditorColorsScheme;
import jetbrains.mps.nodeEditor.EditorSettings.MyState;
import jetbrains.mps.nodeEditor.cells.FontRegistry;
import jetbrains.mps.nodeEditor.cells.TextLine;
import org.apache.log4j.LogManager;
import org.apache.log4j.Logger;
import org.jetbrains.annotations.NotNull;
import java.awt.Color;
import java.awt.Font;
import java.util.ArrayList;
import java.util.List;
@State(
name = "MpsEditorSettings",
storages = @Storage("mpsEditor.xml")
)
public class EditorSettings implements ApplicationComponent, PersistentStateComponent<MyState> {
private static final Logger LOG = LogManager.getLogger(EditorSettings.class);
private static final Color DEFAULT_CARET_ROW_COLOR = new Color(255, 255, 215);
private static final Color DEFAULT_CARET_COLOR = Color.BLACK;
private static final Color DEFAULT_LEFT_HIGHLIGHTER_BACKGROUND_COLOR = Color.WHITE;
private static final Color DEFAULT_LEFT_HIGHLIGHTER_TEAR_LINE_COLOR = Color.gray;
private static final Color DEFAULT_SELECTION_BACKGROUND_COLOR = new Color(82, 109, 165);
private static final Color DEFAULT_SELECTION_FOREGROUND_COLOR = Color.WHITE;
private static final Color DEFAULT_HYPERLINK_COLOR = Color.BLUE;
private static final int DEFAULT_CARET_BLINK_PERIOD = 500;
static final int MIN_CARET_BLINK_PERIOD = 100;
static final int MAX_CARET_BLINK_PERIOD = 1000;
private static EditorSettings ourInstance;
public static EditorSettings getInstance() {
if (ourInstance == null) {
ourInstance = ApplicationManager.getApplication() == null ? new EditorSettings() : ApplicationManager.getApplication().getComponent(EditorSettings.class);
}
return ourInstance;
}
private List<EditorSettingsListener> myListeners = new ArrayList<>();
private final EditorColorsManager myColorsManager;
private MyState myState = new MyState();
private boolean myPresentationMode;
private int myPresentationModeFontSize = 24;
private Font myDefaultEditorFont;
private int mySpaceWidth = -1;
public EditorSettings(EditorColorsManager colorsManager, UISettings uiSettings) {
myColorsManager = colorsManager;
myPresentationMode = uiSettings.PRESENTATION_MODE;
myPresentationModeFontSize = uiSettings.PRESENTATION_MODE_FONT_SIZE;
registerUIListener(uiSettings);
}
private EditorSettings() {
myColorsManager = null;
}
private void registerUIListener(UISettings uiSettings) {
uiSettings.addUISettingsListener(source -> {
if (myPresentationMode == source.PRESENTATION_MODE && myPresentationModeFontSize == source.PRESENTATION_MODE_FONT_SIZE) {
return;
}
myPresentationMode = source.PRESENTATION_MODE;
myPresentationModeFontSize = source.PRESENTATION_MODE_FONT_SIZE;
updateCachedValue();
fireEditorSettingsChanged();
}, ApplicationManager.getApplication());
}
public double getLineSpacing() {
return myState.lineSpacing;
}
public void setLineSpacing(double lineSpacing) {
myState.lineSpacing = lineSpacing;
}
public Font getDefaultEditorFont() {
if (myDefaultEditorFont == null) {
myDefaultEditorFont = FontRegistry.getInstance().getFont(myState.fontFamily, 0, getFontSize());
}
return myDefaultEditorFont;
}
public void setDefaultEditorFont(Font newFont) {
myState.fontFamily = newFont.getFamily();
myState.fontSize = newFont.getSize();
}
public int getFontSize() {
return myPresentationMode ? myPresentationModeFontSize : myState.fontSize;
}
public int getSpecifiedFontSize() {
return myState.fontSize;
}
public String getFontFamily() {
return myState.fontFamily;
}
public boolean useBraces() {
return myState.useBraces;
}
public void setUseBraces(boolean newUseBraces) {
myState.useBraces = newUseBraces;
}
public int getIndentSize() {
return myState.indentSize;
}
public void setIndentSize(int indentSize) {
myState.indentSize = indentSize;
}
public int getVerticalBound() {
return myState.verticalBound;
}
public void setVerticalBound(int verticalBound) {
myState.verticalBound = verticalBound;
}
public int getVerticalBoundWidth() {
return getSpacesWidth(getVerticalBound());
}
public boolean isUseAntialiasing() {
return myState.useAntialiasing;
}
public void setUseAntialiasing(boolean useAntialiasing) {
myState.useAntialiasing = useAntialiasing;
}
public boolean isPowerSaveMode() {
return PowerSaveMode.isEnabled();
}
public void setPowerSaveMode(boolean powerSaveMode) {
//TODO: add PowerSaveModeNotifier.notifyOnPowerSaveMode(e.getData(CommonDataKeys.PROJECT));
PowerSaveMode.setEnabled(powerSaveMode);
}
public boolean isAutoQuickFix() {
return myState.autoQuickFix;
}
public void setAutoQuickFix(boolean autoQuickFix) {
myState.autoQuickFix = autoQuickFix;
}
/**
* @return <code>true</code> when each (potential) use of an edited node get own tab, <code>false</code> means aspect has own tab
*/
public boolean isShowPlain() {
return myState.showPlain;
}
public void setShowPlain(boolean showPlain) {
myState.showPlain = showPlain;
}
public boolean isShowGrayed() {
return myState.showGrayed;
}
public void setShowGrayed(boolean showGrayed) {
myState.showGrayed = showGrayed;
}
/**
* @return <code>true</code> to indicate use of tabs with aspects inside node editor
*/
public boolean isShow() {
return myState.show;
}
public void setShow(boolean show) {
myState.show = show;
}
public boolean isShowContextAssistant() {
return myState.showContextAssistant;
}
public void setShowContextAssistant(boolean showContextAssistant) {
myState.showContextAssistant = showContextAssistant;
}
public int getCaretBlinkPeriod() {
return myState.caretBlinkPeriod;
}
public void setCaretBlinkPeriod(int rate) {
myState.caretBlinkPeriod = rate;
}
public Color getRangeSelectionForegroundColor() {
return EditorColorsManager.getInstance().getGlobalScheme().getColor(EditorColors.SELECTION_FOREGROUND_COLOR);
}
public Color getCaretRowColor() {
return myColorsManager == null ? DEFAULT_CARET_ROW_COLOR : myColorsManager.getGlobalScheme().getColor(EditorColors.CARET_ROW_COLOR);
}
public Color getLeftHighlighterBackgroundColor() {
return myColorsManager == null ? DEFAULT_LEFT_HIGHLIGHTER_BACKGROUND_COLOR : myColorsManager.getGlobalScheme().getColor(EditorColors.GUTTER_BACKGROUND);
}
public Color getLeftHighlighterTearLineColor() {
return myColorsManager == null ? DEFAULT_LEFT_HIGHLIGHTER_TEAR_LINE_COLOR : myColorsManager.getGlobalScheme().getColor(EditorColors.TEARLINE_COLOR);
}
public Color getSelectionBackgroundColor() {
return myColorsManager == null ? DEFAULT_SELECTION_BACKGROUND_COLOR : myColorsManager.getGlobalScheme().getColor(EditorColors.SELECTION_BACKGROUND_COLOR);
}
public Color getSelectionForegroundColor() {
return myColorsManager == null ? DEFAULT_SELECTION_FOREGROUND_COLOR : myColorsManager.getGlobalScheme().getColor(EditorColors.SELECTION_FOREGROUND_COLOR);
}
public Color getHyperlinkColor() {
return myColorsManager == null ? DEFAULT_HYPERLINK_COLOR : myColorsManager.getGlobalScheme().getAttributes(
EditorColors.REFERENCE_HYPERLINK_COLOR).getForegroundColor();
}
public Color getCaretColor() {
return myColorsManager == null ? DEFAULT_CARET_COLOR : myColorsManager.getGlobalScheme().getColor(EditorColors.CARET_COLOR);
}
public int getSpacesWidth(int size) {
if (mySpaceWidth == -1) {
TextLine textLine = new TextLine(" ");
textLine.relayout();
mySpaceWidth = textLine.getWidth();
}
return mySpaceWidth * size;
}
public void addEditorSettingsListener(EditorSettingsListener l) {
myListeners.add(l);
}
public void removeEditorSettingsListener(EditorSettingsListener l) {
myListeners.remove(l);
}
/*package private*/ void fireEditorSettingsChanged() {
for (EditorSettingsListener l : new ArrayList<>(myListeners)) {
try {
l.settingsChanged();
} catch (Throwable t) {
LOG.error(null, t);
}
}
}
@Override
@NotNull
public MyState getState() {
return myState;
}
@Override
public void loadState(MyState state) {
myState = state;
updateCachedValue();
updateGlobalScheme();
}
void updateGlobalScheme() {
if (myColorsManager != null) {
EditorColorsScheme globalScheme = myColorsManager.getGlobalScheme();
globalScheme.setEditorFontSize(getFontSize());
globalScheme.setEditorFontName(getFontFamily());
globalScheme.setLineSpacing(((float) getLineSpacing()));
EditorFactory.getInstance().refreshAllEditors();
}
}
void updateCachedValue() {
myDefaultEditorFont = null;
mySpaceWidth = -1;
}
@Override
public void initComponent() {
}
@Override
public void disposeComponent() {
}
@NotNull
@Override
public String getComponentName() {
return "EditorSettings";
}
@SuppressWarnings("WeakerAccess")
public static class MyState {
public String fontFamily = "Monospaced";
public int fontSize = 13;
public double lineSpacing = 1.0;
public int textWidth = 500;
public boolean useAntialiasing = true;
public boolean useBraces = true;
public int indentSize = 2;
public int verticalBound = 120;
public boolean autoQuickFix = false;
public boolean showPlain = true;
public boolean showGrayed = true;
public boolean show = true;
public boolean showContextAssistant = true;
public int caretBlinkPeriod = DEFAULT_CARET_BLINK_PERIOD;
@Override
public boolean equals(Object o) {
if (this == o) {
return true;
}
if (o == null || getClass() != o.getClass()) {
return false;
}
MyState myState = (MyState) o;
if (fontSize != myState.fontSize) {
return false;
}
if (Double.compare(myState.lineSpacing, lineSpacing) != 0) {
return false;
}
if (textWidth != myState.textWidth) {
return false;
}
if (useAntialiasing != myState.useAntialiasing) {
return false;
}
if (useBraces != myState.useBraces) {
return false;
}
if (indentSize != myState.indentSize) {
return false;
}
if (verticalBound != myState.verticalBound) {
return false;
}
if (autoQuickFix != myState.autoQuickFix) {
return false;
}
if (showPlain != myState.showPlain) {
return false;
}
if (showGrayed != myState.showGrayed) {
return false;
}
if (show != myState.show) {
return false;
}
if (showContextAssistant != myState.showContextAssistant) {
return false;
}
if (caretBlinkPeriod != myState.caretBlinkPeriod) {
return false;
}
return fontFamily != null ? fontFamily.equals(myState.fontFamily) : myState.fontFamily == null;
}
@Override
public int hashCode() {
int result;
long temp;
result = fontFamily != null ? fontFamily.hashCode() : 0;
result = 31 * result + fontSize;
temp = Double.doubleToLongBits(lineSpacing);
result = 31 * result + (int) (temp ^ (temp >>> 32));
result = 31 * result + textWidth;
result = 31 * result + (useAntialiasing ? 1 : 0);
result = 31 * result + (useBraces ? 1 : 0);
result = 31 * result + indentSize;
result = 31 * result + verticalBound;
result = 31 * result + (autoQuickFix ? 1 : 0);
result = 31 * result + (showPlain ? 1 : 0);
result = 31 * result + (showGrayed ? 1 : 0);
result = 31 * result + (show ? 1 : 0);
result = 31 * result + (showContextAssistant ? 1 : 0);
result = 31 * result + caretBlinkPeriod;
return result;
}
}
}