1
+ /*
2
+ * Copyright (c) 2025 derreisende77.
3
+ * This code was developed as part of the MediathekView project https://github.com/mediathekview/MediathekView
4
+ *
5
+ * This program is free software: you can redistribute it and/or modify
6
+ * it under the terms of the GNU General Public License as published by
7
+ * the Free Software Foundation, either version 3 of the License, or
8
+ * (at your option) any later version.
9
+ *
10
+ * This program is distributed in the hope that it will be useful,
11
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
12
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13
+ * GNU General Public License for more details.
14
+ *
15
+ * You should have received a copy of the GNU General Public License
16
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
17
+ */
18
+
19
+ package mediathek .tool .swing ;
20
+
21
+ import com .jidesoft .swing .Searchable ;
22
+ import com .jidesoft .swing .SearchableProvider ;
23
+ import com .jidesoft .swing .event .SearchableEvent ;
24
+
25
+ import javax .swing .*;
26
+ import javax .swing .event .ListDataEvent ;
27
+ import javax .swing .event .ListDataListener ;
28
+ import javax .swing .event .PopupMenuEvent ;
29
+ import javax .swing .event .PopupMenuListener ;
30
+ import java .awt .event .KeyAdapter ;
31
+ import java .awt .event .KeyEvent ;
32
+ import java .beans .PropertyChangeEvent ;
33
+ import java .beans .PropertyChangeListener ;
34
+
35
+ public class ComboBoxSearchable2 extends Searchable implements ListDataListener , PropertyChangeListener , PopupMenuListener {
36
+
37
+ public ComboBoxSearchable2 (final JComboBox <?> comboBox ) {
38
+ super (comboBox );
39
+
40
+ // to avoid conflict with default type-match feature of JComboBox.
41
+ comboBox .setKeySelectionManager ((key , model ) -> -1 );
42
+ comboBox .getModel ().addListDataListener (this );
43
+ comboBox .addPropertyChangeListener ("model" , this );
44
+ comboBox .addPopupMenuListener (this );
45
+
46
+ if (comboBox .isEditable ()) {
47
+ final var textField = (JTextField ) comboBox .getEditor ().getEditorComponent ();
48
+ textField .addKeyListener (new KeyAdapter () {
49
+ @ Override
50
+ public void keyReleased (KeyEvent e ) {
51
+ if (e .getKeyChar () != KeyEvent .CHAR_UNDEFINED && e .getKeyCode () != KeyEvent .VK_ENTER
52
+ && e .getKeyCode () != KeyEvent .VK_ESCAPE ) {
53
+ String text = textField .getText ();
54
+ textChanged (text );
55
+ }
56
+ }
57
+ });
58
+ setSearchableProvider (new MySearchableProvider (textField ));
59
+ }
60
+ }
61
+
62
+ @ Override
63
+ public void uninstallListeners () {
64
+ super .uninstallListeners ();
65
+ if (_component instanceof JComboBox <?> cb ) {
66
+ cb .getModel ().removeListDataListener (this );
67
+ cb .removePopupMenuListener (this );
68
+ }
69
+ _component .removePropertyChangeListener ("model" , this );
70
+ }
71
+
72
+ @ Override
73
+ protected void setSelectedIndex (int index , boolean incremental ) {
74
+ var comboBox = (JComboBox <?>) _component ;
75
+ if (comboBox .getSelectedIndex () != index ) {
76
+ try {
77
+ comboBox .setSelectedIndex (index );
78
+ } catch (Exception ignore ) {
79
+ }
80
+ }
81
+ }
82
+
83
+ @ Override
84
+ protected int getSelectedIndex () {
85
+ return ((JComboBox <?>) _component ).getSelectedIndex ();
86
+ }
87
+
88
+ @ Override
89
+ protected Object getElementAt (int index ) {
90
+ var comboBoxModel = ((JComboBox <?>) _component ).getModel ();
91
+ return comboBoxModel .getElementAt (index );
92
+ }
93
+
94
+ @ Override
95
+ protected int getElementCount () {
96
+ var comboBoxModel = ((JComboBox <?>) _component ).getModel ();
97
+ return comboBoxModel .getSize ();
98
+ }
99
+
100
+ /**
101
+ * Converts the element in JCombobox to string. The returned value will be the <code>toString()</code> of whatever
102
+ * element that returned from <code>list.getModel().getElementAt(i)</code>.
103
+ *
104
+ * @param object the object to be converted
105
+ * @return the string representing the element in the JComboBox.
106
+ */
107
+ @ Override
108
+ protected String convertElementToString (Object object ) {
109
+ if (object != null ) {
110
+ return object .toString ();
111
+ } else {
112
+ return "" ;
113
+ }
114
+ }
115
+
116
+ public void contentsChanged (ListDataEvent e ) {
117
+ if (!isProcessModelChangeEvent ()) {
118
+ return ;
119
+ }
120
+ if (e .getIndex0 () == -1 && e .getIndex1 () == -1 ) {
121
+ //ignore
122
+ } else {
123
+ hidePopup ();
124
+ fireSearchableEvent (new SearchableEvent (this , SearchableEvent .SEARCHABLE_MODEL_CHANGE ));
125
+ }
126
+ }
127
+
128
+ public void intervalAdded (ListDataEvent e ) {
129
+ if (!isProcessModelChangeEvent ()) {
130
+ return ;
131
+ }
132
+ hidePopup ();
133
+ fireSearchableEvent (new SearchableEvent (this , SearchableEvent .SEARCHABLE_MODEL_CHANGE ));
134
+ }
135
+
136
+ public void intervalRemoved (ListDataEvent e ) {
137
+ if (!isProcessModelChangeEvent ()) {
138
+ return ;
139
+ }
140
+ hidePopup ();
141
+ fireSearchableEvent (new SearchableEvent (this , SearchableEvent .SEARCHABLE_MODEL_CHANGE ));
142
+ }
143
+
144
+ public void propertyChange (PropertyChangeEvent evt ) {
145
+ if ("model" .equals (evt .getPropertyName ())) {
146
+ hidePopup ();
147
+
148
+ if (evt .getOldValue () instanceof ComboBoxModel ) {
149
+ ((ComboBoxModel <?>) evt .getOldValue ()).removeListDataListener (this );
150
+ }
151
+
152
+ if (evt .getNewValue () instanceof ComboBoxModel ) {
153
+ ((ComboBoxModel <?>) evt .getNewValue ()).addListDataListener (this );
154
+ }
155
+ fireSearchableEvent (new SearchableEvent (this , SearchableEvent .SEARCHABLE_MODEL_CHANGE ));
156
+ }
157
+ }
158
+
159
+ public void popupMenuWillBecomeVisible (PopupMenuEvent e ) {
160
+ }
161
+
162
+ public void popupMenuWillBecomeInvisible (PopupMenuEvent e ) {
163
+ if (isHideSearchPopupOnEvent ()) {
164
+ hidePopup ();
165
+ }
166
+ }
167
+
168
+ public void popupMenuCanceled (PopupMenuEvent e ) {
169
+ }
170
+
171
+ private record MySearchableProvider (JTextField textField ) implements SearchableProvider {
172
+
173
+ @ Override
174
+ public String getSearchingText () {
175
+ return textField .getText ();
176
+ }
177
+
178
+ @ Override
179
+ public boolean isPassive () {
180
+ return true ;
181
+ }
182
+
183
+ @ Override
184
+ public void processKeyEvent (KeyEvent e ) {
185
+ }
186
+ }
187
+ }
0 commit comments