update copyright
[fedora-idea.git] / xml / dom-openapi / src / com / intellij / util / xml / ui / ComboControl.java
blob63926ecb33ad8d02a68f9096a3e0fecd9a78387a
1 /*
2 * Copyright 2000-2009 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.
16 package com.intellij.util.xml.ui;
18 import com.intellij.lang.annotation.HighlightSeverity;
19 import com.intellij.openapi.application.ApplicationManager;
20 import com.intellij.openapi.project.Project;
21 import com.intellij.openapi.util.Condition;
22 import com.intellij.openapi.util.Factory;
23 import com.intellij.openapi.util.Pair;
24 import com.intellij.util.Function;
25 import com.intellij.util.containers.ContainerUtil;
26 import com.intellij.util.xml.*;
27 import com.intellij.util.xml.highlighting.DomElementAnnotationsManager;
28 import com.intellij.util.xml.highlighting.DomElementProblemDescriptor;
29 import com.intellij.util.xml.highlighting.DomElementsProblemsHolder;
30 import org.jetbrains.annotations.NotNull;
31 import org.jetbrains.annotations.Nullable;
33 import javax.swing.*;
34 import java.awt.*;
35 import java.awt.event.ItemEvent;
36 import java.awt.event.ItemListener;
37 import java.util.*;
38 import java.util.List;
40 /**
41 * @author peter
43 public class ComboControl extends BaseModifiableControl<JComboBox, String> {
44 private static final Pair<String, Icon> EMPTY = new ComboBoxItem(" ", null);
45 private final Factory<List<Pair<String, Icon>>> myDataFactory;
46 private boolean myNullable;
47 private final Map<String, Icon> myIcons = new HashMap<String, Icon>();
48 private final ItemListener myCommitListener = new ItemListener() {
49 public void itemStateChanged(ItemEvent e) {
50 setModified();
51 commit();
55 public ComboControl(final GenericDomValue genericDomValue, final Factory<List<Pair<String, Icon>>> dataFactory) {
56 this(new DomStringWrapper(genericDomValue), dataFactory);
59 public ComboControl(final DomWrapper<String> domWrapper, final Factory<List<Pair<String, Icon>>> dataFactory) {
60 super(domWrapper);
61 myDataFactory = dataFactory;
62 reset();
65 public ComboControl(final DomWrapper<String> domWrapper, final Class<? extends Enum> aClass) {
66 super(domWrapper);
67 myDataFactory = createEnumFactory(aClass);
68 reset();
71 public final boolean isNullable() {
72 return myNullable;
75 public final void setNullable(final boolean nullable) {
76 myNullable = nullable;
79 public ComboControl(final GenericDomValue<?> reference) {
80 this(reference, createResolvingFunction(reference));
83 public static Factory<List<Pair<String, Icon>>> createResolvingFunction(final GenericDomValue<?> reference) {
84 return new Factory<List<Pair<String, Icon>>>() {
85 public List<Pair<String, Icon>> create() {
86 final Converter converter = reference.getConverter();
87 if (converter instanceof ResolvingConverter) {
88 final AbstractConvertContext context = new AbstractConvertContext() {
89 @NotNull
90 public DomElement getInvocationElement() {
91 return reference;
94 final ResolvingConverter resolvingConverter = (ResolvingConverter)converter;
95 final Collection<Object> variants = resolvingConverter.getVariants(context);
96 final List<Pair<String, Icon>> all = ContainerUtil.map(variants, new Function<Object, Pair<String, Icon>>() {
97 public Pair<String, Icon> fun(final Object s) {
98 return Pair.create(ElementPresentationManager.getElementName(s), ElementPresentationManager.getIcon(s));
101 all.addAll(ContainerUtil.map(resolvingConverter.getAdditionalVariants(context), new Function() {
102 public Object fun(final Object s) {
103 return new Pair(s, null);
105 }));
106 return all;
108 return Collections.emptyList();
113 public static Factory<Collection<? extends Object>> createVariantsGetter(final GenericDomValue<?> reference) {
114 return new Factory<Collection<? extends Object>>() {
115 public Collection<? extends Object> create() {
116 final Converter converter = reference.getConverter();
117 if (converter instanceof ResolvingConverter) {
118 return ((ResolvingConverter)converter).getVariants(new AbstractConvertContext() {
119 @NotNull
120 public DomElement getInvocationElement() {
121 return reference;
126 return Collections.emptyList();
131 public static Factory<List<Pair<String, Icon>>> createPresentationFunction(final Factory<Collection<? extends Object>> variantFactory) {
132 return new Factory<List<Pair<String, Icon>>>() {
133 public List<Pair<String, Icon>> create() {
135 return ContainerUtil.map(variantFactory.create(), new Function<Object, Pair<String, Icon>>() {
136 public Pair<String, Icon> fun(final Object s) {
137 return Pair.create(ElementPresentationManager.getElementName(s), ElementPresentationManager.getIcon(s));
145 static Factory<List<Pair<String, Icon>>> createEnumFactory(final Class<? extends Enum> aClass) {
146 return new Factory<List<Pair<String, Icon>>>() {
147 public List<Pair<String, Icon>> create() {
148 return ContainerUtil.map2List(aClass.getEnumConstants(), new Function<Enum, Pair<String, Icon>>() {
149 public Pair<String, Icon> fun(final Enum s) {
150 return Pair.create(NamedEnumUtil.getEnumValueByElement(s), ElementPresentationManager.getIcon(s));
157 public static <T extends Enum> JComboBox createEnumComboBox(final Class<T> type) {
158 return tuneUpComboBox(new JComboBox(), createEnumFactory(type));
161 private static JComboBox tuneUpComboBox(final JComboBox comboBox, Factory<List<Pair<String, Icon>>> dataFactory) {
162 final List<Pair<String, Icon>> list = dataFactory.create();
163 final Set<String> standardValues = new HashSet<String>();
164 for (final Pair<String, Icon> pair : list) {
165 comboBox.addItem(new ComboBoxItem(pair));
166 standardValues.add(pair.first);
168 return initComboBox(comboBox, new Condition<String>() {
169 public boolean value(final String object) {
170 return standardValues.contains(object);
175 private static class ComboBoxItem extends Pair<String,Icon> {
177 public ComboBoxItem(String first, Icon second) {
178 super(first, second);
181 public ComboBoxItem(Pair<String,Icon> pair) {
182 super(pair.first, pair.second);
185 public String toString() {
186 return first;
190 static JComboBox initComboBox(final JComboBox comboBox, final Condition<String> validity) {
191 comboBox.setEditable(false);
192 comboBox.setPrototypeDisplayValue(new ComboBoxItem("A", null));
193 comboBox.setRenderer(new DefaultListCellRenderer() {
194 public Component getListCellRendererComponent(JList list, Object value, int index, boolean isSelected, boolean cellHasFocus) {
195 super.getListCellRendererComponent(list, value, index, isSelected, cellHasFocus);
196 final Pair<String, Icon> pair = (Pair<String, Icon>)value;
197 final String text = pair == null ? null : pair.first;
198 setText(text);
199 final Dimension dimension = getPreferredSize();
200 if (!validity.value(text)) {
201 setFont(getFont().deriveFont(Font.ITALIC));
202 setForeground(Color.RED);
204 setIcon(pair == null ? null : pair.second);
205 setPreferredSize(new Dimension(-1, dimension.height));
206 return this;
209 return comboBox;
212 protected JComboBox createMainComponent(final JComboBox boundedComponent) {
213 return initComboBox(boundedComponent == null ? new JComboBox() : boundedComponent, new Condition<String>() {
214 public boolean value(final String object) {
215 return isValidValue(object);
220 public boolean isValidValue(final String object) {
221 return myNullable && object == EMPTY.first || myIcons.containsKey(object);
224 private boolean dataChanged(List<Pair<String, Icon>> newData) {
225 final JComboBox comboBox = getComponent();
226 final int size = comboBox.getItemCount();
227 final List<Pair<String, Icon>> oldData = new ArrayList<Pair<String, Icon>>(size);
228 for (int i = 0; i < size; i++) {
229 oldData.add((Pair<String, Icon>)comboBox.getItemAt(i));
232 if (myNullable) {
233 final LinkedList<Pair<String, Icon>> list = new LinkedList<Pair<String, Icon>>(newData);
234 list.addFirst(EMPTY);
235 newData = list;
238 return !newData.equals(oldData);
241 protected boolean isCommitted() {
242 return getComponent().isPopupVisible() || super.isCommitted();
245 protected void doReset() {
246 final List<Pair<String, Icon>> data = myDataFactory.create();
247 final JComboBox comboBox = getComponent();
248 comboBox.removeItemListener(myCommitListener);
249 try {
250 if (!dataChanged(data)) {
251 super.doReset();
252 return;
255 final String oldValue = getValue();
256 myIcons.clear();
257 comboBox.removeAllItems();
258 if (myNullable) {
259 comboBox.addItem(EMPTY);
261 for (final Pair<String, Icon> s : data) {
262 comboBox.addItem(new ComboBoxItem(s));
263 myIcons.put(s.first, s.second);
265 setValue(oldValue);
266 super.doReset();
268 finally {
269 comboBox.addItemListener(myCommitListener);
273 @Nullable
274 protected final String getValue() {
275 final Pair<String, Icon> pair = (Pair<String, Icon>)getComponent().getSelectedItem();
276 return pair == null || pair == EMPTY ? null : pair.first;
279 protected final void setValue(final String value) {
280 final JComboBox component = getComponent();
281 if (!isValidValue(value)) {
282 component.setEditable(true);
284 component.setSelectedItem(new ComboBoxItem(value, myIcons.get(value)));
285 component.setEditable(false);
289 protected void updateComponent() {
290 final DomElement domElement = getDomElement();
291 if (domElement == null || !domElement.isValid()) return;
293 final JComboBox comboBox = getComponent();
295 final Project project = getProject();
296 ApplicationManager.getApplication().invokeLater(new Runnable() {
297 public void run() {
298 if (!project.isOpen()) return;
299 if (!getDomWrapper().isValid()) return;
301 final DomElement domElement = getDomElement();
302 if (domElement == null || !domElement.isValid()) return;
304 final DomElementAnnotationsManager manager = DomElementAnnotationsManager.getInstance(project);
305 final DomElementsProblemsHolder holder = manager.getCachedProblemHolder(domElement);
306 final List<DomElementProblemDescriptor> errorProblems = holder.getProblems(domElement);
307 final List<DomElementProblemDescriptor> warningProblems = holder.getProblems(domElement, true, HighlightSeverity.WARNING);
309 Color background = getDefaultBackground();
310 comboBox.setToolTipText(null);
312 if (errorProblems.size() > 0) {
313 background = getErrorBackground();
314 comboBox.setToolTipText(TooltipUtils.getTooltipText(errorProblems));
316 else if (warningProblems.size() > 0) {
317 background = getWarningBackground();
318 comboBox.setToolTipText(TooltipUtils.getTooltipText(warningProblems));
321 final Pair<String, Icon> pair = (Pair<String, Icon>)comboBox.getSelectedItem();
322 final String s = pair == null ? null : pair.first;
323 background = s != null && s.trim().length() > 0 ? getDefaultBackground() : background;
325 comboBox.setBackground(background);
326 comboBox.getEditor().getEditorComponent().setBackground(background);