bug fixed
[fedora-idea.git] / dom / openapi / src / com / intellij / util / xml / ui / ComboControl.java
blob0ba16c7c1fd46ab7280f59d2da08a09c28d6b5de
1 /*
2 * Copyright (c) 2005 Your Corporation. All Rights Reserved.
3 */
4 package com.intellij.util.xml.ui;
6 import com.intellij.lang.annotation.HighlightSeverity;
7 import com.intellij.openapi.application.ApplicationManager;
8 import com.intellij.openapi.project.Project;
9 import com.intellij.openapi.util.Condition;
10 import com.intellij.openapi.util.Factory;
11 import com.intellij.openapi.util.Pair;
12 import com.intellij.psi.PsiManager;
13 import com.intellij.util.Function;
14 import com.intellij.util.containers.ContainerUtil;
15 import com.intellij.util.xml.*;
16 import com.intellij.util.xml.highlighting.DomElementAnnotationsManager;
17 import com.intellij.util.xml.highlighting.DomElementProblemDescriptor;
18 import com.intellij.util.xml.highlighting.DomElementsProblemsHolder;
19 import gnu.trove.THashMap;
20 import org.jetbrains.annotations.NotNull;
21 import org.jetbrains.annotations.Nullable;
23 import java.awt.*;
24 import java.awt.event.ActionEvent;
25 import java.awt.event.ActionListener;
26 import java.util.*;
27 import java.util.List;
28 import javax.swing.*;
29 import javax.swing.text.JTextComponent;
31 /**
32 * @author peter
34 public class ComboControl extends BaseControl<JComboBox, String> {
35 private static final Pair<String, Icon> EMPTY = Pair.create(" ", null);
36 private final Factory<List<Pair<String, Icon>>> myDataFactory;
37 private boolean myNullable;
38 private Map<String, Icon> myIcons = new THashMap<String, Icon>();
39 private final ActionListener myCommitListener = new ActionListener() {
40 public void actionPerformed(ActionEvent e) {
41 commit();
45 public ComboControl(final GenericDomValue genericDomValue, final Factory<List<Pair<String, Icon>>> dataFactory) {
46 this(new DomStringWrapper(genericDomValue), dataFactory);
49 public ComboControl(final DomWrapper<String> domWrapper, final Factory<List<Pair<String, Icon>>> dataFactory) {
50 super(domWrapper);
51 myDataFactory = dataFactory;
52 reset();
55 public ComboControl(final DomWrapper<String> domWrapper, final Class<? extends Enum> aClass) {
56 super(domWrapper);
57 myDataFactory = createEnumFactory(aClass);
58 reset();
61 public final boolean isNullable() {
62 return myNullable;
65 public final void setNullable(final boolean nullable) {
66 myNullable = nullable;
69 public ComboControl(final GenericDomValue<?> reference) {
70 this(reference, createResolvingFunction(reference));
73 public static Factory<List<Pair<String, Icon>>> createResolvingFunction(final GenericDomValue<?> reference) {
74 return new Factory<List<Pair<String, Icon>>>() {
75 public List<Pair<String, Icon>> create() {
76 final Converter converter = reference.getConverter();
77 if (converter instanceof ResolvingConverter) {
78 final AbstractConvertContext context = new AbstractConvertContext() {
79 @NotNull
80 public DomElement getInvocationElement() {
81 return reference;
84 public PsiManager getPsiManager() {
85 return getFile().getManager();
88 final ResolvingConverter resolvingConverter = (ResolvingConverter)converter;
89 final Collection<Object> variants = resolvingConverter.getVariants(context);
90 final List<Pair<String, Icon>> all = ContainerUtil.map(variants, new Function<Object, Pair<String, Icon>>() {
91 public Pair<String, Icon> fun(final Object s) {
92 return Pair.create(ElementPresentationManager.getElementName(s), ElementPresentationManager.getIcon(s));
94 });
95 all.addAll(ContainerUtil.map(resolvingConverter.getAdditionalVariants(), new Function() {
96 public Object fun(final Object s) {
97 return new Pair(s, null);
99 }));
100 return all;
102 return Collections.emptyList();
107 public static Factory<Collection<? extends Object>> createVariantsGetter(final GenericDomValue<?> reference) {
108 return new Factory<Collection<? extends Object>>() {
109 public Collection<? extends Object> create() {
110 final Converter converter = reference.getConverter();
111 if (converter instanceof ResolvingConverter) {
112 return ((ResolvingConverter)converter).getVariants(new AbstractConvertContext() {
113 @NotNull
114 public DomElement getInvocationElement() {
115 return reference;
118 public PsiManager getPsiManager() {
119 return getFile().getManager();
124 return Collections.emptyList();
129 public static Factory<List<Pair<String, Icon>>> createPresentationFunction(final Factory<Collection<? extends Object>> variantFactory) {
130 return new Factory<List<Pair<String, Icon>>>() {
131 public List<Pair<String, Icon>> create() {
133 return ContainerUtil.map(variantFactory.create(), new Function<Object, Pair<String, Icon>>() {
134 public Pair<String, Icon> fun(final Object s) {
135 return Pair.create(ElementPresentationManager.getElementName(s), ElementPresentationManager.getIcon(s));
143 static Factory<List<Pair<String, Icon>>> createEnumFactory(final Class<? extends Enum> aClass) {
144 return new Factory<List<Pair<String, Icon>>>() {
145 public List<Pair<String, Icon>> create() {
146 return ContainerUtil.map2List(aClass.getEnumConstants(), new Function<Enum, Pair<String, Icon>>() {
147 public Pair<String, Icon> fun(final Enum s) {
148 return Pair.create(NamedEnumUtil.getEnumValueByElement(s), ElementPresentationManager.getIcon(s));
155 public static <T extends Enum> JComboBox createEnumComboBox(final Class<T> type) {
156 return tuneUpComboBox(new JComboBox(), createEnumFactory(type));
159 private static JComboBox tuneUpComboBox(final JComboBox comboBox, Factory<List<Pair<String, Icon>>> dataFactory) {
160 final List<Pair<String, Icon>> list = dataFactory.create();
161 final Set<String> standardValues = new HashSet<String>();
162 for (final Pair<String, Icon> s : list) {
163 comboBox.addItem(s);
164 standardValues.add(s.first);
166 return initComboBox(comboBox, new Condition<String>() {
167 public boolean value(final String object) {
168 return standardValues.contains(object);
173 static JComboBox initComboBox(final JComboBox comboBox, final Condition<String> validity) {
174 comboBox.setEditable(false);
175 comboBox.setPrototypeDisplayValue(Pair.create("A", null));
176 comboBox.setRenderer(new DefaultListCellRenderer() {
177 public Component getListCellRendererComponent(JList list, Object value, int index, boolean isSelected, boolean cellHasFocus) {
178 super.getListCellRendererComponent(list, value, index, isSelected, cellHasFocus);
179 final Pair<String, Icon> pair = (Pair<String, Icon>)value;
180 final String text = pair == null ? null : pair.first;
181 setText(text);
182 final Dimension dimension = getPreferredSize();
183 if (!validity.value(text)) {
184 setFont(getFont().deriveFont(Font.ITALIC));
185 setForeground(Color.RED);
187 setIcon(pair == null ? null : pair.second);
188 setPreferredSize(new Dimension(-1, dimension.height));
189 return this;
192 return comboBox;
195 protected JComboBox createMainComponent(final JComboBox boundedComponent) {
196 return tuneUpComboBox(boundedComponent == null ? new JComboBox() : boundedComponent, myDataFactory);
199 public boolean isValidValue(final String object) {
200 return myNullable && object == EMPTY.first || myIcons.containsKey(object);
203 private boolean dataChanged(List<Pair<String, Icon>> newData) {
204 final JComboBox comboBox = getComponent();
205 final int size = comboBox.getItemCount();
206 final List<Pair<String, Icon>> oldData = new ArrayList<Pair<String, Icon>>(size);
207 for (int i = 0; i < size; i++) {
208 oldData.add((Pair<String, Icon>)comboBox.getItemAt(i));
211 if (myNullable) {
212 final LinkedList<Pair<String, Icon>> list = new LinkedList<Pair<String, Icon>>(newData);
213 list.addFirst(EMPTY);
214 newData = list;
217 return !newData.equals(oldData);
220 protected void doReset() {
221 final List<Pair<String, Icon>> data = myDataFactory.create();
222 final JComboBox comboBox = getComponent();
223 comboBox.removeActionListener(myCommitListener);
224 try {
225 if (!dataChanged(data)) {
226 super.doReset();
227 return;
230 final String oldValue = getValue();
231 myIcons.clear();
232 comboBox.removeAllItems();
233 if (myNullable) {
234 comboBox.addItem(EMPTY);
236 for (final Pair<String, Icon> s : data) {
237 comboBox.addItem(s);
238 myIcons.put(s.first, s.second);
240 setValue(oldValue);
241 super.doReset();
243 finally {
244 comboBox.addActionListener(myCommitListener);
248 @Nullable
249 protected final String getValue() {
250 final Pair<String, Icon> pair = (Pair<String, Icon>)getComponent().getSelectedItem();
251 return pair == null || pair == EMPTY ? null : pair.first;
254 protected final void setValue(final String value) {
255 final JComboBox component = getComponent();
256 if (!isValidValue(value)) {
257 component.setEditable(true);
259 component.setSelectedItem(Pair.create(value, myIcons.get(value)));
260 component.setEditable(false);
264 protected void updateComponent() {
265 final DomElement domElement = getDomElement();
266 if (domElement == null || !domElement.isValid()) return;
268 final JComboBox comboBox = getComponent();
270 final Project project = getProject();
271 ApplicationManager.getApplication().invokeLater(new Runnable() {
272 public void run() {
273 if (!project.isOpen()) return;
274 if (!getDomWrapper().isValid()) return;
276 final DomElement domElement = getDomElement();
277 if (domElement == null || !domElement.isValid()) return;
279 final DomElementAnnotationsManager manager = DomElementAnnotationsManager.getInstance(project);
280 final DomElementsProblemsHolder holder = manager.getCachedProblemHolder(domElement);
281 final List<DomElementProblemDescriptor> errorProblems = holder.getProblems(domElement, true);
282 final List<DomElementProblemDescriptor> warningProblems = holder.getProblems(domElement, true, true, HighlightSeverity.WARNING);
284 Color background = getDefaultBackground();
285 comboBox.setToolTipText(null);
287 if (errorProblems.size() > 0) {
288 background = getErrorBackground();
289 comboBox.setToolTipText(TooltipUtils.getTooltipText(errorProblems));
291 else if (warningProblems.size() > 0) {
292 background = getWarningBackground();
293 comboBox.setToolTipText(TooltipUtils.getTooltipText(warningProblems));
296 final Pair<String, Icon> pair = (Pair<String, Icon>)comboBox.getSelectedItem();
297 final String s = pair == null ? null : pair.first;
298 background = s != null && s.trim().length() > 0 ? getDefaultBackground() : background;
300 comboBox.setBackground(background);
301 comboBox.getEditor().getEditorComponent().setBackground(background);