1414import com .intellij .ui .components .fields .ExtendableTextField ;
1515import com .microsoft .azure .toolkit .lib .common .messager .AzureMessager ;
1616import com .microsoft .azure .toolkit .lib .common .operation .AzureOperation ;
17- import com .microsoft .azure .toolkit .lib .common .task .AzureTask ;
18- import com .microsoft .azure .toolkit .lib .common .task .AzureTaskManager ;
1917import com .microsoft .azure .toolkit .lib .common .utils .TailingDebouncer ;
2018import lombok .Getter ;
2119import lombok .Setter ;
2523import rx .Observable ;
2624import rx .schedulers .Schedulers ;
2725
26+ import javax .accessibility .AccessibleRelation ;
2827import javax .annotation .Nonnull ;
2928import javax .annotation .Nullable ;
3029import javax .swing .*;
@@ -56,10 +55,7 @@ public abstract class AzureComboBox<T> extends ComboBox<T> implements AzureFormI
5655 private boolean required ;
5756 private Object value ;
5857 private boolean valueNotSet = true ;
59- private String label ;
60- @ Nullable
61- @ Setter
62- protected Boolean valueFixed ;
58+ protected boolean enabled = true ;
6359 @ Getter
6460 @ Setter
6561 private Supplier <? extends List <? extends T >> itemsLoader ;
@@ -73,7 +69,7 @@ public AzureComboBox(boolean refresh) {
7369 this .init ();
7470 this .refresher = new TailingDebouncer (this ::doRefreshItems , DEBOUNCE_DELAY );
7571 if (refresh ) {
76- AzureTaskManager . getInstance (). runLater ( this :: refreshItems , AzureTask . Modality . ANY );
72+ this . refreshItems ( );
7773 }
7874 }
7975
@@ -108,8 +104,7 @@ public void customize(@Nonnull final JList<? extends T> l, final T t, final int
108104 this .addPopupMenuListener (new AzureComboBoxPopupMenuListener ());
109105 }
110106 final TailingDebouncer valueDebouncer = new TailingDebouncer (() -> {
111- @ SuppressWarnings ("unchecked" )
112- final ValueListener <T >[] listeners = this .listenerList .getListeners (ValueListener .class );
107+ @ SuppressWarnings ("unchecked" ) final ValueListener <T >[] listeners = this .listenerList .getListeners (ValueListener .class );
113108 for (final ValueListener <T > listener : listeners ) {
114109 listener .onValueChanged (this .getValue ());
115110 }
@@ -118,9 +113,6 @@ public void customize(@Nonnull final JList<? extends T> l, final T t, final int
118113 if (e .getStateChange () == ItemEvent .SELECTED ) {
119114 this .refreshValue ();
120115 }
121- if (e .getStateChange () == ItemEvent .SELECTED || e .getStateChange () == ItemEvent .DESELECTED ) {
122- valueDebouncer .debounce ();
123- }
124116 });
125117 }
126118
@@ -136,7 +128,7 @@ public void setValue(final T val) {
136128
137129 public void setValue (final T val , final Boolean fixed ) {
138130 Optional .ofNullable (fixed ).ifPresent (f -> {
139- this .valueFixed = fixed ;
131+ this .setEnabled (! fixed ) ;
140132 this .setEditable (!f );
141133 });
142134 this .valueNotSet = false ;
@@ -150,7 +142,7 @@ public void setValue(final ItemReference<T> val) {
150142
151143 public void setValue (final ItemReference <T > val , final Boolean fixed ) {
152144 Optional .ofNullable (fixed ).ifPresent (f -> {
153- this .valueFixed = fixed ;
145+ this .setEnabled (! fixed ) ;
154146 this .setEditable (!f );
155147 });
156148 this .valueNotSet = false ;
@@ -159,23 +151,27 @@ public void setValue(final ItemReference<T> val, final Boolean fixed) {
159151 }
160152
161153 private void refreshValue () {
162- if (Objects .equals (this .value , this .getSelectedItem ())) {
163- return ;
164- }
165- final List <T > items = this .getItems ();
166- if (!this .valueNotSet && this .value instanceof AzureComboBox .ItemReference ) {
167- items .stream ().filter (i -> ((ItemReference <?>) this .value ).is (i )).findFirst ().ifPresent (this ::setValue );
168- }
169- if (this .valueNotSet && this .value == null && !items .isEmpty ()) {
170- super .setSelectedItem (items .get (0 ));
171- } else if (items .contains (this .value )) {
172- super .setSelectedItem (this .value );
173- } else if (value instanceof Draft ) {
174- // todo: unify model for custom created resource
175- super .addItem ((T ) value );
176- super .setSelectedItem (value );
154+ if (this .valueNotSet ) {
155+ if (this .getItemCount () > 0 && this .getSelectedIndex () != 0 ) {
156+ super .setSelectedIndex (0 );
157+ }
177158 } else {
178- super .setSelectedItem (null );
159+ final Object selected = this .getSelectedItem ();
160+ if (Objects .equals (selected , this .value ) || (this .value instanceof ItemReference && ((ItemReference <?>) this .value ).is (selected ))) {
161+ return ;
162+ }
163+ final List <T > items = this .getItems ();
164+ if (this .value instanceof AzureComboBox .ItemReference ) {
165+ items .stream ().filter (i -> ((ItemReference <?>) this .value ).is (i )).findFirst ().ifPresent (this ::setValue );
166+ } else if (this .value instanceof Draft ) {
167+ // todo: unify model for custom created resource
168+ super .addItem ((T ) this .value );
169+ super .setSelectedItem (this .value );
170+ } else if (items .contains (this .value )) {
171+ super .setSelectedItem (this .value );
172+ } else {
173+ super .setSelectedItem (null );
174+ }
179175 }
180176 }
181177
@@ -189,16 +185,16 @@ public void refreshItems() {
189185 }
190186
191187 @ AzureOperation (
192- name = "common|combobox.load_items" ,
193- params = {"this.label ()" },
194- type = AzureOperation .Type .ACTION
188+ name = "common|combobox.load_items" ,
189+ params = {"this.getLabel ()" },
190+ type = AzureOperation .Type .ACTION
195191 )
196192 private void doRefreshItems () {
197193 try {
198194 this .setLoading (true );
199195 final List <? extends T > items = this .loadItemsInner ();
200196 this .setLoading (false );
201- AzureTaskManager . getInstance (). runLater (() -> this .setItems (items ), AzureTask . Modality . ANY );
197+ this .setItems (items );
202198 } catch (final Exception e ) {
203199 final Throwable rootCause = ExceptionUtils .getRootCause (e );
204200 if (rootCause instanceof InterruptedIOException || rootCause instanceof InterruptedException ) {
@@ -217,26 +213,43 @@ public List<T> getItems() {
217213 return result ;
218214 }
219215
220- protected void setItems (final List <? extends T > items ) {
221- this .removeAllItems ();
222- items .forEach (super ::addItem );
223- this .refreshValue ();
216+ protected synchronized void setItems (final List <? extends T > items ) {
217+ SwingUtilities .invokeLater (() -> {
218+ final DefaultComboBoxModel <T > model = (DefaultComboBoxModel <T >) this .getModel ();
219+ model .removeAllElements ();
220+ model .addAll (items );
221+ this .refreshValue ();
222+ });
224223 }
225224
226225 public void clear () {
227- this .setItems (Collections .emptyList ());
226+ final DefaultComboBoxModel <T > model = (DefaultComboBoxModel <T >) this .getModel ();
227+ model .removeAllElements ();
228+ this .refreshValue ();
228229 }
229230
230231 protected void setLoading (final boolean loading ) {
231- AzureTaskManager . getInstance (). runLater (() -> {
232+ SwingUtilities . invokeLater (() -> {
232233 if (loading ) {
233- this .setEnabled (false );
234+ super .setEnabled (false );
234235 this .setEditor (this .loadingSpinner );
235236 } else {
236- this .setEnabled (! Objects . equals ( valueFixed , true ) );
237+ super .setEnabled (this . enabled );
237238 this .setEditor (this .inputEditor );
238239 }
239- }, AzureTask .Modality .ANY );
240+ this .repaint ();
241+ });
242+ }
243+
244+ @ Override
245+ public void setEnabled (boolean b ) {
246+ this .enabled = b ;
247+ super .setEnabled (b );
248+ }
249+
250+ @ Override
251+ public boolean isEnabled () {
252+ return this .enabled || super .isEnabled ();
240253 }
241254
242255 protected String getItemText (Object item ) {
@@ -324,10 +337,10 @@ protected JTextField createEditorComponent() {
324337 protected ExtendableTextComponent .Extension getExtension () {
325338 final ExtendableTextComponent .Extension extension = AzureComboBox .this .getExtension ();
326339 return extension == null ? null : ExtendableTextComponent .Extension .create (
327- extension .getIcon (true ), extension .getTooltip (), () -> {
328- AzureComboBox .this .hidePopup ();
329- extension .getActionOnClick ().run ();
330- });
340+ extension .getIcon (true ), extension .getTooltip (), () -> {
341+ AzureComboBox .this .hidePopup ();
342+ extension .getActionOnClick ().run ();
343+ });
331344 }
332345 }
333346
@@ -344,7 +357,7 @@ public void setItem(Object item) {
344357
345358 protected ExtendableTextComponent .Extension getExtension () {
346359 return ExtendableTextComponent .Extension .create (
347- new AnimatedIcon .Default (), null , null );
360+ new AnimatedIcon .Default (), null , null );
348361 }
349362 }
350363
@@ -359,7 +372,7 @@ public void popupMenuWillBecomeVisible(final PopupMenuEvent e) {
359372 itemList = AzureComboBox .this .getItems ();
360373 // todo: support customized combo box filter
361374 comboFilterListener = new ComboFilterListener (itemList ,
362- (item , input ) -> StringUtils .containsIgnoreCase (getItemText (item ), input ));
375+ (item , input ) -> StringUtils .containsIgnoreCase (getItemText (item ), input ));
363376 getEditorComponent ().getDocument ().addDocumentListener (comboFilterListener );
364377 }
365378
@@ -397,28 +410,23 @@ public ComboFilterListener(List<? extends T> list, BiPredicate<? super T, ? supe
397410
398411 @ Override
399412 protected void textChanged (@ Nonnull final DocumentEvent documentEvent ) {
400- AzureTaskManager . getInstance (). runLater (() -> {
413+ SwingUtilities . invokeLater (() -> {
401414 try {
402415 final String text = documentEvent .getDocument ().getText (0 , documentEvent .getDocument ().getLength ());
403416 list .stream ().filter (item -> filter .test (item , text ) && !getItems ().contains (item )).forEach (AzureComboBox .this ::addItem );
404417 getItems ().stream ().filter (item -> !filter .test (item , text )).forEach (AzureComboBox .this ::removeItem );
405418 } catch (BadLocationException e ) {
406419 // swallow exception and show all items
407420 }
408- }, AzureTask . Modality . ANY );
421+ });
409422 }
410423 }
411424
412- public void setLabel (final String label ) {
413- this .label = label ;
414- }
415-
416425 public String getLabel () {
417- return Optional .ofNullable (this .label ).orElse ("" );
418- }
419-
420- private String label () {
421- return Optional .ofNullable (this .label ).orElse (this .getClass ().getSimpleName ());
426+ final JLabel label = (JLabel ) this .getClientProperty (AccessibleRelation .LABELED_BY );
427+ return Optional .ofNullable (label ).map (JLabel ::getText )
428+ .map (t -> t .endsWith (":" ) ? t .substring (0 , t .length () - 1 ) : t )
429+ .orElse (this .getClass ().getSimpleName ());
422430 }
423431
424432 public static class ItemReference <T > {
0 commit comments