2 * Copyright 2000-2016 JetBrains s.r.o.
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
8 * http://www.apache.org/licenses/LICENSE-2.0
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.
17 package com.intellij.application.options.colors;
19 import com.intellij.application.options.OptionsContainingConfigurable;
20 import com.intellij.application.options.editor.EditorOptionsProvider;
21 import com.intellij.execution.impl.ConsoleViewUtil;
22 import com.intellij.ide.ui.LafManager;
23 import com.intellij.ide.ui.laf.LafManagerImpl;
24 import com.intellij.ide.ui.laf.darcula.DarculaInstaller;
25 import com.intellij.ide.ui.laf.darcula.DarculaLookAndFeelInfo;
26 import com.intellij.openapi.Disposable;
27 import com.intellij.openapi.application.ApplicationBundle;
28 import com.intellij.openapi.application.ex.ApplicationInfoEx;
29 import com.intellij.openapi.diagnostic.Logger;
30 import com.intellij.openapi.editor.colors.ColorKey;
31 import com.intellij.openapi.editor.colors.EditorColorsManager;
32 import com.intellij.openapi.editor.colors.EditorColorsScheme;
33 import com.intellij.openapi.editor.colors.TextAttributesKey;
34 import com.intellij.openapi.editor.colors.impl.*;
35 import com.intellij.openapi.editor.markup.EffectType;
36 import com.intellij.openapi.editor.markup.TextAttributes;
37 import com.intellij.openapi.extensions.Extensions;
38 import com.intellij.openapi.options.Configurable;
39 import com.intellij.openapi.options.ConfigurationException;
40 import com.intellij.openapi.options.SchemesManager;
41 import com.intellij.openapi.options.SearchableConfigurable;
42 import com.intellij.openapi.options.colors.*;
43 import com.intellij.openapi.project.Project;
44 import com.intellij.openapi.project.ProjectManager;
45 import com.intellij.openapi.ui.Messages;
46 import com.intellij.openapi.util.Comparing;
47 import com.intellij.openapi.util.Disposer;
48 import com.intellij.openapi.util.Pair;
49 import com.intellij.openapi.vcs.FileStatus;
50 import com.intellij.openapi.vcs.FileStatusFactory;
51 import com.intellij.packageDependencies.DependencyValidationManager;
52 import com.intellij.packageDependencies.DependencyValidationManagerImpl;
53 import com.intellij.psi.codeStyle.DisplayPriority;
54 import com.intellij.psi.codeStyle.DisplayPrioritySortable;
55 import com.intellij.psi.search.scope.packageSet.NamedScope;
56 import com.intellij.psi.search.scope.packageSet.NamedScopesHolder;
57 import com.intellij.psi.search.scope.packageSet.PackageSet;
58 import com.intellij.ui.ColorUtil;
59 import com.intellij.util.ArrayUtil;
60 import com.intellij.util.ui.UIUtil;
61 import gnu.trove.THashMap;
62 import gnu.trove.THashSet;
63 import gnu.trove.TObjectHashingStrategy;
64 import org.jetbrains.annotations.Nls;
65 import org.jetbrains.annotations.NonNls;
66 import org.jetbrains.annotations.NotNull;
67 import org.jetbrains.annotations.Nullable;
72 import java.util.List;
74 public class ColorAndFontOptions extends SearchableConfigurable.Parent.Abstract implements EditorOptionsProvider {
75 private static final Logger LOG = Logger.getInstance(ColorAndFontOptions.class);
77 public static final String ID = "reference.settingsdialog.IDE.editor.colors";
79 private Map<String, MyColorScheme> mySchemes;
80 private MyColorScheme mySelectedScheme;
81 public static final String FILE_STATUS_GROUP = ApplicationBundle.message("title.file.status");
82 public static final String SCOPES_GROUP = ApplicationBundle.message("title.scope.based");
84 private boolean mySomeSchemesDeleted = false;
85 private Map<ColorAndFontPanelFactory, InnerSearchableConfigurable> mySubPanelFactories;
87 private SchemesPanel myRootSchemesPanel;
89 private boolean myInitResetCompleted = false;
90 private boolean myInitResetInvoked = false;
92 private boolean myRevertChangesCompleted = false;
94 private boolean myApplyCompleted = false;
95 private boolean myDisposeCompleted = false;
96 private final Disposable myDisposable = Disposer.newDisposable();
99 public boolean isModified() {
100 boolean listModified = isSchemeListModified();
101 boolean schemeModified = isSomeSchemeModified();
103 if (listModified || schemeModified) {
104 myApplyCompleted = false;
110 private boolean isSchemeListModified(){
111 if (mySomeSchemesDeleted) return true;
113 if (!mySelectedScheme.getName().equals(EditorColorsManager.getInstance().getGlobalScheme().getName())) return true;
115 for (MyColorScheme scheme : mySchemes.values()) {
116 if (scheme.isNew()) return true;
122 private boolean isSomeSchemeModified() {
123 for (MyColorScheme scheme : mySchemes.values()) {
124 if (scheme.isModified()) return true;
129 public EditorColorsScheme selectScheme(@NotNull String name) {
130 mySelectedScheme = getScheme(name);
131 return mySelectedScheme;
134 private MyColorScheme getScheme(String name) {
135 return mySchemes.get(name);
139 public String getUniqueName(@NotNull String preferredName) {
141 if (mySchemes.containsKey(preferredName)) {
142 for (int i = 1; ; i++) {
143 name = preferredName + " (" + i + ")";
144 if (!mySchemes.containsKey(name)) {
150 name = preferredName;
155 public EditorColorsScheme getSelectedScheme() {
156 return mySelectedScheme;
159 public EditorSchemeAttributeDescriptor[] getCurrentDescriptions() {
160 return mySelectedScheme.getDescriptors();
163 public static boolean isReadOnly(@NotNull final EditorColorsScheme scheme) {
164 return ((MyColorScheme)scheme).isReadOnly();
168 public String[] getSchemeNames() {
169 List<MyColorScheme> schemes = new ArrayList<MyColorScheme>(mySchemes.values());
170 Collections.sort(schemes, (o1, o2) -> {
171 if (isReadOnly(o1) && !isReadOnly(o2)) return -1;
172 if (!isReadOnly(o1) && isReadOnly(o2)) return 1;
174 return o1.getName().compareToIgnoreCase(o2.getName());
177 List<String> names = new ArrayList<String>(schemes.size());
178 for (MyColorScheme scheme : schemes) {
179 names.add(scheme.getName());
182 return ArrayUtil.toStringArray(names);
186 public Collection<EditorColorsScheme> getSchemes() {
187 return new ArrayList<EditorColorsScheme>(mySchemes.values());
190 public void saveSchemeAs(String name) {
191 MyColorScheme scheme = mySelectedScheme;
192 if (scheme == null) return;
194 EditorColorsScheme clone = (EditorColorsScheme)scheme.getOriginalScheme().clone();
199 MyColorScheme newScheme = new MyColorScheme(clone);
200 initScheme(newScheme);
202 newScheme.setIsNew();
204 mySchemes.put(name, newScheme);
205 selectScheme(newScheme.getName());
206 resetSchemesCombo(null);
209 public void addImportedScheme(@NotNull EditorColorsScheme imported) {
210 MyColorScheme newScheme = new MyColorScheme(imported);
211 initScheme(newScheme);
213 mySchemes.put(imported.getName(), newScheme);
214 selectScheme(newScheme.getName());
215 resetSchemesCombo(null);
218 public void removeScheme(String name) {
219 if (mySelectedScheme.getName().equals(name)) {
220 //noinspection HardCodedStringLiteral
221 selectScheme("Default");
224 boolean deletedNewlyCreated = false;
226 MyColorScheme toDelete = mySchemes.get(name);
228 if (toDelete != null) {
229 deletedNewlyCreated = toDelete.isNew();
232 mySchemes.remove(name);
233 resetSchemesCombo(null);
234 mySomeSchemesDeleted = mySomeSchemesDeleted || !deletedNewlyCreated;
238 public void apply() throws ConfigurationException {
239 if (myApplyCompleted) {
244 EditorColorsManager myColorsManager = EditorColorsManager.getInstance();
245 SchemesManager<EditorColorsScheme, EditorColorsSchemeImpl> schemeManager = ((EditorColorsManagerImpl)myColorsManager).getSchemeManager();
247 List<EditorColorsScheme> result = new ArrayList<EditorColorsScheme>(mySchemes.values().size());
248 boolean activeSchemeModified = false;
249 EditorColorsScheme activeOriginalScheme = mySelectedScheme.getOriginalScheme();
250 for (MyColorScheme scheme : mySchemes.values()) {
251 if (!activeSchemeModified && activeOriginalScheme == scheme.getOriginalScheme()) {
252 activeSchemeModified = scheme.isModified();
255 if (!scheme.isDefault()) {
258 result.add(scheme.getOriginalScheme());
261 // refresh only if scheme is not switched
262 boolean refreshEditors = activeSchemeModified && schemeManager.getCurrentScheme() == activeOriginalScheme;
263 schemeManager.setSchemes(result, activeOriginalScheme);
264 if (refreshEditors) {
265 EditorColorsManagerImpl.schemeChangedOrSwitched();
268 final boolean dark = ColorUtil.isDark(activeOriginalScheme.getDefaultBackground());
269 final String productName = ApplicationInfoEx.getInstanceEx().getFullApplicationName();
270 final LafManager lafManager = LafManager.getInstance();
271 if (dark && !UIUtil.isUnderDarcula()) {
272 if (Messages.showYesNoDialog(
273 "Looks like you have set a dark editor theme. Would you like to set dark theme for entire " + productName,
274 "Change " + productName + " theme?",
275 Messages.getQuestionIcon()) == Messages.YES) {
276 lafManager.setCurrentLookAndFeel(new DarculaLookAndFeelInfo());
277 DarculaInstaller.install();
279 } else if (!dark && UIUtil.isUnderDarcula()) {
280 if (lafManager instanceof LafManagerImpl
282 Messages.showYesNoDialog(
283 "Looks like you have set a bright editor theme. Would you like to set bright theme for entire " + productName,
284 "Change " + productName + " theme",
285 Messages.getQuestionIcon()) == Messages.YES) {
286 lafManager.setCurrentLookAndFeel(((LafManagerImpl)lafManager).getDefaultLaf());
287 DarculaInstaller.uninstall();
294 myApplyCompleted = true;
298 private boolean myIsReset = false;
300 private void resetSchemesCombo(Object source) {
303 myRootSchemesPanel.resetSchemesCombo(source);
304 if (mySubPanelFactories != null) {
305 for (NewColorAndFontPanel subPartialConfigurable : getPanels()) {
306 subPartialConfigurable.reset(source);
316 public JComponent createComponent() {
317 if (myRootSchemesPanel == null) {
318 ensureSchemesPanel();
320 return myRootSchemesPanel;
324 public boolean hasOwnContent() {
330 public Configurable[] buildConfigurables() {
331 myDisposeCompleted = false;
334 List<ColorAndFontPanelFactory> panelFactories = createPanelFactories();
336 List<Configurable> result = new ArrayList<Configurable>();
337 mySubPanelFactories = new LinkedHashMap<ColorAndFontPanelFactory, InnerSearchableConfigurable>(panelFactories.size());
338 for (ColorAndFontPanelFactory panelFactory : panelFactories) {
339 mySubPanelFactories.put(panelFactory, new InnerSearchableConfigurable(panelFactory));
342 result.addAll(new ArrayList<SearchableConfigurable>(mySubPanelFactories.values()));
343 return result.toArray(new Configurable[result.size()]);
347 private Set<NewColorAndFontPanel> getPanels() {
348 Set<NewColorAndFontPanel> result = new HashSet<NewColorAndFontPanel>();
349 for (InnerSearchableConfigurable configurable : mySubPanelFactories.values()) {
350 NewColorAndFontPanel panel = configurable.getSubPanelIfInitialized();
358 protected List<ColorAndFontPanelFactory> createPanelFactories() {
359 List<ColorAndFontPanelFactory> result = new ArrayList<ColorAndFontPanelFactory>();
360 result.add(new FontConfigurableFactory());
362 List<ColorAndFontPanelFactory> extensions = new ArrayList<ColorAndFontPanelFactory>();
363 extensions.add(new ConsoleFontConfigurableFactory());
364 ColorSettingsPage[] pages = ColorSettingsPages.getInstance().getRegisteredPages();
365 for (final ColorSettingsPage page : pages) {
366 extensions.add(new ColorAndFontPanelFactoryEx() {
369 public NewColorAndFontPanel createPanel(@NotNull ColorAndFontOptions options) {
370 final SimpleEditorPreview preview = new SimpleEditorPreview(options, page);
371 return NewColorAndFontPanel.create(preview, page.getDisplayName(), options, null, page);
376 public String getPanelDisplayName() {
377 return page.getDisplayName();
381 public DisplayPriority getPriority() {
382 if (page instanceof DisplayPrioritySortable) {
383 return ((DisplayPrioritySortable)page).getPriority();
385 return DisplayPriority.LANGUAGE_SETTINGS;
389 Collections.addAll(extensions, Extensions.getExtensions(ColorAndFontPanelFactory.EP_NAME));
390 Collections.sort(extensions, (f1, f2) -> {
391 if (f1 instanceof DisplayPrioritySortable) {
392 if (f2 instanceof DisplayPrioritySortable) {
393 int result1 = ((DisplayPrioritySortable)f1).getPriority().compareTo(((DisplayPrioritySortable)f2).getPriority());
394 if (result1 != 0) return result1;
400 else if (f2 instanceof DisplayPrioritySortable) {
403 return f1.getPanelDisplayName().compareToIgnoreCase(f2.getPanelDisplayName());
405 result.addAll(extensions);
407 result.add(new FileStatusColorsPageFactory());
408 result.add(new ScopeColorsPageFactory());
413 private static class FontConfigurableFactory implements ColorAndFontPanelFactory {
416 public NewColorAndFontPanel createPanel(@NotNull ColorAndFontOptions options) {
417 FontEditorPreview previewPanel = new FontEditorPreview(options, true);
418 return new NewColorAndFontPanel(new SchemesPanel(options), new FontOptions(options), previewPanel, "Font", null, null){
420 public boolean containsFontOptions() {
428 public String getPanelDisplayName() {
433 private static class ConsoleFontConfigurableFactory implements ColorAndFontPanelFactoryEx {
436 public NewColorAndFontPanel createPanel(@NotNull ColorAndFontOptions options) {
437 FontEditorPreview previewPanel = new FontEditorPreview(options, false) {
439 protected EditorColorsScheme updateOptionsScheme(EditorColorsScheme selectedScheme) {
440 return ConsoleViewUtil.updateConsoleColorScheme(selectedScheme);
443 return new NewColorAndFontPanel(new SchemesPanel(options), new ConsoleFontOptions(options), previewPanel, "Font", null, null){
445 public boolean containsFontOptions() {
453 public String getPanelDisplayName() {
454 return "Console Font";
459 public DisplayPriority getPriority() {
460 return DisplayPriority.COMMON_SETTINGS;
464 private void initAll() {
465 mySchemes = new THashMap<String, MyColorScheme>();
466 for (EditorColorsScheme allScheme : EditorColorsManager.getInstance().getAllSchemes()) {
467 MyColorScheme schemeDelegate = new MyColorScheme(allScheme);
468 initScheme(schemeDelegate);
469 mySchemes.put(schemeDelegate.getName(), schemeDelegate);
472 mySelectedScheme = mySchemes.get(EditorColorsManager.getInstance().getGlobalScheme().getName());
473 assert mySelectedScheme != null : EditorColorsManager.getInstance().getGlobalScheme().getName() + "; myschemes=" + mySchemes;
476 private static void initScheme(@NotNull MyColorScheme scheme) {
477 List<EditorSchemeAttributeDescriptor> descriptions = new ArrayList<EditorSchemeAttributeDescriptor>();
478 initPluggedDescriptions(descriptions, scheme);
479 initFileStatusDescriptors(descriptions, scheme);
480 initScopesDescriptors(descriptions, scheme);
482 scheme.setDescriptors(descriptions.toArray(new EditorSchemeAttributeDescriptor[descriptions.size()]));
485 private static void initPluggedDescriptions(@NotNull List<EditorSchemeAttributeDescriptor> descriptions, @NotNull MyColorScheme scheme) {
486 ColorSettingsPage[] pages = ColorSettingsPages.getInstance().getRegisteredPages();
487 for (ColorSettingsPage page : pages) {
488 initDescriptions(page, descriptions, scheme);
490 for (ColorAndFontDescriptorsProvider provider : Extensions.getExtensions(ColorAndFontDescriptorsProvider.EP_NAME)) {
491 initDescriptions(provider, descriptions, scheme);
495 private static void initDescriptions(@NotNull ColorAndFontDescriptorsProvider provider,
496 @NotNull List<EditorSchemeAttributeDescriptor> descriptions,
497 @NotNull MyColorScheme scheme) {
498 String group = provider.getDisplayName();
499 List<AttributesDescriptor> attributeDescriptors = ColorSettingsUtil.getAllAttributeDescriptors(provider);
500 for (AttributesDescriptor descriptor : attributeDescriptors) {
501 addSchemedDescription(descriptions, descriptor.getDisplayName(), group, descriptor.getKey(), scheme, null, null);
504 ColorDescriptor[] colorDescriptors = provider.getColorDescriptors();
505 for (ColorDescriptor descriptor : colorDescriptors) {
506 ColorKey back = descriptor.getKind() == ColorDescriptor.Kind.BACKGROUND ? descriptor.getKey() : null;
507 ColorKey fore = descriptor.getKind() == ColorDescriptor.Kind.FOREGROUND ? descriptor.getKey() : null;
508 addEditorSettingDescription(descriptions, descriptor.getDisplayName(), group, back, fore, scheme);
512 private static void initFileStatusDescriptors(@NotNull List<EditorSchemeAttributeDescriptor> descriptions, MyColorScheme scheme) {
514 FileStatus[] statuses = FileStatusFactory.getInstance().getAllFileStatuses();
516 for (FileStatus fileStatus : statuses) {
517 addEditorSettingDescription(descriptions,
518 fileStatus.getText(),
521 fileStatus.getColorKey(),
526 private static void initScopesDescriptors(@NotNull List<EditorSchemeAttributeDescriptor> descriptions, @NotNull MyColorScheme scheme) {
527 Set<Pair<NamedScope,NamedScopesHolder>> namedScopes = new THashSet<Pair<NamedScope,NamedScopesHolder>>(new TObjectHashingStrategy<Pair<NamedScope,NamedScopesHolder>>() {
529 public int computeHashCode(@NotNull final Pair<NamedScope, NamedScopesHolder> object) {
530 return object.getFirst().getName().hashCode();
534 public boolean equals(@NotNull final Pair<NamedScope, NamedScopesHolder> o1, @NotNull final Pair<NamedScope, NamedScopesHolder> o2) {
535 return o1.getFirst().getName().equals(o2.getFirst().getName());
538 Project[] projects = ProjectManager.getInstance().getOpenProjects();
539 for (Project project : projects) {
540 DependencyValidationManagerImpl validationManager = (DependencyValidationManagerImpl)DependencyValidationManager.getInstance(project);
541 List<Pair<NamedScope,NamedScopesHolder>> cachedScopes = validationManager.getScopeBasedHighlightingCachedScopes();
542 namedScopes.addAll(cachedScopes);
545 List<Pair<NamedScope, NamedScopesHolder>> list = new ArrayList<Pair<NamedScope, NamedScopesHolder>>(namedScopes);
547 Collections.sort(list, (o1, o2) -> o1.getFirst().getName().compareToIgnoreCase(o2.getFirst().getName()));
548 for (Pair<NamedScope,NamedScopesHolder> pair : list) {
549 NamedScope namedScope = pair.getFirst();
550 String name = namedScope.getName();
551 TextAttributesKey textAttributesKey = ScopeAttributesUtil.getScopeTextAttributeKey(name);
552 if (scheme.getAttributes(textAttributesKey) == null) {
553 scheme.setAttributes(textAttributesKey, new TextAttributes());
555 NamedScopesHolder holder = pair.getSecond();
557 PackageSet value = namedScope.getValue();
558 String toolTip = holder.getDisplayName() + (value==null ? "" : ": "+ value.getText());
559 addSchemedDescription(descriptions,
563 scheme, holder.getIcon(), toolTip);
568 private static String calcType(@Nullable ColorKey backgroundKey, @Nullable ColorKey foregroundKey) {
569 if (foregroundKey != null) {
570 return foregroundKey.getExternalName();
572 else if (backgroundKey != null) {
573 return backgroundKey.getExternalName();
578 private static void addEditorSettingDescription(@NotNull List<EditorSchemeAttributeDescriptor> list,
581 @Nullable ColorKey backgroundKey,
582 @Nullable ColorKey foregroundKey,
583 @NotNull EditorColorsScheme scheme) {
584 list.add(new EditorSettingColorDescription(name, group, backgroundKey, foregroundKey, calcType(backgroundKey, foregroundKey), scheme));
587 private static void addSchemedDescription(@NotNull List<EditorSchemeAttributeDescriptor> list,
590 @NotNull TextAttributesKey key,
591 @NotNull MyColorScheme scheme,
594 list.add(new SchemeTextAttributesDescription(name, group, key, scheme, icon, toolTip));
598 public String getDisplayName() {
599 return ApplicationBundle.message("title.colors.and.fonts");
602 private void revertChanges(){
603 if (isSchemeListModified() || isSomeSchemeModified()) {
604 myRevertChangesCompleted = false;
607 if (!myRevertChangesCompleted) {
608 ensureSchemesPanel();
615 myRevertChangesCompleted = true;
621 private void resetImpl() {
622 mySomeSchemesDeleted = false;
624 resetSchemesCombo(null);
628 public synchronized void reset() {
629 if (!myInitResetInvoked) {
631 if (!myInitResetCompleted) {
632 ensureSchemesPanel();
638 myInitResetCompleted = true;
643 myInitResetInvoked = true;
651 public synchronized void resetFromChild() {
652 if (!myInitResetCompleted) {
653 ensureSchemesPanel();
660 myInitResetCompleted = true;
666 private void ensureSchemesPanel() {
667 if (myRootSchemesPanel == null) {
668 myRootSchemesPanel = new SchemesPanel(this);
670 myRootSchemesPanel.addListener(new ColorAndFontSettingsListener.Abstract(){
672 public void schemeChanged(final Object source) {
674 resetSchemesCombo(source);
683 public void disposeUIResources() {
685 if (!myDisposeCompleted) {
687 super.disposeUIResources();
688 Disposer.dispose(myDisposable);
691 myDisposeCompleted = true;
696 mySubPanelFactories = null;
698 myInitResetCompleted = false;
699 myInitResetInvoked = false;
700 myRevertChangesCompleted = false;
702 myApplyCompleted = false;
703 myRootSchemesPanel = null;
707 public boolean currentSchemeIsReadOnly() {
708 return isReadOnly(mySelectedScheme);
711 public boolean currentSchemeIsShared() {
712 return ColorSettingsUtil.isSharedScheme(mySelectedScheme);
716 private static class SchemeTextAttributesDescription extends TextAttributesDescription {
717 @NotNull private final TextAttributes myInitialAttributes;
718 @NotNull private final TextAttributesKey key;
719 private TextAttributes myFallbackAttributes;
720 private Pair<ColorSettingsPage,AttributesDescriptor> myBaseAttributeDescriptor;
721 private boolean myIsInheritedInitial = false;
723 private SchemeTextAttributesDescription(String name, String group, @NotNull TextAttributesKey key, @NotNull MyColorScheme scheme, Icon icon,
726 getInitialAttributes(scheme, key).clone(),
727 key, scheme, icon, toolTip);
729 myInitialAttributes = getInitialAttributes(scheme, key);
730 TextAttributesKey fallbackKey = key.getFallbackAttributeKey();
731 if (fallbackKey != null) {
732 myFallbackAttributes = scheme.getAttributes(fallbackKey);
733 myBaseAttributeDescriptor = ColorSettingsPages.getInstance().getAttributeDescriptor(fallbackKey);
734 if (myBaseAttributeDescriptor == null) {
735 myBaseAttributeDescriptor =
736 new Pair<ColorSettingsPage, AttributesDescriptor>(null, new AttributesDescriptor(fallbackKey.getExternalName(), fallbackKey));
739 myIsInheritedInitial = scheme.isInherited(key);
740 setInherited(myIsInheritedInitial);
741 if (myIsInheritedInitial) {
742 setInheritedAttributes(getTextAttributes());
748 private void setInheritedAttributes(@NotNull TextAttributes attributes) {
749 attributes.setFontType(myFallbackAttributes.getFontType());
750 attributes.setForegroundColor(myFallbackAttributes.getForegroundColor());
751 attributes.setBackgroundColor(myFallbackAttributes.getBackgroundColor());
752 attributes.setErrorStripeColor(myFallbackAttributes.getErrorStripeColor());
753 attributes.setEffectColor(myFallbackAttributes.getEffectColor());
754 attributes.setEffectType(myFallbackAttributes.getEffectType());
759 private static TextAttributes getInitialAttributes(@NotNull MyColorScheme scheme, @NotNull TextAttributesKey key) {
760 TextAttributes attributes = scheme.getAttributes(key);
761 return attributes != null ? attributes : new TextAttributes();
765 public void apply(EditorColorsScheme scheme) {
766 if (scheme == null) scheme = getScheme();
767 scheme.setAttributes(key, isInherited() ? new TextAttributes() : getTextAttributes());
771 public boolean isModified() {
773 return !myIsInheritedInitial;
775 return !Comparing.equal(myInitialAttributes, getTextAttributes()) || myIsInheritedInitial;
779 public boolean isErrorStripeEnabled() {
785 public TextAttributes getBaseAttributes() {
786 return myFallbackAttributes;
791 public Pair<ColorSettingsPage,AttributesDescriptor> getBaseAttributeDescriptor() {
792 return myBaseAttributeDescriptor;
796 public void setInherited(boolean isInherited) {
797 super.setInherited(isInherited);
801 private static class GetSetColor {
802 private final ColorKey myKey;
803 private final EditorColorsScheme myScheme;
804 private boolean isModified = false;
805 private Color myColor;
807 private GetSetColor(ColorKey key, EditorColorsScheme scheme) {
810 myColor = myScheme.getColor(myKey);
813 public Color getColor() {
817 public void setColor(Color col) {
818 if (getColor() == null || !getColor().equals(col)) {
824 public void apply(EditorColorsScheme scheme) {
825 if (scheme == null) scheme = myScheme;
826 scheme.setColor(myKey, myColor);
829 public boolean isModified() {
834 private static class EditorSettingColorDescription extends ColorAndFontDescription {
835 private GetSetColor myGetSetForeground;
836 private GetSetColor myGetSetBackground;
838 private EditorSettingColorDescription(String name,
840 ColorKey backgroundKey,
841 ColorKey foregroundKey,
843 EditorColorsScheme scheme) {
844 super(name, group, type, scheme, null, null);
845 if (backgroundKey != null) {
846 myGetSetBackground = new GetSetColor(backgroundKey, scheme);
848 if (foregroundKey != null) {
849 myGetSetForeground = new GetSetColor(foregroundKey, scheme);
855 public int getFontType() {
860 public void setFontType(int type) {
864 public Color getExternalEffectColor() {
869 public void setExternalEffectColor(Color color) {
873 public void setExternalEffectType(EffectType type) {
878 public EffectType getExternalEffectType() {
879 return EffectType.LINE_UNDERSCORE;
883 public Color getExternalForeground() {
884 if (myGetSetForeground == null) {
887 return myGetSetForeground.getColor();
891 public void setExternalForeground(Color col) {
892 if (myGetSetForeground == null) {
895 myGetSetForeground.setColor(col);
899 public Color getExternalBackground() {
900 if (myGetSetBackground == null) {
903 return myGetSetBackground.getColor();
907 public void setExternalBackground(Color col) {
908 if (myGetSetBackground == null) {
911 myGetSetBackground.setColor(col);
915 public Color getExternalErrorStripe() {
920 public void setExternalErrorStripe(Color col) {
924 public boolean isFontEnabled() {
929 public boolean isForegroundEnabled() {
930 return myGetSetForeground != null;
934 public boolean isBackgroundEnabled() {
935 return myGetSetBackground != null;
939 public boolean isEffectsColorEnabled() {
944 public boolean isModified() {
945 return myGetSetBackground != null && myGetSetBackground.isModified()
946 || myGetSetForeground != null && myGetSetForeground.isModified();
950 public void apply(EditorColorsScheme scheme) {
951 if (myGetSetBackground != null) {
952 myGetSetBackground.apply(scheme);
954 if (myGetSetForeground != null) {
955 myGetSetForeground.apply(scheme);
962 public String getHelpTopic() {
966 private static class MyColorScheme extends EditorColorsSchemeImpl {
967 private EditorSchemeAttributeDescriptor[] myDescriptors;
968 private String myName;
969 private boolean myIsNew = false;
971 private MyColorScheme(@NotNull EditorColorsScheme parentScheme) {
974 parentScheme.getFontPreferences().copyTo(getFontPreferences());
975 setLineSpacing(parentScheme.getLineSpacing());
977 parentScheme.getConsoleFontPreferences().copyTo(getConsoleFontPreferences());
978 setConsoleLineSpacing(parentScheme.getConsoleLineSpacing());
980 setQuickDocFontSize(parentScheme.getQuickDocFontSize());
981 myName = parentScheme.getName();
987 public String getName() {
992 public void setName(@NotNull String name) {
996 public void setDescriptors(EditorSchemeAttributeDescriptor[] descriptors) {
997 myDescriptors = descriptors;
1000 public EditorSchemeAttributeDescriptor[] getDescriptors() {
1001 return myDescriptors;
1004 public boolean isDefault() {
1005 return myParentScheme instanceof DefaultColorsScheme;
1009 public boolean isReadOnly() {
1010 return myParentScheme instanceof ReadOnlyColorsScheme;
1013 public boolean isModified() {
1014 if (isFontModified() || isConsoleFontModified()) return true;
1016 for (EditorSchemeAttributeDescriptor descriptor : myDescriptors) {
1017 if (descriptor.isModified()) {
1025 private boolean isFontModified() {
1026 if (!getFontPreferences().equals(myParentScheme.getFontPreferences())) return true;
1027 if (getLineSpacing() != myParentScheme.getLineSpacing()) return true;
1028 return getQuickDocFontSize() != myParentScheme.getQuickDocFontSize();
1031 private boolean isConsoleFontModified() {
1032 if (!getConsoleFontPreferences().equals(myParentScheme.getConsoleFontPreferences())) return true;
1033 return getConsoleLineSpacing() != myParentScheme.getConsoleLineSpacing();
1036 public void apply() {
1037 if (!(myParentScheme instanceof ReadOnlyColorsScheme)) {
1038 apply(myParentScheme);
1042 public void apply(@NotNull EditorColorsScheme scheme) {
1043 scheme.setFontPreferences(getFontPreferences());
1044 scheme.setLineSpacing(myLineSpacing);
1045 scheme.setQuickDocFontSize(getQuickDocFontSize());
1046 scheme.setConsoleFontPreferences(getConsoleFontPreferences());
1047 scheme.setConsoleLineSpacing(getConsoleLineSpacing());
1049 for (EditorSchemeAttributeDescriptor descriptor : myDescriptors) {
1050 descriptor.apply(scheme);
1053 if (scheme instanceof AbstractColorsScheme) {
1054 ((AbstractColorsScheme)scheme).setSaveNeeded(true);
1059 public Object clone() {
1064 public EditorColorsScheme getOriginalScheme() {
1065 return myParentScheme;
1068 public void setIsNew() {
1072 public boolean isNew() {
1078 public String toString() {
1079 return "temporary scheme for " + myName;
1082 public boolean isInherited(TextAttributesKey key) {
1083 TextAttributesKey fallbackKey = key.getFallbackAttributeKey();
1084 if (fallbackKey != null) {
1085 if (myParentScheme instanceof AbstractColorsScheme) {
1086 TextAttributes ownAttrs = ((AbstractColorsScheme)myParentScheme).getDirectlyDefinedAttributes(key);
1087 if (ownAttrs != null) {
1088 return ownAttrs.isFallbackEnabled();
1091 TextAttributes attributes = getAttributes(key);
1092 if (attributes != null) {
1093 TextAttributes fallbackAttributes = getAttributes(fallbackKey);
1094 return attributes == fallbackAttributes;
1103 public String getId() {
1104 return getHelpTopic();
1109 public Runnable enableSearch(final String option) {
1114 public SearchableConfigurable findSubConfigurable(@NotNull Class pageClass) {
1115 if (mySubPanelFactories == null) {
1116 buildConfigurables();
1118 for (Map.Entry<ColorAndFontPanelFactory, InnerSearchableConfigurable> entry : mySubPanelFactories.entrySet()) {
1119 if (pageClass.isInstance(entry.getValue().createPanel().getSettingsPage())) {
1120 return entry.getValue();
1127 public SearchableConfigurable findSubConfigurable(String pageName) {
1128 if (mySubPanelFactories == null) {
1129 buildConfigurables();
1131 for (InnerSearchableConfigurable configurable : mySubPanelFactories.values()) {
1132 if (configurable.getDisplayName().equals(pageName)) {
1133 return configurable;
1140 public NewColorAndFontPanel findPage(String pageName) {
1141 InnerSearchableConfigurable child = (InnerSearchableConfigurable)findSubConfigurable(pageName);
1142 return child == null ? null : child.createPanel();
1145 private class InnerSearchableConfigurable implements SearchableConfigurable, OptionsContainingConfigurable, NoScroll {
1146 private NewColorAndFontPanel mySubPanel;
1147 private boolean mySubInitInvoked = false;
1148 @NotNull private final ColorAndFontPanelFactory myFactory;
1150 private InnerSearchableConfigurable(@NotNull ColorAndFontPanelFactory factory) {
1151 myFactory = factory;
1157 public String getDisplayName() {
1158 return myFactory.getPanelDisplayName();
1161 public NewColorAndFontPanel getSubPanelIfInitialized() {
1165 private NewColorAndFontPanel createPanel() {
1166 if (mySubPanel == null) {
1167 mySubPanel = myFactory.createPanel(ColorAndFontOptions.this);
1168 mySubPanel.reset(this);
1169 mySubPanel.addSchemesListener(new ColorAndFontSettingsListener.Abstract(){
1171 public void schemeChanged(final Object source) {
1173 resetSchemesCombo(source);
1178 mySubPanel.addDescriptionListener(new ColorAndFontSettingsListener.Abstract(){
1180 public void fontChanged() {
1181 for (NewColorAndFontPanel panel : getPanels()) {
1182 panel.updatePreview();
1191 public String getHelpTopic() {
1196 public JComponent createComponent() {
1197 return createPanel().getPanel();
1201 public boolean isModified() {
1203 for (MyColorScheme scheme : mySchemes.values()) {
1204 if (mySubPanel.containsFontOptions()) {
1205 if (scheme.isFontModified() || scheme.isConsoleFontModified()) {
1206 myRevertChangesCompleted = false;
1211 for (EditorSchemeAttributeDescriptor descriptor : scheme.getDescriptors()) {
1212 if (mySubPanel.contains(descriptor) && descriptor.isModified()) {
1213 myRevertChangesCompleted = false;
1226 public void apply() throws ConfigurationException {
1227 ColorAndFontOptions.this.apply();
1231 public void reset() {
1232 if (!mySubInitInvoked) {
1233 if (!myInitResetCompleted) {
1236 mySubInitInvoked = true;
1244 public void disposeUIResources() {
1245 if (mySubPanel != null) {
1246 mySubPanel.disposeUIResources();
1253 public String getId() {
1254 return ColorAndFontOptions.this.getId() + "." + getDisplayName();
1258 public Runnable enableSearch(final String option) {
1259 return createPanel().showOption(option);
1264 public Set<String> processListOptions() {
1265 return createPanel().processListOptions();
1271 public String toString() {
1272 return "Color And Fonts for "+getDisplayName();