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.editor.colors.ColorKey;
30 import com.intellij.openapi.editor.colors.EditorColorsManager;
31 import com.intellij.openapi.editor.colors.EditorColorsScheme;
32 import com.intellij.openapi.editor.colors.TextAttributesKey;
33 import com.intellij.openapi.editor.colors.impl.*;
34 import com.intellij.openapi.editor.markup.EffectType;
35 import com.intellij.openapi.editor.markup.TextAttributes;
36 import com.intellij.openapi.extensions.Extensions;
37 import com.intellij.openapi.options.Configurable;
38 import com.intellij.openapi.options.ConfigurationException;
39 import com.intellij.openapi.options.SchemeManager;
40 import com.intellij.openapi.options.SearchableConfigurable;
41 import com.intellij.openapi.options.colors.*;
42 import com.intellij.openapi.project.Project;
43 import com.intellij.openapi.project.ProjectManager;
44 import com.intellij.openapi.ui.Messages;
45 import com.intellij.openapi.util.Comparing;
46 import com.intellij.openapi.util.Disposer;
47 import com.intellij.openapi.util.Pair;
48 import com.intellij.openapi.vcs.FileStatus;
49 import com.intellij.openapi.vcs.FileStatusFactory;
50 import com.intellij.packageDependencies.DependencyValidationManager;
51 import com.intellij.packageDependencies.DependencyValidationManagerImpl;
52 import com.intellij.psi.codeStyle.DisplayPriority;
53 import com.intellij.psi.codeStyle.DisplayPrioritySortable;
54 import com.intellij.psi.search.scope.packageSet.NamedScope;
55 import com.intellij.psi.search.scope.packageSet.NamedScopesHolder;
56 import com.intellij.psi.search.scope.packageSet.PackageSet;
57 import com.intellij.ui.ColorUtil;
58 import com.intellij.util.ArrayUtil;
59 import com.intellij.util.ui.UIUtil;
60 import gnu.trove.THashMap;
61 import gnu.trove.THashSet;
62 import gnu.trove.TObjectHashingStrategy;
63 import org.jetbrains.annotations.Nls;
64 import org.jetbrains.annotations.NonNls;
65 import org.jetbrains.annotations.NotNull;
66 import org.jetbrains.annotations.Nullable;
71 import java.util.List;
73 public class ColorAndFontOptions extends SearchableConfigurable.Parent.Abstract implements EditorOptionsProvider {
74 public static final String ID = "reference.settingsdialog.IDE.editor.colors";
76 private Map<String, MyColorScheme> mySchemes;
77 private MyColorScheme mySelectedScheme;
78 public static final String FILE_STATUS_GROUP = ApplicationBundle.message("title.file.status");
79 public static final String SCOPES_GROUP = ApplicationBundle.message("title.scope.based");
81 private boolean mySomeSchemesDeleted = false;
82 private Map<ColorAndFontPanelFactory, InnerSearchableConfigurable> mySubPanelFactories;
84 private SchemesPanel myRootSchemesPanel;
86 private boolean myInitResetCompleted = false;
87 private boolean myInitResetInvoked = false;
89 private boolean myRevertChangesCompleted = false;
91 private boolean myApplyCompleted = false;
92 private boolean myDisposeCompleted = false;
93 private final Disposable myDisposable = Disposer.newDisposable();
96 public boolean isModified() {
97 boolean listModified = isSchemeListModified();
98 boolean schemeModified = isSomeSchemeModified();
100 if (listModified || schemeModified) {
101 myApplyCompleted = false;
107 private boolean isSchemeListModified(){
108 if (mySomeSchemesDeleted) return true;
110 if (!mySelectedScheme.getName().equals(EditorColorsManager.getInstance().getGlobalScheme().getName())) return true;
112 for (MyColorScheme scheme : mySchemes.values()) {
113 if (scheme.isNew()) return true;
119 private boolean isSomeSchemeModified() {
120 for (MyColorScheme scheme : mySchemes.values()) {
121 if (scheme.isModified()) return true;
126 public EditorColorsScheme selectScheme(@NotNull String name) {
127 mySelectedScheme = getScheme(name);
128 return mySelectedScheme;
131 private MyColorScheme getScheme(String name) {
132 return mySchemes.get(name);
136 public String getUniqueName(@NotNull String preferredName) {
138 if (mySchemes.containsKey(preferredName)) {
139 for (int i = 1; ; i++) {
140 name = preferredName + " (" + i + ")";
141 if (!mySchemes.containsKey(name)) {
147 name = preferredName;
152 public EditorColorsScheme getSelectedScheme() {
153 return mySelectedScheme;
156 public EditorSchemeAttributeDescriptor[] getCurrentDescriptions() {
157 return mySelectedScheme.getDescriptors();
160 public static boolean isReadOnly(@NotNull final EditorColorsScheme scheme) {
161 return ((MyColorScheme)scheme).isReadOnly();
165 public String[] getSchemeNames() {
166 List<MyColorScheme> schemes = new ArrayList<MyColorScheme>(mySchemes.values());
167 Collections.sort(schemes, (o1, o2) -> {
168 if (isReadOnly(o1) && !isReadOnly(o2)) return -1;
169 if (!isReadOnly(o1) && isReadOnly(o2)) return 1;
171 return o1.getName().compareToIgnoreCase(o2.getName());
174 List<String> names = new ArrayList<String>(schemes.size());
175 for (MyColorScheme scheme : schemes) {
176 names.add(scheme.getName());
179 return ArrayUtil.toStringArray(names);
183 public Collection<EditorColorsScheme> getSchemes() {
184 return new ArrayList<EditorColorsScheme>(mySchemes.values());
187 public void saveSchemeAs(String name) {
188 MyColorScheme scheme = mySelectedScheme;
189 if (scheme == null) return;
191 EditorColorsScheme clone = (EditorColorsScheme)scheme.getOriginalScheme().clone();
196 MyColorScheme newScheme = new MyColorScheme(clone);
197 initScheme(newScheme);
199 newScheme.setIsNew();
201 mySchemes.put(name, newScheme);
202 selectScheme(newScheme.getName());
203 resetSchemesCombo(null);
206 public void addImportedScheme(@NotNull EditorColorsScheme imported) {
207 MyColorScheme newScheme = new MyColorScheme(imported);
208 initScheme(newScheme);
210 mySchemes.put(imported.getName(), newScheme);
211 selectScheme(newScheme.getName());
212 resetSchemesCombo(null);
215 public void removeScheme(String name) {
216 if (mySelectedScheme.getName().equals(name)) {
217 //noinspection HardCodedStringLiteral
218 selectScheme("Default");
221 boolean deletedNewlyCreated = false;
223 MyColorScheme toDelete = mySchemes.get(name);
225 if (toDelete != null) {
226 deletedNewlyCreated = toDelete.isNew();
229 mySchemes.remove(name);
230 resetSchemesCombo(null);
231 mySomeSchemesDeleted = mySomeSchemesDeleted || !deletedNewlyCreated;
235 public void apply() throws ConfigurationException {
236 if (myApplyCompleted) {
241 EditorColorsManager myColorsManager = EditorColorsManager.getInstance();
242 SchemeManager<EditorColorsScheme> schemeManager = ((EditorColorsManagerImpl)myColorsManager).getSchemeManager();
244 List<EditorColorsScheme> result = new ArrayList<EditorColorsScheme>(mySchemes.values().size());
245 boolean activeSchemeModified = false;
246 EditorColorsScheme activeOriginalScheme = mySelectedScheme.getOriginalScheme();
247 for (MyColorScheme scheme : mySchemes.values()) {
248 if (!activeSchemeModified && activeOriginalScheme == scheme.getOriginalScheme()) {
249 activeSchemeModified = scheme.isModified();
252 if (!scheme.isDefault()) {
255 result.add(scheme.getOriginalScheme());
258 // refresh only if scheme is not switched
259 boolean refreshEditors = activeSchemeModified && schemeManager.getCurrentScheme() == activeOriginalScheme;
260 schemeManager.setSchemes(result, activeOriginalScheme);
261 if (refreshEditors) {
262 EditorColorsManagerImpl.schemeChangedOrSwitched();
265 final boolean dark = ColorUtil.isDark(activeOriginalScheme.getDefaultBackground());
266 final String productName = ApplicationInfoEx.getInstanceEx().getFullApplicationName();
267 final LafManager lafManager = LafManager.getInstance();
268 if (dark && !UIUtil.isUnderDarcula()) {
269 if (Messages.showYesNoDialog(
270 "Looks like you have set a dark editor theme. Would you like to set dark theme for entire " + productName,
271 "Change " + productName + " theme?",
272 Messages.getQuestionIcon()) == Messages.YES) {
273 lafManager.setCurrentLookAndFeel(new DarculaLookAndFeelInfo());
274 DarculaInstaller.install();
276 } else if (!dark && UIUtil.isUnderDarcula()) {
277 if (lafManager instanceof LafManagerImpl
279 Messages.showYesNoDialog(
280 "Looks like you have set a bright editor theme. Would you like to set bright theme for entire " + productName,
281 "Change " + productName + " theme",
282 Messages.getQuestionIcon()) == Messages.YES) {
283 lafManager.setCurrentLookAndFeel(((LafManagerImpl)lafManager).getDefaultLaf());
284 DarculaInstaller.uninstall();
291 myApplyCompleted = true;
295 private boolean myIsReset = false;
297 private void resetSchemesCombo(Object source) {
300 myRootSchemesPanel.resetSchemesCombo(source);
301 if (mySubPanelFactories != null) {
302 for (NewColorAndFontPanel subPartialConfigurable : getPanels()) {
303 subPartialConfigurable.reset(source);
313 public JComponent createComponent() {
314 if (myRootSchemesPanel == null) {
315 ensureSchemesPanel();
317 return myRootSchemesPanel;
321 public boolean hasOwnContent() {
327 public Configurable[] buildConfigurables() {
328 myDisposeCompleted = false;
331 List<ColorAndFontPanelFactory> panelFactories = createPanelFactories();
333 List<Configurable> result = new ArrayList<Configurable>();
334 mySubPanelFactories = new LinkedHashMap<ColorAndFontPanelFactory, InnerSearchableConfigurable>(panelFactories.size());
335 for (ColorAndFontPanelFactory panelFactory : panelFactories) {
336 mySubPanelFactories.put(panelFactory, new InnerSearchableConfigurable(panelFactory));
339 result.addAll(new ArrayList<SearchableConfigurable>(mySubPanelFactories.values()));
340 return result.toArray(new Configurable[result.size()]);
344 private Set<NewColorAndFontPanel> getPanels() {
345 Set<NewColorAndFontPanel> result = new HashSet<NewColorAndFontPanel>();
346 for (InnerSearchableConfigurable configurable : mySubPanelFactories.values()) {
347 NewColorAndFontPanel panel = configurable.getSubPanelIfInitialized();
355 protected List<ColorAndFontPanelFactory> createPanelFactories() {
356 List<ColorAndFontPanelFactory> result = new ArrayList<ColorAndFontPanelFactory>();
357 result.add(new FontConfigurableFactory());
359 List<ColorAndFontPanelFactory> extensions = new ArrayList<ColorAndFontPanelFactory>();
360 extensions.add(new ConsoleFontConfigurableFactory());
361 ColorSettingsPage[] pages = ColorSettingsPages.getInstance().getRegisteredPages();
362 for (final ColorSettingsPage page : pages) {
363 extensions.add(new ColorAndFontPanelFactoryEx() {
366 public NewColorAndFontPanel createPanel(@NotNull ColorAndFontOptions options) {
367 final SimpleEditorPreview preview = new SimpleEditorPreview(options, page);
368 return NewColorAndFontPanel.create(preview, page.getDisplayName(), options, null, page);
373 public String getPanelDisplayName() {
374 return page.getDisplayName();
378 public DisplayPriority getPriority() {
379 if (page instanceof DisplayPrioritySortable) {
380 return ((DisplayPrioritySortable)page).getPriority();
382 return DisplayPriority.LANGUAGE_SETTINGS;
386 Collections.addAll(extensions, Extensions.getExtensions(ColorAndFontPanelFactory.EP_NAME));
387 Collections.sort(extensions, (f1, f2) -> {
388 if (f1 instanceof DisplayPrioritySortable) {
389 if (f2 instanceof DisplayPrioritySortable) {
390 int result1 = ((DisplayPrioritySortable)f1).getPriority().compareTo(((DisplayPrioritySortable)f2).getPriority());
391 if (result1 != 0) return result1;
397 else if (f2 instanceof DisplayPrioritySortable) {
400 return f1.getPanelDisplayName().compareToIgnoreCase(f2.getPanelDisplayName());
402 result.addAll(extensions);
404 result.add(new FileStatusColorsPageFactory());
405 result.add(new ScopeColorsPageFactory());
410 private static class FontConfigurableFactory implements ColorAndFontPanelFactory {
413 public NewColorAndFontPanel createPanel(@NotNull ColorAndFontOptions options) {
414 FontEditorPreview previewPanel = new FontEditorPreview(options, true);
415 return new NewColorAndFontPanel(new SchemesPanel(options), new FontOptions(options), previewPanel, "Font", null, null){
417 public boolean containsFontOptions() {
425 public String getPanelDisplayName() {
430 private static class ConsoleFontConfigurableFactory implements ColorAndFontPanelFactoryEx {
433 public NewColorAndFontPanel createPanel(@NotNull ColorAndFontOptions options) {
434 FontEditorPreview previewPanel = new FontEditorPreview(options, false) {
436 protected EditorColorsScheme updateOptionsScheme(EditorColorsScheme selectedScheme) {
437 return ConsoleViewUtil.updateConsoleColorScheme(selectedScheme);
440 return new NewColorAndFontPanel(new SchemesPanel(options), new ConsoleFontOptions(options), previewPanel, "Font", null, null){
442 public boolean containsFontOptions() {
450 public String getPanelDisplayName() {
451 return "Console Font";
456 public DisplayPriority getPriority() {
457 return DisplayPriority.COMMON_SETTINGS;
461 private void initAll() {
462 mySchemes = new THashMap<String, MyColorScheme>();
463 for (EditorColorsScheme allScheme : EditorColorsManager.getInstance().getAllSchemes()) {
464 MyColorScheme schemeDelegate = new MyColorScheme(allScheme);
465 initScheme(schemeDelegate);
466 mySchemes.put(schemeDelegate.getName(), schemeDelegate);
469 mySelectedScheme = mySchemes.get(EditorColorsManager.getInstance().getGlobalScheme().getName());
470 assert mySelectedScheme != null : EditorColorsManager.getInstance().getGlobalScheme().getName() + "; myschemes=" + mySchemes;
473 private static void initScheme(@NotNull MyColorScheme scheme) {
474 List<EditorSchemeAttributeDescriptor> descriptions = new ArrayList<EditorSchemeAttributeDescriptor>();
475 initPluggedDescriptions(descriptions, scheme);
476 initFileStatusDescriptors(descriptions, scheme);
477 initScopesDescriptors(descriptions, scheme);
479 scheme.setDescriptors(descriptions.toArray(new EditorSchemeAttributeDescriptor[descriptions.size()]));
482 private static void initPluggedDescriptions(@NotNull List<EditorSchemeAttributeDescriptor> descriptions, @NotNull MyColorScheme scheme) {
483 ColorSettingsPage[] pages = ColorSettingsPages.getInstance().getRegisteredPages();
484 for (ColorSettingsPage page : pages) {
485 initDescriptions(page, descriptions, scheme);
487 for (ColorAndFontDescriptorsProvider provider : Extensions.getExtensions(ColorAndFontDescriptorsProvider.EP_NAME)) {
488 initDescriptions(provider, descriptions, scheme);
492 private static void initDescriptions(@NotNull ColorAndFontDescriptorsProvider provider,
493 @NotNull List<EditorSchemeAttributeDescriptor> descriptions,
494 @NotNull MyColorScheme scheme) {
495 String group = provider.getDisplayName();
496 List<AttributesDescriptor> attributeDescriptors = ColorSettingsUtil.getAllAttributeDescriptors(provider);
497 for (AttributesDescriptor descriptor : attributeDescriptors) {
498 addSchemedDescription(descriptions, descriptor.getDisplayName(), group, descriptor.getKey(), scheme, null, null);
501 ColorDescriptor[] colorDescriptors = provider.getColorDescriptors();
502 for (ColorDescriptor descriptor : colorDescriptors) {
503 ColorKey back = descriptor.getKind() == ColorDescriptor.Kind.BACKGROUND ? descriptor.getKey() : null;
504 ColorKey fore = descriptor.getKind() == ColorDescriptor.Kind.FOREGROUND ? descriptor.getKey() : null;
505 addEditorSettingDescription(descriptions, descriptor.getDisplayName(), group, back, fore, scheme);
509 private static void initFileStatusDescriptors(@NotNull List<EditorSchemeAttributeDescriptor> descriptions, MyColorScheme scheme) {
511 FileStatus[] statuses = FileStatusFactory.getInstance().getAllFileStatuses();
513 for (FileStatus fileStatus : statuses) {
514 addEditorSettingDescription(descriptions,
515 fileStatus.getText(),
518 fileStatus.getColorKey(),
523 private static void initScopesDescriptors(@NotNull List<EditorSchemeAttributeDescriptor> descriptions, @NotNull MyColorScheme scheme) {
524 Set<Pair<NamedScope,NamedScopesHolder>> namedScopes = new THashSet<Pair<NamedScope,NamedScopesHolder>>(new TObjectHashingStrategy<Pair<NamedScope,NamedScopesHolder>>() {
526 public int computeHashCode(@NotNull final Pair<NamedScope, NamedScopesHolder> object) {
527 return object.getFirst().getName().hashCode();
531 public boolean equals(@NotNull final Pair<NamedScope, NamedScopesHolder> o1, @NotNull final Pair<NamedScope, NamedScopesHolder> o2) {
532 return o1.getFirst().getName().equals(o2.getFirst().getName());
535 Project[] projects = ProjectManager.getInstance().getOpenProjects();
536 for (Project project : projects) {
537 DependencyValidationManagerImpl validationManager = (DependencyValidationManagerImpl)DependencyValidationManager.getInstance(project);
538 List<Pair<NamedScope,NamedScopesHolder>> cachedScopes = validationManager.getScopeBasedHighlightingCachedScopes();
539 namedScopes.addAll(cachedScopes);
542 List<Pair<NamedScope, NamedScopesHolder>> list = new ArrayList<Pair<NamedScope, NamedScopesHolder>>(namedScopes);
544 Collections.sort(list, (o1, o2) -> o1.getFirst().getName().compareToIgnoreCase(o2.getFirst().getName()));
545 for (Pair<NamedScope,NamedScopesHolder> pair : list) {
546 NamedScope namedScope = pair.getFirst();
547 String name = namedScope.getName();
548 TextAttributesKey textAttributesKey = ScopeAttributesUtil.getScopeTextAttributeKey(name);
549 if (scheme.getAttributes(textAttributesKey) == null) {
550 scheme.setAttributes(textAttributesKey, new TextAttributes());
552 NamedScopesHolder holder = pair.getSecond();
554 PackageSet value = namedScope.getValue();
555 String toolTip = holder.getDisplayName() + (value==null ? "" : ": "+ value.getText());
556 addSchemedDescription(descriptions,
560 scheme, holder.getIcon(), toolTip);
565 private static String calcType(@Nullable ColorKey backgroundKey, @Nullable ColorKey foregroundKey) {
566 if (foregroundKey != null) {
567 return foregroundKey.getExternalName();
569 else if (backgroundKey != null) {
570 return backgroundKey.getExternalName();
575 private static void addEditorSettingDescription(@NotNull List<EditorSchemeAttributeDescriptor> list,
578 @Nullable ColorKey backgroundKey,
579 @Nullable ColorKey foregroundKey,
580 @NotNull EditorColorsScheme scheme) {
581 list.add(new EditorSettingColorDescription(name, group, backgroundKey, foregroundKey, calcType(backgroundKey, foregroundKey), scheme));
584 private static void addSchemedDescription(@NotNull List<EditorSchemeAttributeDescriptor> list,
587 @NotNull TextAttributesKey key,
588 @NotNull MyColorScheme scheme,
591 list.add(new SchemeTextAttributesDescription(name, group, key, scheme, icon, toolTip));
595 public String getDisplayName() {
596 return ApplicationBundle.message("title.colors.and.fonts");
599 private void revertChanges(){
600 if (isSchemeListModified() || isSomeSchemeModified()) {
601 myRevertChangesCompleted = false;
604 if (!myRevertChangesCompleted) {
605 ensureSchemesPanel();
612 myRevertChangesCompleted = true;
618 private void resetImpl() {
619 mySomeSchemesDeleted = false;
621 resetSchemesCombo(null);
625 public synchronized void reset() {
626 if (!myInitResetInvoked) {
628 if (!myInitResetCompleted) {
629 ensureSchemesPanel();
635 myInitResetCompleted = true;
640 myInitResetInvoked = true;
648 public synchronized void resetFromChild() {
649 if (!myInitResetCompleted) {
650 ensureSchemesPanel();
657 myInitResetCompleted = true;
663 private void ensureSchemesPanel() {
664 if (myRootSchemesPanel == null) {
665 myRootSchemesPanel = new SchemesPanel(this);
667 myRootSchemesPanel.addListener(new ColorAndFontSettingsListener.Abstract(){
669 public void schemeChanged(final Object source) {
671 resetSchemesCombo(source);
680 public void disposeUIResources() {
682 if (!myDisposeCompleted) {
684 super.disposeUIResources();
685 Disposer.dispose(myDisposable);
688 myDisposeCompleted = true;
693 mySubPanelFactories = null;
695 myInitResetCompleted = false;
696 myInitResetInvoked = false;
697 myRevertChangesCompleted = false;
699 myApplyCompleted = false;
700 myRootSchemesPanel = null;
704 private static class SchemeTextAttributesDescription extends TextAttributesDescription {
705 @NotNull private final TextAttributes myInitialAttributes;
706 @NotNull private final TextAttributesKey key;
707 private TextAttributes myFallbackAttributes;
708 private Pair<ColorSettingsPage,AttributesDescriptor> myBaseAttributeDescriptor;
709 private boolean myIsInheritedInitial = false;
711 private SchemeTextAttributesDescription(String name, String group, @NotNull TextAttributesKey key, @NotNull MyColorScheme scheme, Icon icon,
714 getInitialAttributes(scheme, key).clone(),
715 key, scheme, icon, toolTip);
717 myInitialAttributes = getInitialAttributes(scheme, key);
718 TextAttributesKey fallbackKey = key.getFallbackAttributeKey();
719 if (fallbackKey != null) {
720 myFallbackAttributes = scheme.getAttributes(fallbackKey);
721 myBaseAttributeDescriptor = ColorSettingsPages.getInstance().getAttributeDescriptor(fallbackKey);
722 if (myBaseAttributeDescriptor == null) {
723 myBaseAttributeDescriptor =
724 new Pair<ColorSettingsPage, AttributesDescriptor>(null, new AttributesDescriptor(fallbackKey.getExternalName(), fallbackKey));
727 myIsInheritedInitial = scheme.isInherited(key);
728 setInherited(myIsInheritedInitial);
729 if (myIsInheritedInitial) {
730 setInheritedAttributes(getTextAttributes());
736 private void setInheritedAttributes(@NotNull TextAttributes attributes) {
737 attributes.setFontType(myFallbackAttributes.getFontType());
738 attributes.setForegroundColor(myFallbackAttributes.getForegroundColor());
739 attributes.setBackgroundColor(myFallbackAttributes.getBackgroundColor());
740 attributes.setErrorStripeColor(myFallbackAttributes.getErrorStripeColor());
741 attributes.setEffectColor(myFallbackAttributes.getEffectColor());
742 attributes.setEffectType(myFallbackAttributes.getEffectType());
747 private static TextAttributes getInitialAttributes(@NotNull MyColorScheme scheme, @NotNull TextAttributesKey key) {
748 TextAttributes attributes = scheme.getAttributes(key);
749 return attributes != null ? attributes : new TextAttributes();
753 public void apply(EditorColorsScheme scheme) {
754 if (scheme == null) scheme = getScheme();
755 scheme.setAttributes(key, isInherited() ? new TextAttributes() : getTextAttributes());
759 public boolean isModified() {
761 return !myIsInheritedInitial;
763 return !Comparing.equal(myInitialAttributes, getTextAttributes()) || myIsInheritedInitial;
767 public boolean isErrorStripeEnabled() {
773 public TextAttributes getBaseAttributes() {
774 return myFallbackAttributes;
779 public Pair<ColorSettingsPage,AttributesDescriptor> getBaseAttributeDescriptor() {
780 return myBaseAttributeDescriptor;
784 public void setInherited(boolean isInherited) {
785 super.setInherited(isInherited);
789 private static class GetSetColor {
790 private final ColorKey myKey;
791 private final EditorColorsScheme myScheme;
792 private boolean isModified = false;
793 private Color myColor;
795 private GetSetColor(ColorKey key, EditorColorsScheme scheme) {
798 myColor = myScheme.getColor(myKey);
801 public Color getColor() {
805 public void setColor(Color col) {
806 if (getColor() == null || !getColor().equals(col)) {
812 public void apply(EditorColorsScheme scheme) {
813 if (scheme == null) scheme = myScheme;
814 scheme.setColor(myKey, myColor);
817 public boolean isModified() {
822 private static class EditorSettingColorDescription extends ColorAndFontDescription {
823 private GetSetColor myGetSetForeground;
824 private GetSetColor myGetSetBackground;
826 private EditorSettingColorDescription(String name,
828 ColorKey backgroundKey,
829 ColorKey foregroundKey,
831 EditorColorsScheme scheme) {
832 super(name, group, type, scheme, null, null);
833 if (backgroundKey != null) {
834 myGetSetBackground = new GetSetColor(backgroundKey, scheme);
836 if (foregroundKey != null) {
837 myGetSetForeground = new GetSetColor(foregroundKey, scheme);
843 public int getFontType() {
848 public void setFontType(int type) {
852 public Color getExternalEffectColor() {
857 public void setExternalEffectColor(Color color) {
861 public void setExternalEffectType(EffectType type) {
866 public EffectType getExternalEffectType() {
867 return EffectType.LINE_UNDERSCORE;
871 public Color getExternalForeground() {
872 if (myGetSetForeground == null) {
875 return myGetSetForeground.getColor();
879 public void setExternalForeground(Color col) {
880 if (myGetSetForeground == null) {
883 myGetSetForeground.setColor(col);
887 public Color getExternalBackground() {
888 if (myGetSetBackground == null) {
891 return myGetSetBackground.getColor();
895 public void setExternalBackground(Color col) {
896 if (myGetSetBackground == null) {
899 myGetSetBackground.setColor(col);
903 public Color getExternalErrorStripe() {
908 public void setExternalErrorStripe(Color col) {
912 public boolean isFontEnabled() {
917 public boolean isForegroundEnabled() {
918 return myGetSetForeground != null;
922 public boolean isBackgroundEnabled() {
923 return myGetSetBackground != null;
927 public boolean isEffectsColorEnabled() {
932 public boolean isModified() {
933 return myGetSetBackground != null && myGetSetBackground.isModified()
934 || myGetSetForeground != null && myGetSetForeground.isModified();
938 public void apply(EditorColorsScheme scheme) {
939 if (myGetSetBackground != null) {
940 myGetSetBackground.apply(scheme);
942 if (myGetSetForeground != null) {
943 myGetSetForeground.apply(scheme);
950 public String getHelpTopic() {
954 private static class MyColorScheme extends EditorColorsSchemeImpl {
955 private EditorSchemeAttributeDescriptor[] myDescriptors;
956 private String myName;
957 private boolean myIsNew = false;
959 private MyColorScheme(@NotNull EditorColorsScheme parentScheme) {
962 parentScheme.getFontPreferences().copyTo(getFontPreferences());
963 setLineSpacing(parentScheme.getLineSpacing());
965 parentScheme.getConsoleFontPreferences().copyTo(getConsoleFontPreferences());
966 setConsoleLineSpacing(parentScheme.getConsoleLineSpacing());
968 setQuickDocFontSize(parentScheme.getQuickDocFontSize());
969 myName = parentScheme.getName();
975 public String getName() {
980 public void setName(@NotNull String name) {
984 public void setDescriptors(EditorSchemeAttributeDescriptor[] descriptors) {
985 myDescriptors = descriptors;
988 public EditorSchemeAttributeDescriptor[] getDescriptors() {
989 return myDescriptors;
992 public boolean isDefault() {
993 return myParentScheme instanceof DefaultColorsScheme;
997 public boolean isReadOnly() {
998 return myParentScheme instanceof ReadOnlyColorsScheme;
1001 public boolean isModified() {
1002 if (isFontModified() || isConsoleFontModified()) return true;
1004 for (EditorSchemeAttributeDescriptor descriptor : myDescriptors) {
1005 if (descriptor.isModified()) {
1013 private boolean isFontModified() {
1014 if (!getFontPreferences().equals(myParentScheme.getFontPreferences())) return true;
1015 if (getLineSpacing() != myParentScheme.getLineSpacing()) return true;
1016 return getQuickDocFontSize() != myParentScheme.getQuickDocFontSize();
1019 private boolean isConsoleFontModified() {
1020 if (!getConsoleFontPreferences().equals(myParentScheme.getConsoleFontPreferences())) return true;
1021 return getConsoleLineSpacing() != myParentScheme.getConsoleLineSpacing();
1024 public void apply() {
1025 if (!(myParentScheme instanceof ReadOnlyColorsScheme)) {
1026 apply(myParentScheme);
1030 public void apply(@NotNull EditorColorsScheme scheme) {
1031 scheme.setFontPreferences(getFontPreferences());
1032 scheme.setLineSpacing(myLineSpacing);
1033 scheme.setQuickDocFontSize(getQuickDocFontSize());
1034 scheme.setConsoleFontPreferences(getConsoleFontPreferences());
1035 scheme.setConsoleLineSpacing(getConsoleLineSpacing());
1037 for (EditorSchemeAttributeDescriptor descriptor : myDescriptors) {
1038 descriptor.apply(scheme);
1041 if (scheme instanceof AbstractColorsScheme) {
1042 ((AbstractColorsScheme)scheme).setSaveNeeded(true);
1047 public Object clone() {
1052 public EditorColorsScheme getOriginalScheme() {
1053 return myParentScheme;
1056 public void setIsNew() {
1060 public boolean isNew() {
1066 public String toString() {
1067 return "temporary scheme for " + myName;
1070 public boolean isInherited(TextAttributesKey key) {
1071 TextAttributesKey fallbackKey = key.getFallbackAttributeKey();
1072 if (fallbackKey != null) {
1073 if (myParentScheme instanceof AbstractColorsScheme) {
1074 TextAttributes ownAttrs = ((AbstractColorsScheme)myParentScheme).getDirectlyDefinedAttributes(key);
1075 if (ownAttrs != null) {
1076 return ownAttrs.isFallbackEnabled();
1079 TextAttributes attributes = getAttributes(key);
1080 if (attributes != null) {
1081 TextAttributes fallbackAttributes = getAttributes(fallbackKey);
1082 return attributes == fallbackAttributes;
1091 public String getId() {
1092 return getHelpTopic();
1097 public Runnable enableSearch(final String option) {
1102 public SearchableConfigurable findSubConfigurable(@NotNull Class pageClass) {
1103 if (mySubPanelFactories == null) {
1104 buildConfigurables();
1106 for (Map.Entry<ColorAndFontPanelFactory, InnerSearchableConfigurable> entry : mySubPanelFactories.entrySet()) {
1107 if (pageClass.isInstance(entry.getValue().createPanel().getSettingsPage())) {
1108 return entry.getValue();
1115 public SearchableConfigurable findSubConfigurable(String pageName) {
1116 if (mySubPanelFactories == null) {
1117 buildConfigurables();
1119 for (InnerSearchableConfigurable configurable : mySubPanelFactories.values()) {
1120 if (configurable.getDisplayName().equals(pageName)) {
1121 return configurable;
1128 public NewColorAndFontPanel findPage(String pageName) {
1129 InnerSearchableConfigurable child = (InnerSearchableConfigurable)findSubConfigurable(pageName);
1130 return child == null ? null : child.createPanel();
1133 private class InnerSearchableConfigurable implements SearchableConfigurable, OptionsContainingConfigurable, NoScroll {
1134 private NewColorAndFontPanel mySubPanel;
1135 private boolean mySubInitInvoked = false;
1136 @NotNull private final ColorAndFontPanelFactory myFactory;
1138 private InnerSearchableConfigurable(@NotNull ColorAndFontPanelFactory factory) {
1139 myFactory = factory;
1145 public String getDisplayName() {
1146 return myFactory.getPanelDisplayName();
1149 public NewColorAndFontPanel getSubPanelIfInitialized() {
1153 private NewColorAndFontPanel createPanel() {
1154 if (mySubPanel == null) {
1155 mySubPanel = myFactory.createPanel(ColorAndFontOptions.this);
1156 mySubPanel.reset(this);
1157 mySubPanel.addSchemesListener(new ColorAndFontSettingsListener.Abstract(){
1159 public void schemeChanged(final Object source) {
1161 resetSchemesCombo(source);
1166 mySubPanel.addDescriptionListener(new ColorAndFontSettingsListener.Abstract(){
1168 public void fontChanged() {
1169 for (NewColorAndFontPanel panel : getPanels()) {
1170 panel.updatePreview();
1179 public String getHelpTopic() {
1184 public JComponent createComponent() {
1185 return createPanel().getPanel();
1189 public boolean isModified() {
1191 for (MyColorScheme scheme : mySchemes.values()) {
1192 if (mySubPanel.containsFontOptions()) {
1193 if (scheme.isFontModified() || scheme.isConsoleFontModified()) {
1194 myRevertChangesCompleted = false;
1199 for (EditorSchemeAttributeDescriptor descriptor : scheme.getDescriptors()) {
1200 if (mySubPanel.contains(descriptor) && descriptor.isModified()) {
1201 myRevertChangesCompleted = false;
1214 public void apply() throws ConfigurationException {
1215 ColorAndFontOptions.this.apply();
1219 public void reset() {
1220 if (!mySubInitInvoked) {
1221 if (!myInitResetCompleted) {
1224 mySubInitInvoked = true;
1232 public void disposeUIResources() {
1233 if (mySubPanel != null) {
1234 mySubPanel.disposeUIResources();
1241 public String getId() {
1242 return ColorAndFontOptions.this.getId() + "." + getDisplayName();
1246 public Runnable enableSearch(final String option) {
1247 return createPanel().showOption(option);
1252 public Set<String> processListOptions() {
1253 return createPanel().processListOptions();
1259 public String toString() {
1260 return "Color And Fonts for "+getDisplayName();