forgot to check length()
[idea/community.git] / platform / lang-impl / src / com / intellij / application / options / colors / OptionsPanelImpl.java
1 /*
2  * Copyright 2000-2015 JetBrains s.r.o.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16
17 package com.intellij.application.options.colors;
18
19 import com.intellij.ide.DataManager;
20 import com.intellij.ide.util.PropertiesComponent;
21 import com.intellij.openapi.editor.colors.EditorColorsScheme;
22 import com.intellij.openapi.options.SearchableConfigurable;
23 import com.intellij.openapi.options.ex.Settings;
24 import com.intellij.openapi.util.ActionCallback;
25 import com.intellij.ui.ScrollPaneFactory;
26 import com.intellij.util.EventDispatcher;
27 import com.intellij.util.ui.JBUI;
28 import org.jetbrains.annotations.NotNull;
29
30 import javax.swing.*;
31 import javax.swing.event.HyperlinkEvent;
32 import javax.swing.event.TreeSelectionEvent;
33 import javax.swing.event.TreeSelectionListener;
34 import javax.swing.text.BadLocationException;
35 import javax.swing.text.Element;
36 import java.awt.*;
37 import java.awt.event.ActionEvent;
38 import java.util.EventListener;
39 import java.util.HashSet;
40 import java.util.Set;
41
42 public class OptionsPanelImpl extends JPanel implements OptionsPanel {
43   public static final String SELECTED_COLOR_OPTION_PROPERTY = "selected.color.option.type";
44
45   private final ColorOptionsTree myOptionsTree;
46   private final ColorDescriptionPanel myOptionsPanel;
47
48   private final ColorAndFontOptions myOptions;
49   private final SchemesPanel mySchemesProvider;
50   private final String myCategoryName;
51
52   private final PropertiesComponent myProperties;
53
54   private final EventDispatcher<ColorAndFontSettingsListener> myDispatcher = EventDispatcher.create(ColorAndFontSettingsListener.class);
55
56   public OptionsPanelImpl(ColorAndFontOptions options,
57                           SchemesPanel schemesProvider,
58                           String categoryName) {
59     this(options, schemesProvider, categoryName, new ColorAndFontDescriptionPanel());
60   }
61
62   public OptionsPanelImpl(ColorAndFontOptions options,
63                           SchemesPanel schemesProvider,
64                           String categoryName,
65                           ColorDescriptionPanel optionsPanel) {
66     super(new BorderLayout());
67     myOptions = options;
68     mySchemesProvider = schemesProvider;
69     myCategoryName = categoryName;
70     myProperties = PropertiesComponent.getInstance();
71
72     myOptionsPanel = optionsPanel;
73     myOptionsPanel.addListener(new ColorDescriptionPanel.Listener() {
74       @Override
75       public void onSettingsChanged(ActionEvent e) {
76         myDispatcher.getMulticaster().settingsChanged();
77       }
78
79       @Override
80       public void onHyperLinkClicked(HyperlinkEvent e) {
81         if (e.getEventType() == HyperlinkEvent.EventType.ACTIVATED) {
82           Settings settings = Settings.KEY.getData(DataManager.getInstance().getDataContext(OptionsPanelImpl.this));
83           String attrName = e.getDescription();
84           Element element = e.getSourceElement();
85           String pageName;
86           try {
87             pageName = element.getDocument().getText(element.getStartOffset(), element.getEndOffset() - element.getStartOffset());
88           }
89           catch (BadLocationException e1) {
90             return;
91           }
92           final SearchableConfigurable page = myOptions.findSubConfigurable(pageName);
93           if (page != null && settings != null) {
94             Runnable runnable = page.enableSearch(attrName);
95             ActionCallback callback = settings.select(page);
96             if (runnable != null) callback.doWhenDone(runnable);
97           }
98         }
99       }
100     });
101
102     myOptionsTree = new ColorOptionsTree(myCategoryName);
103
104     myOptionsTree.addTreeSelectionListener(new TreeSelectionListener() {
105       @Override
106       public void valueChanged(TreeSelectionEvent e) {
107         if (!mySchemesProvider.areSchemesLoaded()) return;
108         processListValueChanged();
109       }
110     });
111
112     JScrollPane scrollPane = ScrollPaneFactory.createScrollPane(myOptionsTree);
113     add(scrollPane, BorderLayout.CENTER);
114     add(myOptionsPanel.getPanel(), BorderLayout.EAST);
115
116   }
117
118   @Override
119   public void addListener(ColorAndFontSettingsListener listener) {
120     myDispatcher.addListener(listener);
121   }
122
123   private void processListValueChanged() {
124     Object selectedValue = myOptionsTree.getSelectedValue();
125     ColorAndFontDescription description = selectedValue instanceof ColorAndFontDescription ? (ColorAndFontDescription)selectedValue : null;
126     if (description == null) {
127       if (selectedValue == null) {
128         String preselectedType = myProperties.getValue(SELECTED_COLOR_OPTION_PROPERTY);
129         if (preselectedType != null) {
130           myOptionsTree.selectOptionByType(preselectedType);
131           description = myOptionsTree.getSelectedDescriptor();
132         }
133       }
134     }
135     if (description != null) {
136       myProperties.setValue(SELECTED_COLOR_OPTION_PROPERTY, description.getType());
137       myOptionsPanel.reset(description);
138       myDispatcher.getMulticaster().selectedOptionChanged(description);
139     }
140     else {
141       myOptionsPanel.resetDefault();
142     }
143   }
144
145   private void fillOptionsList() {
146     myOptionsTree.fillOptions(myOptions);
147   }
148
149   @Override
150   public JPanel getPanel() {
151     return this;
152   }
153
154   @Override
155   public void updateOptionsList() {
156     fillOptionsList();
157     processListValueChanged();
158   }
159
160   @Override
161   public Runnable showOption(final String attributeDisplayName) {
162     return () -> myOptionsTree.selectOptionByName(attributeDisplayName);
163   }
164
165   @Override
166   public void applyChangesToScheme() {
167     ColorAndFontDescription descriptor = myOptionsTree.getSelectedDescriptor();
168     if (descriptor != null) {
169       myOptionsPanel.apply(descriptor, myOptions.getSelectedScheme());
170     }
171   }
172
173   @Override
174   public void selectOption(String attributeType) {
175     myOptionsTree.selectOptionByType(attributeType);
176   }
177
178   @Override
179   public Set<String> processListOptions() {
180     HashSet<String> result = new HashSet<>();
181     EditorSchemeAttributeDescriptor[] descriptions = myOptions.getCurrentDescriptions();
182     for (EditorSchemeAttributeDescriptor description : descriptions) {
183       if (description.getGroup().equals(myCategoryName)) {
184         result.add(description.toString());
185       }
186     }
187     return result;
188   }
189
190   public interface ColorDescriptionPanel {
191     @NotNull
192     JComponent getPanel();
193
194     void resetDefault();
195
196     void reset(@NotNull ColorAndFontDescription description);
197
198     void apply(@NotNull ColorAndFontDescription descriptor, EditorColorsScheme scheme);
199
200     void addListener(@NotNull Listener listener);
201
202     interface Listener extends EventListener {
203       void onSettingsChanged(ActionEvent e);
204
205       void onHyperLinkClicked(HyperlinkEvent e);
206     }
207   }
208 }