/*
* Copyright 2000-2014 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.intellij.ide.ui;
import com.intellij.ide.IdeBundle;
import com.intellij.openapi.Disposable;
import com.intellij.openapi.application.Application;
import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.application.PathManager;
import com.intellij.openapi.components.*;
import com.intellij.openapi.util.Pair;
import com.intellij.openapi.util.SimpleModificationTracker;
import com.intellij.openapi.util.SystemInfo;
import com.intellij.util.ComponentTreeEventDispatcher;
import com.intellij.util.SystemProperties;
import com.intellij.util.ui.UIUtil;
import com.intellij.util.xmlb.Accessor;
import com.intellij.util.xmlb.SerializationFilter;
import com.intellij.util.xmlb.XmlSerializerUtil;
import com.intellij.util.xmlb.annotations.Property;
import com.intellij.util.xmlb.annotations.Transient;
import consulo.annotations.DeprecationInfo;
import consulo.util.ui.AntialiasingUtil;
import org.jetbrains.annotations.NonNls;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import javax.swing.*;
import java.awt.*;
import java.io.File;
import java.util.Map;
import static com.intellij.util.ui.UIUtil.isValidFont;
@State(name = "UISettings", storages = {@Storage(file = StoragePathMacros.APP_CONFIG + "/ui.lnf.xml")})
public class UISettings extends SimpleModificationTracker implements PersistentStateComponent<UISettings>, ExportableApplicationComponent {
/**
* Not tabbed pane.
*/
public static final int TABS_NONE = 0;
public static final int ANIMATION_DURATION = 300; // Milliseconds
public static UISettings getInstance() {
return ApplicationManager.getApplication().getComponent(UISettings.class);
}
/**
* Use this method if you are not sure whether the application is initialized.
*
* @return persisted UISettings instance or default values.
*/
public static UISettings getShadowInstance() {
Application application = ApplicationManager.getApplication();
UISettings settings = application == null ? null : application.getComponent(UISettings.class);
return settings == null ? new UISettings() : settings;
}
@Nullable
public static UISettings getInstanceOrNull() {
Application application = ApplicationManager.getApplication();
UISettings settings = application == null ? null : application.getComponent(UISettings.class);
return settings == null ? null : settings;
}
@Property(filter = FontFilter.class)
public String FONT_FACE;
@Property(filter = FontFilter.class)
public int FONT_SIZE;
public int RECENT_FILES_LIMIT = 50;
public int CONSOLE_COMMAND_HISTORY_LIMIT = 300;
public boolean OVERRIDE_CONSOLE_CYCLE_BUFFER_SIZE = false;
public int CONSOLE_CYCLE_BUFFER_SIZE_KB = 1024;
public int EDITOR_TAB_LIMIT = 10;
public boolean REUSE_NOT_MODIFIED_TABS = false;
public boolean ANIMATE_WINDOWS = true;
public boolean SHOW_TOOL_WINDOW_NUMBERS = true;
public boolean HIDE_TOOL_STRIPES = true;
public boolean WIDESCREEN_SUPPORT = false;
public boolean LEFT_HORIZONTAL_SPLIT = false;
public boolean RIGHT_HORIZONTAL_SPLIT = false;
public boolean SHOW_EDITOR_TOOLTIP = true;
public boolean SHOW_MEMORY_INDICATOR = false;
public boolean ALLOW_MERGE_BUTTONS = true;
public boolean SHOW_MAIN_TOOLBAR = false;
public boolean SHOW_STATUS_BAR = true;
public boolean SHOW_NAVIGATION_BAR = true;
public boolean ALWAYS_SHOW_WINDOW_BUTTONS = false;
public boolean CYCLE_SCROLLING = true;
public boolean SCROLL_TAB_LAYOUT_IN_EDITOR = true;
public boolean HIDE_TABS_IF_NEED = true;
public boolean SHOW_CLOSE_BUTTON = true;
public int EDITOR_TAB_PLACEMENT = 1;
public boolean HIDE_KNOWN_EXTENSION_IN_TABS = false;
public boolean SHOW_ICONS_IN_QUICK_NAVIGATION = true;
public boolean CLOSE_NON_MODIFIED_FILES_FIRST = false;
public boolean ACTIVATE_MRU_EDITOR_ON_CLOSE = false;
public boolean ACTIVATE_RIGHT_EDITOR_ON_CLOSE = false;
public AntialiasingType IDE_AA_TYPE = AntialiasingType.SUBPIXEL;
public AntialiasingType EDITOR_AA_TYPE = AntialiasingType.SUBPIXEL;
public ColorBlindness COLOR_BLINDNESS;
public boolean MOVE_MOUSE_ON_DEFAULT_BUTTON = false;
public boolean ENABLE_ALPHA_MODE = false;
public int ALPHA_MODE_DELAY = 1500;
public float ALPHA_MODE_RATIO = 0.5f;
public int MAX_CLIPBOARD_CONTENTS = 5;
public boolean OVERRIDE_NONIDEA_LAF_FONTS = false;
public boolean SHOW_ICONS_IN_MENUS = true;
public boolean DISABLE_MNEMONICS = SystemInfo.isMac; // IDEADEV-33409, should be disabled by default on MacOS
public boolean DISABLE_MNEMONICS_IN_CONTROLS = false;
public boolean USE_SMALL_LABELS_ON_TABS = SystemInfo.isMac;
public boolean SORT_LOOKUP_ELEMENTS_LEXICOGRAPHICALLY = false;
public int MAX_LOOKUP_WIDTH2 = 500;
public int MAX_LOOKUP_LIST_HEIGHT = 11;
public boolean HIDE_NAVIGATION_ON_FOCUS_LOSS = true;
public boolean DND_WITH_PRESSED_ALT_ONLY = false;
public boolean FILE_COLORS_IN_PROJECT_VIEW = false;
public boolean DEFAULT_AUTOSCROLL_TO_SOURCE = false;
@Transient
public boolean PRESENTATION_MODE = false;
public int PRESENTATION_MODE_FONT_SIZE = 24;
public boolean MARK_MODIFIED_TABS_WITH_ASTERISK = false;
public boolean SHOW_TABS_TOOLTIPS = true;
public boolean SHOW_DIRECTORY_FOR_NON_UNIQUE_FILENAMES = true;
public boolean NAVIGATE_TO_PREVIEW = false;
public boolean SMOOTH_SCROLLING = SystemInfo.isMac && (SystemInfo.isJetbrainsJvm || SystemInfo.isJavaVersionAtLeast("9"));
private final ComponentTreeEventDispatcher<UISettingsListener> myDispatcher = ComponentTreeEventDispatcher.create(UISettingsListener.class);
public UISettings() {
setSystemFontFaceAndSize();
}
@Deprecated
@DeprecationInfo("Use UISettingsListener#TOPIC")
public void addUISettingsListener(UISettingsListener listener) {
ApplicationManager.getApplication().getMessageBus().connect().subscribe(UISettingsListener.TOPIC, listener);
}
@Deprecated
@DeprecationInfo("Use UISettingsListener#TOPIC")
public void addUISettingsListener(@NotNull final UISettingsListener listener, @NotNull Disposable parentDisposable) {
ApplicationManager.getApplication().getMessageBus().connect(parentDisposable).subscribe(UISettingsListener.TOPIC, listener);
}
/**
* Notifies all registered listeners that UI settings has been changed.
*/
public void fireUISettingsChanged() {
incModificationCount();
myDispatcher.getMulticaster().uiSettingsChanged(this);
ApplicationManager.getApplication().getMessageBus().syncPublisher(UISettingsListener.TOPIC).uiSettingsChanged(this);
}
private void setSystemFontFaceAndSize() {
if (FONT_FACE == null || FONT_SIZE <= 0) {
final Pair<String, Integer> fontData = getSystemFontFaceAndSize();
FONT_FACE = fontData.first;
FONT_SIZE = fontData.second;
}
}
public static Pair<String, Integer> getSystemFontFaceAndSize() {
final Pair<String, Integer> fontData = UIUtil.getSystemFontData();
if (fontData != null) {
return fontData;
}
return Pair.create("Dialog", 12);
}
public static class FontFilter implements SerializationFilter {
@Override
public boolean accepts(@NotNull Accessor accessor, Object bean) {
UISettings settings = (UISettings)bean;
return !hasDefaultFontSetting(settings);
}
}
private static boolean hasDefaultFontSetting(final UISettings settings) {
final Pair<String, Integer> fontData = getSystemFontFaceAndSize();
return fontData.first.equals(settings.FONT_FACE) && fontData.second.equals(settings.FONT_SIZE);
}
@Override
public UISettings getState() {
return this;
}
@Override
public void loadState(UISettings object) {
XmlSerializerUtil.copyBean(object, this);
// Check tab placement in editor
if (EDITOR_TAB_PLACEMENT != TABS_NONE &&
EDITOR_TAB_PLACEMENT != SwingConstants.TOP &&
EDITOR_TAB_PLACEMENT != SwingConstants.LEFT &&
EDITOR_TAB_PLACEMENT != SwingConstants.BOTTOM &&
EDITOR_TAB_PLACEMENT != SwingConstants.RIGHT) {
EDITOR_TAB_PLACEMENT = SwingConstants.TOP;
}
// Check that alpha delay and ratio are valid
if (ALPHA_MODE_DELAY < 0) {
ALPHA_MODE_DELAY = 1500;
}
if (ALPHA_MODE_RATIO < 0.0f || ALPHA_MODE_RATIO > 1.0f) {
ALPHA_MODE_RATIO = 0.5f;
}
setSystemFontFaceAndSize();
// 1. Sometimes system font cannot display standard ASCII symbols. If so we have
// find any other suitable font withing "preferred" fonts first.
boolean fontIsValid = isValidFont(new Font(FONT_FACE, Font.PLAIN, FONT_SIZE));
if (!fontIsValid) {
@NonNls final String[] preferredFonts = {"dialog", "Arial", "Tahoma"};
for (String preferredFont : preferredFonts) {
if (isValidFont(new Font(preferredFont, Font.PLAIN, FONT_SIZE))) {
FONT_FACE = preferredFont;
fontIsValid = true;
break;
}
}
// 2. If all preferred fonts are not valid in current environment
// we have to find first valid font (if any)
if (!fontIsValid) {
String[] fontNames = UIUtil.getValidFontNames(false);
if (fontNames.length > 0) {
FONT_FACE = fontNames[0];
}
}
}
if (MAX_CLIPBOARD_CONTENTS <= 0) {
MAX_CLIPBOARD_CONTENTS = 5;
}
fireUISettingsChanged();
}
public static final boolean FORCE_USE_FRACTIONAL_METRICS = SystemProperties.getBooleanProperty("idea.force.use.fractional.metrics", false);
public static void setupFractionalMetrics(final Graphics2D g2d) {
if (FORCE_USE_FRACTIONAL_METRICS) {
g2d.setRenderingHint(RenderingHints.KEY_FRACTIONALMETRICS, RenderingHints.VALUE_FRACTIONALMETRICS_ON);
}
}
/* This method must not be used for set up antialiasing for editor components
*/
public static void setupAntialiasing(final Graphics g) {
Graphics2D g2d = (Graphics2D)g;
g2d.setRenderingHint(RenderingHints.KEY_TEXT_LCD_CONTRAST, UIUtil.getLcdContrastValue());
Application application = ApplicationManager.getApplication();
if (application == null) {
// We cannot use services while Application has not been loaded yet
// So let's apply the default hints.
UIUtil.applyRenderingHints(g);
return;
}
UISettings uiSettings = getInstance();
if (uiSettings != null) {
g2d.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING, AntialiasingType.getKeyForCurrentScope(false));
}
else {
g2d.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING, RenderingHints.VALUE_TEXT_ANTIALIAS_OFF);
}
setupFractionalMetrics(g2d);
}
/**
* @return true when Remote Desktop (i.e. Windows RDP) is connected
*/
@Deprecated
@DeprecationInfo("Use RemoteDesktopDetector class - it should work in more cases")
public static boolean isRemoteDesktopConnected() {
if (System.getProperty("os.name").contains("Windows")) {
final Map map = (Map)Toolkit.getDefaultToolkit().getDesktopProperty("awt.font.desktophints");
return map != null && RenderingHints.VALUE_TEXT_ANTIALIAS_DEFAULT.equals(map.get(RenderingHints.KEY_TEXT_ANTIALIASING));
}
return false;
}
@NotNull
@Override
public File[] getExportFiles() {
return new File[]{PathManager.getOptionsFile("ui.lnf")};
}
@NotNull
@Override
public String getPresentableName() {
return IdeBundle.message("ui.settings");
}
@NonNls
@NotNull
@Override
public String getComponentName() {
return "UISettings";
}
public int getEditorTabLimit() {
return EDITOR_TAB_LIMIT;
}
public int getEditorTabPlacement() {
return EDITOR_TAB_PLACEMENT;
}
public boolean getShowTabsTooltips() {
return SHOW_TABS_TOOLTIPS;
}
public boolean getHideTabsIfNeed() {
return HIDE_TABS_IF_NEED;
}
public boolean getMarkModifiedTabsWithAsterisk() {
return MARK_MODIFIED_TABS_WITH_ASTERISK;
}
public boolean getActiveMruEditorOnClose() {
return ACTIVATE_MRU_EDITOR_ON_CLOSE;
}
public boolean getActiveRigtEditorOnClose() {
return ACTIVATE_RIGHT_EDITOR_ON_CLOSE;
}
public boolean getCloseNonModifiedFilesFirst() {
return CLOSE_NON_MODIFIED_FILES_FIRST;
}
public boolean getPresentationMode() {
return PRESENTATION_MODE;
}
public boolean getReuseNotModifiedTabs() {
return REUSE_NOT_MODIFIED_TABS;
}
public boolean getScrollTabLayoutInEditor() {
return SCROLL_TAB_LAYOUT_IN_EDITOR;
}
public boolean getHideToolStripes() {
return HIDE_TOOL_STRIPES;
}
public boolean getShowCloseButton() {
return SHOW_CLOSE_BUTTON;
}
public boolean getShowMainToolbar() {
return SHOW_MAIN_TOOLBAR;
}
public void setShowMainToolbar(boolean value) {
SHOW_MAIN_TOOLBAR = value;
}
public boolean getShowMemoryIndicator() {
return SHOW_MEMORY_INDICATOR;
}
public boolean getShowStatusBar() {
return SHOW_STATUS_BAR;
}
public boolean getShowNavigationBar() {
return SHOW_MAIN_TOOLBAR;
}
public int getPresentationModeFontSize() {
return PRESENTATION_MODE_FONT_SIZE;
}
public boolean getSortLookupElementsLexicographically() {
return SORT_LOOKUP_ELEMENTS_LEXICOGRAPHICALLY;
}
public int getMaxLookupListHeight() {
return MAX_LOOKUP_LIST_HEIGHT;
}
public void setHideToolStripes(boolean value) {
HIDE_TOOL_STRIPES = value;
}
public boolean getWideScreenSupport() {
return WIDESCREEN_SUPPORT;
}
public boolean getAnimateWindows() {
return ANIMATE_WINDOWS;
}
public boolean getLeftHorizontalSplit() {
return LEFT_HORIZONTAL_SPLIT;
}
public void setLeftHorizontalSplit(boolean value) {
LEFT_HORIZONTAL_SPLIT = value;
}
public boolean getRightHorizontalSplit() {
return RIGHT_HORIZONTAL_SPLIT;
}
public void setRightHorizontalSplit(boolean value) {
RIGHT_HORIZONTAL_SPLIT = value;
}
/**
* @see #setupComponentAntialiasing(JComponent)
*/
public static void setupComponentAntialiasing(JComponent component) {
AntialiasingUtil.setup(component::putClientProperty, AntialiasingType.getAAHintForSwingComponent());
}
public static void setupEditorAntialiasing(JComponent component) {
AntialiasingUtil.setup(component::putClientProperty, getInstance().EDITOR_AA_TYPE.getTextInfo());
}
}