2 * Copyright (c) 2005 Your Corporation. All Rights Reserved.
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
;
24 import java
.awt
.event
.ActionEvent
;
25 import java
.awt
.event
.ActionListener
;
27 import java
.util
.List
;
29 import javax
.swing
.text
.JTextComponent
;
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
) {
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
) {
51 myDataFactory
= dataFactory
;
55 public ComboControl(final DomWrapper
<String
> domWrapper
, final Class
<?
extends Enum
> aClass
) {
57 myDataFactory
= createEnumFactory(aClass
);
61 public final boolean isNullable() {
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() {
80 public DomElement
getInvocationElement() {
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
));
95 all
.addAll(ContainerUtil
.map(resolvingConverter
.getAdditionalVariants(), new Function() {
96 public Object
fun(final Object s
) {
97 return new Pair(s
, null);
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() {
114 public DomElement
getInvocationElement() {
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
) {
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
;
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
));
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
));
212 final LinkedList
<Pair
<String
, Icon
>> list
= new LinkedList
<Pair
<String
, Icon
>>(newData
);
213 list
.addFirst(EMPTY
);
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
);
225 if (!dataChanged(data
)) {
230 final String oldValue
= getValue();
232 comboBox
.removeAllItems();
234 comboBox
.addItem(EMPTY
);
236 for (final Pair
<String
, Icon
> s
: data
) {
238 myIcons
.put(s
.first
, s
.second
);
244 comboBox
.addActionListener(myCommitListener
);
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() {
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
);