/*
* Copyright 2000-2013 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.openapi.application.ApplicationBundle;
import com.intellij.openapi.editor.colors.EditorColorsScheme;
import com.intellij.openapi.editor.markup.EffectType;
import com.intellij.openapi.editor.markup.TextAttributes;
import com.intellij.openapi.options.colors.AttributesDescriptor;
import com.intellij.openapi.options.colors.ColorSettingsPage;
import com.intellij.openapi.ui.Messages;
import com.intellij.openapi.util.Pair;
import com.intellij.ui.*;
import com.intellij.ui.components.JBCheckBox;
import com.intellij.util.FontUtil;
import com.intellij.util.containers.ContainerUtil;
import com.intellij.util.ui.UIUtil;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import javax.swing.*;
import javax.swing.event.HyperlinkEvent;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.Collections;
import java.util.List;
import java.util.Map;
/**
* @author cdr
*/
public class ColorAndFontDescriptionPanel extends JPanel {
private JPanel myPanel;
private ColorPanel myBackgroundChooser;
private ColorPanel myForegroundChooser;
private ColorPanel myEffectsColorChooser;
private ColorPanel myErrorStripeColorChooser;
private JBCheckBox myCbBackground;
private JBCheckBox myCbForeground;
private JBCheckBox myCbEffects;
private JBCheckBox myCbErrorStripe;
private Map<String, EffectType> myEffectsMap;
{
Map<String, EffectType> map = ContainerUtil.newLinkedHashMap();
map.put(ApplicationBundle.message("combobox.effect.underscored"), EffectType.LINE_UNDERSCORE);
map.put(ApplicationBundle.message("combobox.effect.boldunderscored"), EffectType.BOLD_LINE_UNDERSCORE);
map.put(ApplicationBundle.message("combobox.effect.underwaved"), EffectType.WAVE_UNDERSCORE);
map.put(ApplicationBundle.message("combobox.effect.bordered"), EffectType.BOXED);
map.put(ApplicationBundle.message("combobox.effect.strikeout"), EffectType.STRIKEOUT);
map.put(ApplicationBundle.message("combobox.effect.bold.dottedline"), EffectType.BOLD_DOTTED_LINE);
myEffectsMap = Collections.unmodifiableMap(map);
}
private JComboBox myEffectsCombo;
private final EffectsComboModel myEffectsModel;
private JBCheckBox myCbBold;
private JBCheckBox myCbItalic;
private JLabel myLabelFont;
private JTextPane myInheritanceLabel;
private JBCheckBox myInheritAttributesBox;
public ColorAndFontDescriptionPanel() {
super(new BorderLayout());
add(myPanel, BorderLayout.CENTER);
setBorder(BorderFactory.createEmptyBorder(4, 0, 4, 4));
myEffectsModel = new EffectsComboModel(ContainerUtil.newArrayList(myEffectsMap.keySet()));
//noinspection unchecked
myEffectsCombo.setModel(myEffectsModel);
//noinspection unchecked
myEffectsCombo.setRenderer(new ListCellRendererWrapper<String>() {
@Override
public void customize(JList list, String value, int index, boolean selected, boolean hasFocus) {
setText(value != null ? value : "<invalid>");
}
});
ActionListener actionListener = new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
onSettingsChanged(e);
}
};
for (JBCheckBox c : new JBCheckBox[]{myCbBackground, myCbForeground, myCbEffects, myCbErrorStripe, myCbItalic, myCbBold, myInheritAttributesBox}) {
c.addActionListener(actionListener);
}
for (ColorPanel c : new ColorPanel[]{myBackgroundChooser, myForegroundChooser, myEffectsColorChooser, myErrorStripeColorChooser}) {
c.addActionListener(actionListener);
}
myEffectsCombo.addActionListener(actionListener);
Messages.configureMessagePaneUi(myInheritanceLabel, "<html>", null);
myInheritanceLabel.addHyperlinkListener(new HyperlinkAdapter() {
@Override
protected void hyperlinkActivated(HyperlinkEvent e) {
onHyperLinkClicked(e);
}
});
myInheritanceLabel.setBorder(BorderFactory.createEmptyBorder());
myLabelFont.setVisible(false); // hide for now as it doesn't look that good
}
protected void onHyperLinkClicked(HyperlinkEvent e) {
}
protected void onSettingsChanged(ActionEvent e) {
myErrorStripeColorChooser.setEnabled(myCbErrorStripe.isSelected());
myForegroundChooser.setEnabled(myCbForeground.isSelected());
myBackgroundChooser.setEnabled(myCbBackground.isSelected());
myEffectsColorChooser.setEnabled(myCbEffects.isSelected());
myEffectsCombo.setEnabled(myCbEffects.isSelected());
}
public void resetDefault() {
myLabelFont.setEnabled(false);
myCbBold.setSelected(false);
myCbBold.setEnabled(false);
myCbItalic.setSelected(false);
myCbItalic.setEnabled(false);
updateColorChooser(myCbForeground, myForegroundChooser, false, false, null);
updateColorChooser(myCbBackground, myBackgroundChooser, false, false, null);
updateColorChooser(myCbErrorStripe, myErrorStripeColorChooser, false, false, null);
updateColorChooser(myCbEffects, myEffectsColorChooser, false, false, null);
myEffectsCombo.setEnabled(false);
myInheritanceLabel.setVisible(false);
myInheritAttributesBox.setVisible(false);
}
private static void updateColorChooser(JCheckBox checkBox,
ColorPanel colorPanel,
boolean isEnabled,
boolean isChecked,
@Nullable Color color) {
checkBox.setEnabled(isEnabled);
checkBox.setSelected(isChecked);
if (color != null) {
colorPanel.setSelectedColor(color);
}
else {
colorPanel.setSelectedColor(JBColor.WHITE);
}
colorPanel.setEnabled(isChecked);
}
public void reset(ColorAndFontDescription description) {
if (description.isFontEnabled()) {
myLabelFont.setEnabled(true);
myCbBold.setEnabled(true);
myCbItalic.setEnabled(true);
int fontType = description.getFontType();
myCbBold.setSelected((fontType & Font.BOLD) != 0);
myCbItalic.setSelected((fontType & Font.ITALIC) != 0);
}
else {
myLabelFont.setEnabled(false);
myCbBold.setSelected(false);
myCbBold.setEnabled(false);
myCbItalic.setSelected(false);
myCbItalic.setEnabled(false);
}
updateColorChooser(myCbForeground, myForegroundChooser, description.isForegroundEnabled(),
description.isForegroundChecked(), description.getForegroundColor());
updateColorChooser(myCbBackground, myBackgroundChooser, description.isBackgroundEnabled(),
description.isBackgroundChecked(), description.getBackgroundColor());
updateColorChooser(myCbErrorStripe, myErrorStripeColorChooser, description.isErrorStripeEnabled(),
description.isErrorStripeChecked(), description.getErrorStripeColor());
EffectType effectType = description.getEffectType();
updateColorChooser(myCbEffects, myEffectsColorChooser, description.isEffectsColorEnabled(),
description.isEffectsColorChecked(), description.getEffectColor());
if (description.isEffectsColorEnabled() && description.isEffectsColorChecked()) {
myEffectsCombo.setEnabled(true);
myEffectsModel.setEffectName(ContainerUtil.reverseMap(myEffectsMap).get(effectType));
}
else {
myEffectsCombo.setEnabled(false);
}
setInheritanceInfo(description);
myLabelFont.setEnabled(myCbBold.isEnabled() || myCbItalic.isEnabled());
}
private void setInheritanceInfo(ColorAndFontDescription description) {
Pair<ColorSettingsPage, AttributesDescriptor> baseDescriptor = description.getBaseAttributeDescriptor();
if (baseDescriptor != null && baseDescriptor.second.getDisplayName() != null) {
String attrName = baseDescriptor.second.getDisplayName();
String attrLabel = attrName.replaceAll(ColorOptionsTree.NAME_SEPARATOR, FontUtil.rightArrow(UIUtil.getLabelFont()));
ColorSettingsPage settingsPage = baseDescriptor.first;
String style = "<div style=\"text-align:right\" vertical-align=\"top\">";
String tooltipText;
String labelText;
if (settingsPage != null) {
String pageName = settingsPage.getDisplayName();
tooltipText = "'" + attrLabel + "' from<br>'" + pageName + "' section";
labelText = style + "'" + attrLabel + "'<br>of <a href=\"" + attrName + "\">" + pageName;
}
else {
tooltipText = attrLabel;
labelText = style + attrLabel + "<br> ";
}
myInheritanceLabel.setVisible(true);
myInheritanceLabel.setText(labelText);
myInheritanceLabel.setToolTipText(tooltipText);
myInheritanceLabel.setEnabled(true);
myInheritAttributesBox.setVisible(true);
myInheritAttributesBox.setEnabled(true);
myInheritAttributesBox.setSelected(description.isInherited());
setEditEnabled(!description.isInherited(), description);
}
else {
myInheritanceLabel.setVisible(false);
myInheritAttributesBox.setSelected(false);
myInheritAttributesBox.setVisible(false);
setEditEnabled(true, description);
}
}
private void setEditEnabled(boolean isEditEnabled, ColorAndFontDescription description) {
myCbBackground.setEnabled(isEditEnabled && description.isBackgroundEnabled());
myCbForeground.setEnabled(isEditEnabled && description.isForegroundEnabled());
myCbBold.setEnabled(isEditEnabled && description.isFontEnabled());
myCbItalic.setEnabled(isEditEnabled && description.isFontEnabled());
myCbEffects.setEnabled(isEditEnabled && description.isEffectsColorEnabled());
myCbErrorStripe.setEnabled(isEditEnabled && description.isErrorStripeEnabled());
myErrorStripeColorChooser.setEditable(isEditEnabled);
myEffectsColorChooser.setEditable(isEditEnabled);
myForegroundChooser.setEditable(isEditEnabled);
myBackgroundChooser.setEditable(isEditEnabled);
}
public void apply(ColorAndFontDescription description, EditorColorsScheme scheme) {
if (description != null) {
description.setInherited(myInheritAttributesBox.isSelected());
if (description.isInherited()) {
TextAttributes baseAttributes = description.getBaseAttributes();
if (baseAttributes != null) {
description.setFontType(baseAttributes.getFontType());
description.setForegroundChecked(baseAttributes.getForegroundColor() != null);
description.setForegroundColor(baseAttributes.getForegroundColor());
description.setBackgroundChecked(baseAttributes.getBackgroundColor() != null);
description.setBackgroundColor(baseAttributes.getBackgroundColor());
description.setErrorStripeChecked(baseAttributes.getErrorStripeColor() != null);
description.setErrorStripeColor(baseAttributes.getErrorStripeColor());
description.setEffectColor(baseAttributes.getEffectColor());
description.setEffectType(baseAttributes.getEffectType());
description.setEffectsColorChecked(baseAttributes.getEffectColor() != null);
}
else {
description.setInherited(false);
}
reset(description);
}
else {
setInheritanceInfo(description);
int fontType = Font.PLAIN;
if (myCbBold.isSelected()) fontType |= Font.BOLD;
if (myCbItalic.isSelected()) fontType |= Font.ITALIC;
description.setFontType(fontType);
description.setForegroundChecked(myCbForeground.isSelected());
description.setForegroundColor(myForegroundChooser.getSelectedColor());
description.setBackgroundChecked(myCbBackground.isSelected());
description.setBackgroundColor(myBackgroundChooser.getSelectedColor());
description.setErrorStripeChecked(myCbErrorStripe.isSelected());
description.setErrorStripeColor(myErrorStripeColorChooser.getSelectedColor());
description.setEffectsColorChecked(myCbEffects.isSelected());
description.setEffectColor(myEffectsColorChooser.getSelectedColor());
if (myEffectsCombo.isEnabled()) {
String effectType = (String)myEffectsCombo.getModel().getSelectedItem();
description.setEffectType(myEffectsMap.get(effectType));
}
}
description.apply(scheme);
}
}
private static class EffectsComboModel extends CollectionComboBoxModel<String> {
public EffectsComboModel(List<String> names) {
super(names);
}
/**
* Set the current effect name when a text attribute selection changes without notifying the listeners since otherwise it will
* be considered as an actual change and lead to unnecessary evens including 'read-only scheme' check.
*
* @param effectName
*/
public void setEffectName(@NotNull String effectName) {
mySelection = effectName;
}
}
}