IDEA-63980 Make idea.cycle.buffer.size configurable in IDEA GUI / IDEA settings
[idea/community.git] / platform / editor-ui-api / src / com / intellij / ide / ui / UISettings.java
1 /*
2  * Copyright 2000-2015 JetBrains s.r.o.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 package com.intellij.ide.ui;
17
18 import com.intellij.ide.WelcomeWizardUtil;
19 import com.intellij.openapi.Disposable;
20 import com.intellij.openapi.application.Application;
21 import com.intellij.openapi.application.ApplicationManager;
22 import com.intellij.openapi.components.*;
23 import com.intellij.openapi.util.Pair;
24 import com.intellij.openapi.util.SimpleModificationTracker;
25 import com.intellij.openapi.util.SystemInfo;
26 import com.intellij.util.EventDispatcher;
27 import com.intellij.util.PlatformUtils;
28 import com.intellij.util.SystemProperties;
29 import com.intellij.util.ui.UIUtil;
30 import com.intellij.util.xmlb.Accessor;
31 import com.intellij.util.xmlb.SerializationFilter;
32 import com.intellij.util.xmlb.XmlSerializerUtil;
33 import com.intellij.util.xmlb.annotations.Property;
34 import com.intellij.util.xmlb.annotations.Transient;
35 import org.jetbrains.annotations.NonNls;
36 import org.jetbrains.annotations.NotNull;
37
38 import javax.swing.*;
39 import java.awt.*;
40 import java.util.Map;
41
42 import static com.intellij.util.ui.UIUtil.isValidFont;
43
44 @State(
45   name = "UISettings",
46   storages = @Storage(file = StoragePathMacros.APP_CONFIG + "/ui.lnf.xml")
47 )
48 public class UISettings extends SimpleModificationTracker implements PersistentStateComponent<UISettings> {
49   /** Not tabbed pane. */
50   public static final int TABS_NONE = 0;
51
52   public static UISettings getInstance() {
53     return ServiceManager.getService(UISettings.class);
54   }
55
56   /**
57    * Use this method if you are not sure whether the application is initialized.
58    * @return persisted UISettings instance or default values.
59    */
60   public static UISettings getShadowInstance() {
61     Application application = ApplicationManager.getApplication();
62     UISettings settings = application == null ? null : getInstance();
63     return settings == null ? new UISettings() : settings;
64   }
65
66   @Property(filter = FontFilter.class) public String FONT_FACE;
67   @Property(filter = FontFilter.class) public int FONT_SIZE;
68   public int RECENT_FILES_LIMIT = 50;
69   public int CONSOLE_COMMAND_HISTORY_LIMIT = 300;
70   public boolean OVERRIDE_CONSOLE_CYCLE_BUFFER_SIZE = false;
71   public int CONSOLE_CYCLE_BUFFER_SIZE_KB = 1024;
72   public int EDITOR_TAB_LIMIT = 10;
73   public boolean REUSE_NOT_MODIFIED_TABS = false;
74   public boolean ANIMATE_WINDOWS = true;
75   @Deprecated //todo remove in IDEA 16
76   public int ANIMATION_SPEED = 4000; // Pixels per second
77   public int ANIMATION_DURATION = 300; // Milliseconds
78   public boolean SHOW_TOOL_WINDOW_NUMBERS = true;
79   public boolean HIDE_TOOL_STRIPES = true;
80   public boolean WIDESCREEN_SUPPORT = false;
81   public boolean LEFT_HORIZONTAL_SPLIT = false;
82   public boolean RIGHT_HORIZONTAL_SPLIT = false;
83   public boolean SHOW_EDITOR_TOOLTIP = true;
84   public boolean SHOW_MEMORY_INDICATOR = false;
85   public boolean ALLOW_MERGE_BUTTONS = true;
86   public boolean SHOW_MAIN_TOOLBAR = false;
87   public boolean SHOW_STATUS_BAR = true;
88   public boolean SHOW_NAVIGATION_BAR = true;
89   public boolean ALWAYS_SHOW_WINDOW_BUTTONS = false;
90   public boolean CYCLE_SCROLLING = true;
91   public boolean SCROLL_TAB_LAYOUT_IN_EDITOR = true;
92   public boolean HIDE_TABS_IF_NEED = true;
93   public boolean SHOW_CLOSE_BUTTON = true;
94   public int EDITOR_TAB_PLACEMENT = 1;
95   public boolean HIDE_KNOWN_EXTENSION_IN_TABS = false;
96   public boolean SHOW_ICONS_IN_QUICK_NAVIGATION = true;
97   public boolean CLOSE_NON_MODIFIED_FILES_FIRST = false;
98   public boolean ACTIVATE_MRU_EDITOR_ON_CLOSE = false;
99   public boolean ACTIVATE_RIGHT_EDITOR_ON_CLOSE = false;
100   @Deprecated
101   public boolean ANTIALIASING_IN_EDITOR = true;
102   public boolean ANTIALIASING_IN_IDE = ANTIALIASING_IN_EDITOR;
103   public LCDRenderingScope LCD_RENDERING_SCOPE = UIUtil.isRetina() ? LCDRenderingScope.OFF : LCDRenderingScope.IDE;
104   public boolean USE_LCD_RENDERING_IN_EDITOR = true;
105   public boolean MOVE_MOUSE_ON_DEFAULT_BUTTON = false;
106   public boolean ENABLE_ALPHA_MODE = false;
107   public int ALPHA_MODE_DELAY = 1500;
108   public float ALPHA_MODE_RATIO = 0.5f;
109   public int MAX_CLIPBOARD_CONTENTS = 5;
110   public boolean OVERRIDE_NONIDEA_LAF_FONTS = false;
111   public boolean SHOW_ICONS_IN_MENUS = true;
112   public boolean DISABLE_MNEMONICS = SystemInfo.isMac; // IDEADEV-33409, should be disabled by default on MacOS
113   public boolean DISABLE_MNEMONICS_IN_CONTROLS = false;
114   public boolean USE_SMALL_LABELS_ON_TABS = SystemInfo.isMac;
115   public boolean SORT_LOOKUP_ELEMENTS_LEXICOGRAPHICALLY = false;
116   public int MAX_LOOKUP_WIDTH2 = 500;
117   public int MAX_LOOKUP_LIST_HEIGHT = 11;
118   public boolean HIDE_NAVIGATION_ON_FOCUS_LOSS = true;
119   public boolean DND_WITH_PRESSED_ALT_ONLY = false;
120   public boolean FILE_COLORS_IN_PROJECT_VIEW = false;
121   public boolean DEFAULT_AUTOSCROLL_TO_SOURCE = false;
122   @Transient
123   public boolean PRESENTATION_MODE = false;
124   public int PRESENTATION_MODE_FONT_SIZE = 24;
125   public boolean MARK_MODIFIED_TABS_WITH_ASTERISK = false;
126   public boolean SHOW_TABS_TOOLTIPS = true;
127   public boolean SHOW_DIRECTORY_FOR_NON_UNIQUE_FILENAMES = true;
128   public boolean NAVIGATE_TO_PREVIEW = false;
129   public boolean SORT_BOOKMARKS = false;
130
131   private final EventDispatcher<UISettingsListener> myDispatcher = EventDispatcher.create(UISettingsListener.class);
132
133   public UISettings() {
134     tweakPlatformDefaults();
135     setSystemFontFaceAndSize();
136
137     Boolean scrollToSource = WelcomeWizardUtil.getAutoScrollToSource();
138     if (scrollToSource != null) {
139       DEFAULT_AUTOSCROLL_TO_SOURCE = scrollToSource;
140     }
141   }
142
143   private void tweakPlatformDefaults() {
144     // TODO[anton] consider making all IDEs use the same settings
145     if (PlatformUtils.isAppCode()) {
146       SCROLL_TAB_LAYOUT_IN_EDITOR = true;
147       ACTIVATE_RIGHT_EDITOR_ON_CLOSE = true;
148       SHOW_ICONS_IN_MENUS = false;
149     }
150   }
151
152   /**
153    * @deprecated use {@link UISettings#addUISettingsListener(com.intellij.ide.ui.UISettingsListener, Disposable disposable)} instead.
154    */
155   public void addUISettingsListener(UISettingsListener listener) {
156     myDispatcher.addListener(listener);
157   }
158
159   public void addUISettingsListener(@NotNull final UISettingsListener listener, @NotNull Disposable parentDisposable) {
160     myDispatcher.addListener(listener, parentDisposable);
161   }
162
163   /**
164    * Notifies all registered listeners that UI settings has been changed.
165    */
166   public void fireUISettingsChanged() {
167     incModificationCount();
168     myDispatcher.getMulticaster().uiSettingsChanged(this);
169     ApplicationManager.getApplication().getMessageBus().syncPublisher(UISettingsListener.TOPIC).uiSettingsChanged(this);
170   }
171
172   public void removeUISettingsListener(UISettingsListener listener) {
173     myDispatcher.removeListener(listener);
174   }
175
176   private void setSystemFontFaceAndSize() {
177     if (FONT_FACE == null || FONT_SIZE <= 0) {
178       final Pair<String, Integer> fontData = getSystemFontFaceAndSize();
179       FONT_FACE = fontData.first;
180       FONT_SIZE = fontData.second;
181     }
182   }
183
184   private static Pair<String, Integer> getSystemFontFaceAndSize() {
185     final Pair<String,Integer> fontData = UIUtil.getSystemFontData();
186     if (fontData != null) {
187       return fontData;
188     }
189
190     return Pair.create("Dialog", 12);
191   }
192
193   public static class FontFilter implements SerializationFilter {
194     @Override
195     public boolean accepts(@NotNull Accessor accessor, @NotNull Object bean) {
196       UISettings settings = (UISettings)bean;
197       return !hasDefaultFontSetting(settings);
198     }
199   }
200
201   private static boolean hasDefaultFontSetting(final UISettings settings) {
202     final Pair<String, Integer> fontData = getSystemFontFaceAndSize();
203     return fontData.first.equals(settings.FONT_FACE) && fontData.second.equals(settings.FONT_SIZE);
204   }
205
206   @Override
207   public UISettings getState() {
208     return this;
209   }
210
211   @Override
212   public void loadState(UISettings object) {
213     XmlSerializerUtil.copyBean(object, this);
214
215     // Check tab placement in editor
216     if (EDITOR_TAB_PLACEMENT != TABS_NONE &&
217         EDITOR_TAB_PLACEMENT != SwingConstants.TOP &&
218         EDITOR_TAB_PLACEMENT != SwingConstants.LEFT &&
219         EDITOR_TAB_PLACEMENT != SwingConstants.BOTTOM &&
220         EDITOR_TAB_PLACEMENT != SwingConstants.RIGHT) {
221       EDITOR_TAB_PLACEMENT = SwingConstants.TOP;
222     }
223
224     // Check that alpha delay and ratio are valid
225     if (ALPHA_MODE_DELAY < 0) {
226       ALPHA_MODE_DELAY = 1500;
227     }
228     if (ALPHA_MODE_RATIO < 0.0f || ALPHA_MODE_RATIO > 1.0f) {
229       ALPHA_MODE_RATIO = 0.5f;
230     }
231
232     setSystemFontFaceAndSize();
233     // 1. Sometimes system font cannot display standard ASCII symbols. If so we have
234     // find any other suitable font withing "preferred" fonts first.
235     boolean fontIsValid = isValidFont(new Font(FONT_FACE, Font.PLAIN, FONT_SIZE));
236     if (!fontIsValid) {
237       @NonNls final String[] preferredFonts = {"dialog", "Arial", "Tahoma"};
238       for (String preferredFont : preferredFonts) {
239         if (isValidFont(new Font(preferredFont, Font.PLAIN, FONT_SIZE))) {
240           FONT_FACE = preferredFont;
241           fontIsValid = true;
242           break;
243         }
244       }
245
246       // 2. If all preferred fonts are not valid in current environment
247       // we have to find first valid font (if any)
248       if (!fontIsValid) {
249         String[] fontNames = UIUtil.getValidFontNames(false);
250         if (fontNames.length > 0) {
251           FONT_FACE = fontNames[0];
252         }
253       }
254     }
255
256     if (MAX_CLIPBOARD_CONTENTS <= 0) {
257       MAX_CLIPBOARD_CONTENTS = 5;
258     }
259
260     fireUISettingsChanged();
261   }
262
263   public static final boolean FORCE_USE_FRACTIONAL_METRICS =
264     SystemProperties.getBooleanProperty("idea.force.use.fractional.metrics", false);
265
266   public static void setupFractionalMetrics(final Graphics2D g2d) {
267     if (FORCE_USE_FRACTIONAL_METRICS) {
268       g2d.setRenderingHint(RenderingHints.KEY_FRACTIONALMETRICS, RenderingHints.VALUE_FRACTIONALMETRICS_ON);
269     }
270   }
271
272   /* This method must not be used for set up antialiasing for editor components
273    */
274   public static void setupAntialiasing(final Graphics g) {
275
276     Application application = ApplicationManager.getApplication();
277     if (application == null) {
278       // We cannot use services while Aplication has not been loaded yet
279       // So let's apply the default hints.
280       UIUtil.applyRenderingHints(g);
281       return;
282     }
283
284     Graphics2D g2d = (Graphics2D)g;
285     UISettings uiSettings = getInstance();
286
287     g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
288
289     if (uiSettings != null) {
290       g2d.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING, LCDRenderingScope.getKeyForCurrentScope(false));
291     } else {
292       g2d.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING, RenderingHints.VALUE_TEXT_ANTIALIAS_OFF);
293     }
294
295     setupFractionalMetrics(g2d);
296   }
297
298   /**
299    * @return true when Remote Desktop (i.e. Windows RDP) is connected
300    */
301   // TODO[neuro]: move to UIUtil
302   public static boolean isRemoteDesktopConnected() {
303     if (System.getProperty("os.name").contains("Windows")) {
304       final Map map = (Map)Toolkit.getDefaultToolkit().getDesktopProperty("awt.font.desktophints");
305       return map != null && RenderingHints.VALUE_TEXT_ANTIALIAS_DEFAULT.equals(map.get(RenderingHints.KEY_TEXT_ANTIALIASING));
306     }
307     return false;
308   }
309 }