/* * 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; } } }