blob: ce2a00d3d6711411485bcf0fc856af7e4456e7a7 [file] [log] [blame]
/*
* 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.application.options.colors;
import com.intellij.application.options.OptionsContainingConfigurable;
import com.intellij.application.options.editor.EditorOptionsProvider;
import com.intellij.codeInsight.daemon.DaemonCodeAnalyzer;
import com.intellij.execution.impl.ConsoleViewUtil;
import com.intellij.ide.bookmarks.BookmarkManager;
import com.intellij.ide.todo.TodoConfiguration;
import com.intellij.ide.ui.LafManager;
import com.intellij.ide.ui.laf.darcula.DarculaInstaller;
import com.intellij.ide.ui.laf.darcula.DarculaLaf;
import com.intellij.ide.ui.laf.darcula.DarculaLookAndFeelInfo;
import com.intellij.openapi.Disposable;
import com.intellij.openapi.application.ApplicationBundle;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.diff.impl.settings.DiffOptionsPanel;
import com.intellij.openapi.diff.impl.settings.DiffPreviewPanel;
import com.intellij.openapi.editor.EditorFactory;
import com.intellij.openapi.editor.colors.ColorKey;
import com.intellij.openapi.editor.colors.EditorColorsManager;
import com.intellij.openapi.editor.colors.EditorColorsScheme;
import com.intellij.openapi.editor.colors.TextAttributesKey;
import com.intellij.openapi.editor.colors.ex.DefaultColorSchemesManager;
import com.intellij.openapi.editor.colors.impl.DefaultColorsScheme;
import com.intellij.openapi.editor.colors.impl.EditorColorsSchemeImpl;
import com.intellij.openapi.editor.colors.impl.ReadOnlyColorsScheme;
import com.intellij.openapi.editor.markup.EffectType;
import com.intellij.openapi.editor.markup.TextAttributes;
import com.intellij.openapi.extensions.Extensions;
import com.intellij.openapi.options.Configurable;
import com.intellij.openapi.options.ConfigurationException;
import com.intellij.openapi.options.ExternalizableScheme;
import com.intellij.openapi.options.SearchableConfigurable;
import com.intellij.openapi.options.colors.*;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.project.ProjectManager;
import com.intellij.openapi.ui.Messages;
import com.intellij.openapi.util.Comparing;
import com.intellij.openapi.util.Disposer;
import com.intellij.openapi.util.Pair;
import com.intellij.openapi.vcs.FileStatus;
import com.intellij.openapi.vcs.FileStatusFactory;
import com.intellij.openapi.vcs.FileStatusManager;
import com.intellij.packageDependencies.DependencyValidationManager;
import com.intellij.packageDependencies.DependencyValidationManagerImpl;
import com.intellij.psi.codeStyle.DisplayPriority;
import com.intellij.psi.codeStyle.DisplayPrioritySortable;
import com.intellij.psi.search.scope.packageSet.NamedScope;
import com.intellij.psi.search.scope.packageSet.NamedScopesHolder;
import com.intellij.psi.search.scope.packageSet.PackageSet;
import com.intellij.util.ArrayUtil;
import com.intellij.util.containers.HashMap;
import com.intellij.util.diff.FilesTooBigForDiffException;
import com.intellij.util.ui.UIUtil;
import gnu.trove.THashSet;
import gnu.trove.TObjectHashingStrategy;
import org.jetbrains.annotations.Nls;
import org.jetbrains.annotations.NonNls;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import javax.swing.*;
import java.awt.*;
import java.util.*;
import java.util.List;
public class ColorAndFontOptions extends SearchableConfigurable.Parent.Abstract implements EditorOptionsProvider {
public static final String ID = "reference.settingsdialog.IDE.editor.colors";
private HashMap<String,MyColorScheme> mySchemes;
private MyColorScheme mySelectedScheme;
public static final String DIFF_GROUP = ApplicationBundle.message("title.diff");
public static final String FILE_STATUS_GROUP = ApplicationBundle.message("title.file.status");
public static final String SCOPES_GROUP = ApplicationBundle.message("title.scope.based");
private boolean mySomeSchemesDeleted = false;
private Map<ColorAndFontPanelFactory, InnerSearchableConfigurable> mySubPanelFactories;
private SchemesPanel myRootSchemesPanel;
private boolean myInitResetCompleted = false;
private boolean myInitResetInvoked = false;
private boolean myRevertChangesCompleted = false;
private boolean myApplyCompleted = false;
private boolean myDisposeCompleted = false;
private final Disposable myDisposable = Disposer.newDisposable();
private static final Logger LOG = Logger.getInstance("#com.intellij.application.options.colors.ColorAndFontOptions");
@Override
public boolean isModified() {
boolean listModified = isSchemeListModified();
boolean schemeModified = isSomeSchemeModified();
if (listModified || schemeModified) {
myApplyCompleted = false;
}
return listModified;
}
private boolean isSchemeListModified(){
if (mySomeSchemesDeleted) return true;
if (!mySelectedScheme.getName().equals(EditorColorsManager.getInstance().getGlobalScheme().getName())) return true;
for (MyColorScheme scheme : mySchemes.values()) {
if (scheme.isNew()) return true;
}
return false;
}
private boolean isSomeSchemeModified() {
for (MyColorScheme scheme : mySchemes.values()) {
if (scheme.isModified()) return true;
}
return false;
}
public EditorColorsScheme selectScheme(@NotNull String name) {
mySelectedScheme = getScheme(name);
return mySelectedScheme;
}
private MyColorScheme getScheme(String name) {
return mySchemes.get(name);
}
public EditorColorsScheme getSelectedScheme() {
return mySelectedScheme;
}
public EditorColorsScheme getOriginalSelectedScheme() {
return mySelectedScheme == null ? null : mySelectedScheme.getOriginalScheme();
}
public EditorSchemeAttributeDescriptor[] getCurrentDescriptions() {
return mySelectedScheme.getDescriptors();
}
public static boolean isReadOnly(@NotNull final EditorColorsScheme scheme) {
return ((MyColorScheme)scheme).isReadOnly();
}
@NotNull
public String[] getSchemeNames() {
List<MyColorScheme> schemes = new ArrayList<MyColorScheme>(mySchemes.values());
Collections.sort(schemes, new Comparator<MyColorScheme>() {
@Override
public int compare(@NotNull MyColorScheme o1, @NotNull MyColorScheme o2) {
if (isReadOnly(o1) && !isReadOnly(o2)) return -1;
if (!isReadOnly(o1) && isReadOnly(o2)) return 1;
return o1.getName().compareToIgnoreCase(o2.getName());
}
});
List<String> names = new ArrayList<String>(schemes.size());
for (MyColorScheme scheme : schemes) {
names.add(scheme.getName());
}
return ArrayUtil.toStringArray(names);
}
@NotNull
public Collection<EditorColorsScheme> getSchemes() {
return new ArrayList<EditorColorsScheme>(mySchemes.values());
}
public void saveSchemeAs(String name) {
MyColorScheme scheme = mySelectedScheme;
if (scheme == null) return;
EditorColorsScheme clone = (EditorColorsScheme)scheme.getOriginalScheme().clone();
scheme.apply(clone);
clone.setName(name);
MyColorScheme newScheme = new MyColorScheme(clone);
initScheme(newScheme);
newScheme.setIsNew();
mySchemes.put(name, newScheme);
selectScheme(newScheme.getName());
resetSchemesCombo(null);
}
public void addImportedScheme(@NotNull final EditorColorsScheme imported) {
MyColorScheme newScheme = new MyColorScheme(imported);
initScheme(newScheme);
mySchemes.put(imported.getName(), newScheme);
selectScheme(newScheme.getName());
resetSchemesCombo(null);
}
public void removeScheme(String name) {
if (mySelectedScheme.getName().equals(name)) {
//noinspection HardCodedStringLiteral
selectScheme("Default");
}
boolean deletedNewlyCreated = false;
MyColorScheme toDelete = mySchemes.get(name);
if (toDelete != null) {
deletedNewlyCreated = toDelete.isNew();
}
mySchemes.remove(name);
resetSchemesCombo(null);
mySomeSchemesDeleted = mySomeSchemesDeleted || !deletedNewlyCreated;
}
@Override
public void apply() throws ConfigurationException {
if (myApplyCompleted) {
return;
}
try {
EditorColorsManager myColorsManager = EditorColorsManager.getInstance();
myColorsManager.removeAllSchemes();
for (MyColorScheme scheme : mySchemes.values()) {
if (!scheme.isDefault()) {
scheme.apply();
myColorsManager.addColorsScheme(scheme.getOriginalScheme());
}
}
EditorColorsScheme originalScheme = mySelectedScheme.getOriginalScheme();
myColorsManager.setGlobalScheme(originalScheme);
if (originalScheme != null && DarculaLaf.NAME.equals(originalScheme.getName()) && !UIUtil.isUnderDarcula()) {
int ok = Messages.showYesNoDialog(
"Darcula color scheme has been set for editors. Would you like to set Darcula as default Look and Feel?",
"Darcula Look and Feel",
Messages.getQuestionIcon());
if (ok == Messages.YES) {
LafManager.getInstance().setCurrentLookAndFeel(new DarculaLookAndFeelInfo());
DarculaInstaller.install();
}
}
applyChangesToEditors();
reset();
}
finally {
myApplyCompleted = true;
}
}
private static void applyChangesToEditors() {
EditorFactory.getInstance().refreshAllEditors();
TodoConfiguration.getInstance().colorSettingsChanged();
Project[] openProjects = ProjectManager.getInstance().getOpenProjects();
for (Project openProject : openProjects) {
FileStatusManager.getInstance(openProject).fileStatusesChanged();
DaemonCodeAnalyzer.getInstance(openProject).restart();
BookmarkManager.getInstance(openProject).colorsChanged();
}
}
private boolean myIsReset = false;
private void resetSchemesCombo(Object source) {
myIsReset = true;
try {
myRootSchemesPanel.resetSchemesCombo(source);
if (mySubPanelFactories != null) {
for (NewColorAndFontPanel subPartialConfigurable : getPanels()) {
subPartialConfigurable.reset(source);
}
}
}
finally {
myIsReset = false;
}
}
@Override
public JComponent createComponent() {
if (myRootSchemesPanel == null) {
ensureSchemesPanel();
}
return myRootSchemesPanel;
}
@Override
public boolean hasOwnContent() {
return true;
}
@NotNull
@Override
public Configurable[] buildConfigurables() {
myDisposeCompleted = false;
initAll();
List<ColorAndFontPanelFactory> panelFactories = createPanelFactories();
List<Configurable> result = new ArrayList<Configurable>();
mySubPanelFactories = new LinkedHashMap<ColorAndFontPanelFactory, InnerSearchableConfigurable>(panelFactories.size());
for (ColorAndFontPanelFactory panelFactory : panelFactories) {
mySubPanelFactories.put(panelFactory, new InnerSearchableConfigurable(panelFactory));
}
result.addAll(new ArrayList<SearchableConfigurable>(mySubPanelFactories.values()));
return result.toArray(new Configurable[result.size()]);
}
@NotNull
private Set<NewColorAndFontPanel> getPanels() {
Set<NewColorAndFontPanel> result = new HashSet<NewColorAndFontPanel>();
for (InnerSearchableConfigurable configurable : mySubPanelFactories.values()) {
NewColorAndFontPanel panel = configurable.getSubPanelIfInitialized();
if (panel != null) {
result.add(panel);
}
}
return result;
}
protected List<ColorAndFontPanelFactory> createPanelFactories() {
List<ColorAndFontPanelFactory> result = new ArrayList<ColorAndFontPanelFactory>();
result.add(new FontConfigurableFactory());
List<ColorAndFontPanelFactory> extensions = new ArrayList<ColorAndFontPanelFactory>();
extensions.add(new ConsoleFontConfigurableFactory());
ColorSettingsPage[] pages = ColorSettingsPages.getInstance().getRegisteredPages();
for (final ColorSettingsPage page : pages) {
extensions.add(new ColorAndFontPanelFactoryEx() {
@Override
@NotNull
public NewColorAndFontPanel createPanel(@NotNull ColorAndFontOptions options) {
final SimpleEditorPreview preview = new SimpleEditorPreview(options, page);
return NewColorAndFontPanel.create(preview, page.getDisplayName(), options, null, page);
}
@Override
@NotNull
public String getPanelDisplayName() {
return page.getDisplayName();
}
@Override
public DisplayPriority getPriority() {
if (page instanceof DisplayPrioritySortable) {
return ((DisplayPrioritySortable)page).getPriority();
}
return DisplayPriority.LANGUAGE_SETTINGS;
}
});
}
Collections.addAll(extensions, Extensions.getExtensions(ColorAndFontPanelFactory.EP_NAME));
Collections.sort(extensions, new Comparator<ColorAndFontPanelFactory>() {
@Override
public int compare(ColorAndFontPanelFactory f1, ColorAndFontPanelFactory f2) {
if (f1 instanceof DisplayPrioritySortable) {
if (f2 instanceof DisplayPrioritySortable) {
int result = ((DisplayPrioritySortable)f1).getPriority().compareTo(((DisplayPrioritySortable)f2).getPriority());
if (result != 0) return result;
}
else {
return 1;
}
}
else if (f2 instanceof DisplayPrioritySortable) {
return -1;
}
return f1.getPanelDisplayName().compareToIgnoreCase(f2.getPanelDisplayName());
}
});
result.addAll(extensions);
result.add(new DiffColorsPageFactory());
result.add(new FileStatusColorsPageFactory());
result.add(new ScopeColorsPageFactory());
return result;
}
private static class FontConfigurableFactory implements ColorAndFontPanelFactory {
@Override
@NotNull
public NewColorAndFontPanel createPanel(@NotNull ColorAndFontOptions options) {
FontEditorPreview previewPanel = new FontEditorPreview(options, true);
return new NewColorAndFontPanel(new SchemesPanel(options), new FontOptions(options), previewPanel, "Font", null, null){
@Override
public boolean containsFontOptions() {
return true;
}
};
}
@Override
@NotNull
public String getPanelDisplayName() {
return "Font";
}
}
private static class ConsoleFontConfigurableFactory implements ColorAndFontPanelFactoryEx {
@Override
@NotNull
public NewColorAndFontPanel createPanel(@NotNull ColorAndFontOptions options) {
FontEditorPreview previewPanel = new FontEditorPreview(options, false) {
@Override
protected EditorColorsScheme updateOptionsScheme(EditorColorsScheme selectedScheme) {
return ConsoleViewUtil.updateConsoleColorScheme(selectedScheme);
}
};
return new NewColorAndFontPanel(new SchemesPanel(options), new ConsoleFontOptions(options), previewPanel, "Font", null, null){
@Override
public boolean containsFontOptions() {
return true;
}
};
}
@Override
@NotNull
public String getPanelDisplayName() {
return "Console Font";
}
@NotNull
@Override
public DisplayPriority getPriority() {
return DisplayPriority.COMMON_SETTINGS;
}
}
private class DiffColorsPageFactory implements ColorAndFontPanelFactory {
@Override
@NotNull
public NewColorAndFontPanel createPanel(@NotNull ColorAndFontOptions options) {
final DiffOptionsPanel optionsPanel = new DiffOptionsPanel(options);
SchemesPanel schemesPanel = new SchemesPanel(options);
PreviewPanel previewPanel;
try {
final DiffPreviewPanel diffPreviewPanel = new DiffPreviewPanel(myDisposable);
diffPreviewPanel.setMergeRequest(null);
schemesPanel.addListener(new ColorAndFontSettingsListener.Abstract(){
@Override
public void schemeChanged(final Object source) {
diffPreviewPanel.setColorScheme(getSelectedScheme());
optionsPanel.updateOptionsList();
diffPreviewPanel.updateView();
}
} );
previewPanel = diffPreviewPanel;
}
catch (FilesTooBigForDiffException e) {
LOG.info(e);
previewPanel = new PreviewPanel.Empty();
}
return new NewColorAndFontPanel(schemesPanel, optionsPanel, previewPanel, DIFF_GROUP, null, null);
}
@Override
@NotNull
public String getPanelDisplayName() {
return DIFF_GROUP;
}
}
private void initAll() {
EditorColorsManager colorsManager = EditorColorsManager.getInstance();
EditorColorsScheme[] allSchemes = colorsManager.getAllSchemes();
mySchemes = new HashMap<String, MyColorScheme>();
for (EditorColorsScheme allScheme : allSchemes) {
MyColorScheme schemeDelegate = new MyColorScheme(allScheme);
initScheme(schemeDelegate);
mySchemes.put(schemeDelegate.getName(), schemeDelegate);
}
mySelectedScheme = mySchemes.get(EditorColorsManager.getInstance().getGlobalScheme().getName());
assert mySelectedScheme != null : EditorColorsManager.getInstance().getGlobalScheme().getName() + "; myschemes=" + mySchemes;
}
private static void initScheme(@NotNull MyColorScheme scheme) {
List<EditorSchemeAttributeDescriptor> descriptions = new ArrayList<EditorSchemeAttributeDescriptor>();
initPluggedDescriptions(descriptions, scheme);
initDiffDescriptors(descriptions, scheme);
initFileStatusDescriptors(descriptions, scheme);
initScopesDescriptors(descriptions, scheme);
scheme.setDescriptors(descriptions.toArray(new EditorSchemeAttributeDescriptor[descriptions.size()]));
}
private static void initPluggedDescriptions(@NotNull List<EditorSchemeAttributeDescriptor> descriptions, @NotNull MyColorScheme scheme) {
ColorSettingsPage[] pages = ColorSettingsPages.getInstance().getRegisteredPages();
for (ColorSettingsPage page : pages) {
initDescriptions(page, descriptions, scheme);
}
for (ColorAndFontDescriptorsProvider provider : Extensions.getExtensions(ColorAndFontDescriptorsProvider.EP_NAME)) {
initDescriptions(provider, descriptions, scheme);
}
}
private static void initDescriptions(@NotNull ColorAndFontDescriptorsProvider provider,
@NotNull List<EditorSchemeAttributeDescriptor> descriptions,
@NotNull MyColorScheme scheme) {
String group = provider.getDisplayName();
List<AttributesDescriptor> attributeDescriptors = ColorSettingsUtil.getAllAttributeDescriptors(provider);
for (AttributesDescriptor descriptor : attributeDescriptors) {
addSchemedDescription(descriptions, descriptor.getDisplayName(), group, descriptor.getKey(), scheme, null, null);
}
ColorDescriptor[] colorDescriptors = provider.getColorDescriptors();
for (ColorDescriptor descriptor : colorDescriptors) {
ColorKey back = descriptor.getKind() == ColorDescriptor.Kind.BACKGROUND ? descriptor.getKey() : null;
ColorKey fore = descriptor.getKind() == ColorDescriptor.Kind.FOREGROUND ? descriptor.getKey() : null;
addEditorSettingDescription(descriptions, descriptor.getDisplayName(), group, back, fore, scheme);
}
}
private static void initDiffDescriptors(@NotNull List<EditorSchemeAttributeDescriptor> descriptions, @NotNull MyColorScheme scheme) {
DiffOptionsPanel.addSchemeDescriptions(descriptions, scheme);
}
private static void initFileStatusDescriptors(@NotNull List<EditorSchemeAttributeDescriptor> descriptions, MyColorScheme scheme) {
FileStatus[] statuses = FileStatusFactory.getInstance().getAllFileStatuses();
for (FileStatus fileStatus : statuses) {
addEditorSettingDescription(descriptions,
fileStatus.getText(),
FILE_STATUS_GROUP,
null,
fileStatus.getColorKey(),
scheme);
}
}
private static void initScopesDescriptors(@NotNull List<EditorSchemeAttributeDescriptor> descriptions, @NotNull MyColorScheme scheme) {
Set<Pair<NamedScope,NamedScopesHolder>> namedScopes = new THashSet<Pair<NamedScope,NamedScopesHolder>>(new TObjectHashingStrategy<Pair<NamedScope,NamedScopesHolder>>() {
@Override
public int computeHashCode(@NotNull final Pair<NamedScope, NamedScopesHolder> object) {
return object.getFirst().getName().hashCode();
}
@Override
public boolean equals(@NotNull final Pair<NamedScope, NamedScopesHolder> o1, @NotNull final Pair<NamedScope, NamedScopesHolder> o2) {
return o1.getFirst().getName().equals(o2.getFirst().getName());
}
});
Project[] projects = ProjectManager.getInstance().getOpenProjects();
for (Project project : projects) {
DependencyValidationManagerImpl validationManager = (DependencyValidationManagerImpl)DependencyValidationManager.getInstance(project);
List<Pair<NamedScope,NamedScopesHolder>> cachedScopes = validationManager.getScopeBasedHighlightingCachedScopes();
namedScopes.addAll(cachedScopes);
}
List<Pair<NamedScope, NamedScopesHolder>> list = new ArrayList<Pair<NamedScope, NamedScopesHolder>>(namedScopes);
Collections.sort(list, new Comparator<Pair<NamedScope,NamedScopesHolder>>() {
@Override
public int compare(@NotNull final Pair<NamedScope,NamedScopesHolder> o1, @NotNull final Pair<NamedScope,NamedScopesHolder> o2) {
return o1.getFirst().getName().compareToIgnoreCase(o2.getFirst().getName());
}
});
for (Pair<NamedScope,NamedScopesHolder> pair : list) {
NamedScope namedScope = pair.getFirst();
String name = namedScope.getName();
TextAttributesKey textAttributesKey = ScopeAttributesUtil.getScopeTextAttributeKey(name);
if (scheme.getAttributes(textAttributesKey) == null) {
scheme.setAttributes(textAttributesKey, new TextAttributes());
}
NamedScopesHolder holder = pair.getSecond();
PackageSet value = namedScope.getValue();
String toolTip = holder.getDisplayName() + (value==null ? "" : ": "+ value.getText());
addSchemedDescription(descriptions,
name,
SCOPES_GROUP,
textAttributesKey,
scheme, holder.getIcon(), toolTip);
}
}
private static void addEditorSettingDescription(@NotNull List<EditorSchemeAttributeDescriptor> array,
String name,
String group,
@Nullable ColorKey backgroundKey,
@Nullable ColorKey foregroundKey,
EditorColorsScheme scheme) {
String type = null;
if (foregroundKey != null) {
type = foregroundKey.getExternalName();
}
else {
if (backgroundKey != null) {
type = backgroundKey.getExternalName();
}
}
ColorAndFontDescription descr = new EditorSettingColorDescription(name, group, backgroundKey, foregroundKey, type, scheme);
array.add(descr);
}
private static void addSchemedDescription(@NotNull List<EditorSchemeAttributeDescriptor> array,
String name,
String group,
@NotNull TextAttributesKey key,
@NotNull MyColorScheme scheme,
Icon icon,
String toolTip) {
ColorAndFontDescription descr = new SchemeTextAttributesDescription(name, group, key, scheme, icon, toolTip);
array.add(descr);
}
@Override
public String getDisplayName() {
return ApplicationBundle.message("title.colors.and.fonts");
}
private void revertChanges(){
if (isSchemeListModified() || isSomeSchemeModified()) {
myRevertChangesCompleted = false;
}
if (!myRevertChangesCompleted) {
ensureSchemesPanel();
try {
resetImpl();
}
finally {
myRevertChangesCompleted = true;
}
}
}
private void resetImpl() {
mySomeSchemesDeleted = false;
initAll();
resetSchemesCombo(null);
}
@Override
public synchronized void reset() {
if (!myInitResetInvoked) {
try {
super.reset();
if (!myInitResetCompleted) {
ensureSchemesPanel();
try {
resetImpl();
}
finally {
myInitResetCompleted = true;
}
}
}
finally {
myInitResetInvoked = true;
}
}
else {
revertChanges();
}
}
public synchronized void resetFromChild() {
if (!myInitResetCompleted) {
ensureSchemesPanel();
try {
resetImpl();
}
finally {
myInitResetCompleted = true;
}
}
}
private void ensureSchemesPanel() {
if (myRootSchemesPanel == null) {
myRootSchemesPanel = new SchemesPanel(this);
myRootSchemesPanel.addListener(new ColorAndFontSettingsListener.Abstract(){
@Override
public void schemeChanged(final Object source) {
if (!myIsReset) {
resetSchemesCombo(source);
}
}
});
}
}
@Override
public void disposeUIResources() {
try {
if (!myDisposeCompleted) {
try {
super.disposeUIResources();
Disposer.dispose(myDisposable);
if (myRootSchemesPanel != null) {
myRootSchemesPanel.disposeUIResources();
}
}
finally {
myDisposeCompleted = true;
}
}
}
finally {
mySubPanelFactories = null;
myInitResetCompleted = false;
myInitResetInvoked = false;
myRevertChangesCompleted = false;
myApplyCompleted = false;
myRootSchemesPanel = null;
}
}
public boolean currentSchemeIsReadOnly() {
return isReadOnly(mySelectedScheme);
}
public boolean currentSchemeIsShared() {
return ColorSettingsUtil.isSharedScheme(mySelectedScheme);
}
private static class SchemeTextAttributesDescription extends TextAttributesDescription {
@NotNull private final TextAttributes myAttributesToApply;
@NotNull private final TextAttributesKey key;
private TextAttributes myFallbackAttributes;
private Pair<ColorSettingsPage,AttributesDescriptor> myBaseAttributeDescriptor;
private boolean myIsInheritedInitial = false;
private SchemeTextAttributesDescription(String name, String group, @NotNull TextAttributesKey key, @NotNull MyColorScheme scheme, Icon icon,
String toolTip) {
super(name, group,
getInitialAttributes(scheme, key).clone(),
key, scheme, icon, toolTip);
this.key = key;
myAttributesToApply = getInitialAttributes(scheme, key);
TextAttributesKey fallbackKey = key.getFallbackAttributeKey();
if (fallbackKey != null) {
myFallbackAttributes = scheme.getAttributes(fallbackKey);
myBaseAttributeDescriptor = ColorSettingsPages.getInstance().getAttributeDescriptor(fallbackKey);
if (myBaseAttributeDescriptor == null) {
myBaseAttributeDescriptor =
new Pair<ColorSettingsPage, AttributesDescriptor>(null, new AttributesDescriptor(fallbackKey.getExternalName(), fallbackKey));
}
}
myIsInheritedInitial = isInherited(scheme);
setInherited(myIsInheritedInitial);
initCheckedStatus();
}
@NotNull
private static TextAttributes getInitialAttributes(@NotNull MyColorScheme scheme, @NotNull TextAttributesKey key) {
TextAttributes attributes = scheme.getAttributes(key);
return attributes != null ? attributes : new TextAttributes();
}
private boolean isInherited(@NotNull MyColorScheme scheme) {
TextAttributes attributes = scheme.getAttributes(key);
TextAttributesKey fallbackKey = key.getFallbackAttributeKey();
if (fallbackKey != null && !scheme.containsKey(key)) {
TextAttributes fallbackAttributes = scheme.getAttributes(fallbackKey);
if (attributes != null && attributes == fallbackAttributes) {
return true;
}
}
return false;
}
@Override
public void apply(EditorColorsScheme scheme) {
if (scheme == null) scheme = getScheme();
scheme.setAttributes(key, isInherited() ? new TextAttributes() : getTextAttributes());
}
@Override
public boolean isModified() {
return !Comparing.equal(myAttributesToApply, getTextAttributes()) || myIsInheritedInitial != isInherited();
}
@Override
public boolean isErrorStripeEnabled() {
return true;
}
@Nullable
@Override
public TextAttributes getBaseAttributes() {
return myFallbackAttributes;
}
@Nullable
@Override
public Pair<ColorSettingsPage,AttributesDescriptor> getBaseAttributeDescriptor() {
return myBaseAttributeDescriptor;
}
@Override
public void setInherited(boolean isInherited) {
super.setInherited(isInherited);
}
}
private static class GetSetColor {
private final ColorKey myKey;
private final EditorColorsScheme myScheme;
private boolean isModified = false;
private Color myColor;
private GetSetColor(ColorKey key, EditorColorsScheme scheme) {
myKey = key;
myScheme = scheme;
myColor = myScheme.getColor(myKey);
}
public Color getColor() {
return myColor;
}
public void setColor(Color col) {
if (getColor() == null || !getColor().equals(col)) {
isModified = true;
myColor = col;
}
}
public void apply(EditorColorsScheme scheme) {
if (scheme == null) scheme = myScheme;
scheme.setColor(myKey, myColor);
}
public boolean isModified() {
return isModified;
}
}
private static class EditorSettingColorDescription extends ColorAndFontDescription {
private GetSetColor myGetSetForeground;
private GetSetColor myGetSetBackground;
private EditorSettingColorDescription(String name,
String group,
ColorKey backgroundKey,
ColorKey foregroundKey,
String type,
EditorColorsScheme scheme) {
super(name, group, type, scheme, null, null);
if (backgroundKey != null) {
myGetSetBackground = new GetSetColor(backgroundKey, scheme);
}
if (foregroundKey != null) {
myGetSetForeground = new GetSetColor(foregroundKey, scheme);
}
initCheckedStatus();
}
@Override
public int getFontType() {
return 0;
}
@Override
public void setFontType(int type) {
}
@Override
public Color getExternalEffectColor() {
return null;
}
@Override
public void setExternalEffectColor(Color color) {
}
@Override
public void setExternalEffectType(EffectType type) {
}
@NotNull
@Override
public EffectType getExternalEffectType() {
return EffectType.LINE_UNDERSCORE;
}
@Override
public Color getExternalForeground() {
if (myGetSetForeground == null) {
return null;
}
return myGetSetForeground.getColor();
}
@Override
public void setExternalForeground(Color col) {
if (myGetSetForeground == null) {
return;
}
myGetSetForeground.setColor(col);
}
@Override
public Color getExternalBackground() {
if (myGetSetBackground == null) {
return null;
}
return myGetSetBackground.getColor();
}
@Override
public void setExternalBackground(Color col) {
if (myGetSetBackground == null) {
return;
}
myGetSetBackground.setColor(col);
}
@Override
public Color getExternalErrorStripe() {
return null;
}
@Override
public void setExternalErrorStripe(Color col) {
}
@Override
public boolean isFontEnabled() {
return false;
}
@Override
public boolean isForegroundEnabled() {
return myGetSetForeground != null;
}
@Override
public boolean isBackgroundEnabled() {
return myGetSetBackground != null;
}
@Override
public boolean isEffectsColorEnabled() {
return false;
}
@Override
public boolean isModified() {
return myGetSetBackground != null && myGetSetBackground.isModified()
|| myGetSetForeground != null && myGetSetForeground.isModified();
}
@Override
public void apply(EditorColorsScheme scheme) {
if (myGetSetBackground != null) {
myGetSetBackground.apply(scheme);
}
if (myGetSetForeground != null) {
myGetSetForeground.apply(scheme);
}
}
}
@Override
@NotNull
public String getHelpTopic() {
return ID;
}
private static class MyColorScheme extends EditorColorsSchemeImpl {
private EditorSchemeAttributeDescriptor[] myDescriptors;
private String myName;
private boolean myIsNew = false;
private MyColorScheme(@NotNull EditorColorsScheme parentScheme) {
super(parentScheme, DefaultColorSchemesManager.getInstance());
parentScheme.getFontPreferences().copyTo(getFontPreferences());
setLineSpacing(parentScheme.getLineSpacing());
parentScheme.getConsoleFontPreferences().copyTo(getConsoleFontPreferences());
setConsoleLineSpacing(parentScheme.getConsoleLineSpacing());
setQuickDocFontSize(parentScheme.getQuickDocFontSize());
myName = parentScheme.getName();
if (parentScheme instanceof ExternalizableScheme) {
getExternalInfo().copy(((ExternalizableScheme)parentScheme).getExternalInfo());
}
initFonts();
}
@NotNull
@Override
public String getName() {
return myName;
}
@Override
public void setName(@NotNull String name) {
myName = name;
}
public void setDescriptors(EditorSchemeAttributeDescriptor[] descriptors) {
myDescriptors = descriptors;
}
public EditorSchemeAttributeDescriptor[] getDescriptors() {
return myDescriptors;
}
public boolean isDefault() {
return myParentScheme instanceof DefaultColorsScheme;
}
public boolean isReadOnly() {
return myParentScheme instanceof ReadOnlyColorsScheme;
}
public boolean isModified() {
if (isFontModified() || isConsoleFontModified()) return true;
for (EditorSchemeAttributeDescriptor descriptor : myDescriptors) {
if (descriptor.isModified()) {
return true;
}
}
return false;
}
private boolean isFontModified() {
if (!getFontPreferences().equals(myParentScheme.getFontPreferences())) return true;
if (getLineSpacing() != myParentScheme.getLineSpacing()) return true;
return getQuickDocFontSize() != myParentScheme.getQuickDocFontSize();
}
private boolean isConsoleFontModified() {
if (!getConsoleFontPreferences().equals(myParentScheme.getConsoleFontPreferences())) return true;
return getConsoleLineSpacing() != myParentScheme.getConsoleLineSpacing();
}
public void apply() {
apply(myParentScheme);
}
public void apply(@NotNull EditorColorsScheme scheme) {
scheme.setFontPreferences(getFontPreferences());
scheme.setLineSpacing(myLineSpacing);
scheme.setQuickDocFontSize(getQuickDocFontSize());
scheme.setConsoleFontPreferences(getConsoleFontPreferences());
scheme.setConsoleLineSpacing(getConsoleLineSpacing());
for (EditorSchemeAttributeDescriptor descriptor : myDescriptors) {
descriptor.apply(scheme);
}
}
@Override
public Object clone() {
return null;
}
public EditorColorsScheme getOriginalScheme() {
return myParentScheme;
}
public void setIsNew() {
myIsNew = true;
}
public boolean isNew() {
return myIsNew;
}
@NotNull
@Override
public String toString() {
return "temporary scheme for " + myName;
}
}
@Override
@NotNull
public String getId() {
return getHelpTopic();
}
@Override
@Nullable
public Runnable enableSearch(final String option) {
return null;
}
@Nullable
public InnerSearchableConfigurable findSubConfigurable(@NotNull final Class pageClass) {
if (mySubPanelFactories == null) {
buildConfigurables();
}
for (Map.Entry<ColorAndFontPanelFactory, InnerSearchableConfigurable> entry : mySubPanelFactories.entrySet()) {
if (pageClass.isInstance(entry.getValue().createPanel().getSettingsPage())) {
return entry.getValue();
}
}
return null;
}
@Nullable
public NewColorAndFontPanel findPage(String pageName) {
if (mySubPanelFactories == null) {
buildConfigurables();
}
for (InnerSearchableConfigurable configurable : mySubPanelFactories.values()) {
if (configurable.getDisplayName().equals(pageName)) {
return configurable.createPanel();
}
}
return null;
}
private class InnerSearchableConfigurable implements SearchableConfigurable, OptionsContainingConfigurable, NoScroll {
private NewColorAndFontPanel mySubPanel;
private boolean mySubInitInvoked = false;
@NotNull private final ColorAndFontPanelFactory myFactory;
private InnerSearchableConfigurable(@NotNull ColorAndFontPanelFactory factory) {
myFactory = factory;
}
@NotNull
@Override
@Nls
public String getDisplayName() {
return myFactory.getPanelDisplayName();
}
public NewColorAndFontPanel getSubPanelIfInitialized() {
return mySubPanel;
}
private NewColorAndFontPanel createPanel() {
if (mySubPanel == null) {
mySubPanel = myFactory.createPanel(ColorAndFontOptions.this);
mySubPanel.reset(this);
mySubPanel.addSchemesListener(new ColorAndFontSettingsListener.Abstract(){
@Override
public void schemeChanged(final Object source) {
if (!myIsReset) {
resetSchemesCombo(source);
}
}
});
mySubPanel.addDescriptionListener(new ColorAndFontSettingsListener.Abstract(){
@Override
public void fontChanged() {
for (NewColorAndFontPanel panel : getPanels()) {
panel.updatePreview();
}
}
});
}
return mySubPanel;
}
@Override
public String getHelpTopic() {
return null;
}
@Override
public JComponent createComponent() {
return createPanel().getPanel();
}
@Override
public boolean isModified() {
createPanel();
for (MyColorScheme scheme : mySchemes.values()) {
if (mySubPanel.containsFontOptions()) {
if (scheme.isFontModified() || scheme.isConsoleFontModified()) {
myRevertChangesCompleted = false;
return true;
}
}
else {
for (EditorSchemeAttributeDescriptor descriptor : scheme.getDescriptors()) {
if (mySubPanel.contains(descriptor) && descriptor.isModified()) {
myRevertChangesCompleted = false;
return true;
}
}
}
}
return false;
}
@Override
public void apply() throws ConfigurationException {
ColorAndFontOptions.this.apply();
}
@Override
public void reset() {
if (!mySubInitInvoked) {
if (!myInitResetCompleted) {
resetFromChild();
}
mySubInitInvoked = true;
}
else {
revertChanges();
}
}
@Override
public void disposeUIResources() {
if (mySubPanel != null) {
mySubPanel.disposeUIResources();
mySubPanel = null;
}
}
@Override
@NotNull
public String getId() {
return ColorAndFontOptions.this.getId() + "." + getDisplayName();
}
@Override
public Runnable enableSearch(final String option) {
return createPanel().showOption(option);
}
@NotNull
@Override
public Set<String> processListOptions() {
return createPanel().processListOptions();
}
@NotNull
@NonNls
@Override
public String toString() {
return "Color And Fonts for "+getDisplayName();
}
}
}