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
;
35 import java
.awt
.event
.ItemEvent
;
36 import java
.awt
.event
.ItemListener
;
38 import java
.util
.List
;
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
) {
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
) {
61 myDataFactory
= dataFactory
;
65 public ComboControl(final DomWrapper
<String
> domWrapper
, final Class
<?
extends Enum
> aClass
) {
67 myDataFactory
= createEnumFactory(aClass
);
71 public final boolean isNullable() {
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() {
90 public DomElement
getInvocationElement() {
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);
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() {
120 public DomElement
getInvocationElement() {
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() {
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
;
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
));
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
));
233 final LinkedList
<Pair
<String
, Icon
>> list
= new LinkedList
<Pair
<String
, Icon
>>(newData
);
234 list
.addFirst(EMPTY
);
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
);
250 if (!dataChanged(data
)) {
255 final String oldValue
= getValue();
257 comboBox
.removeAllItems();
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
);
269 comboBox
.addItemListener(myCommitListener
);
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() {
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
);