- combo dropdowns intitially show an empty field which is now removed when selecting...
[taxeditor.git] / eu.etaxonomy.taxeditor.store / src / main / java / eu / etaxonomy / taxeditor / ui / combo / TermComboElement.java
1 /**
2 *
3 */
4 package eu.etaxonomy.taxeditor.ui.combo;
5
6 import java.util.ArrayList;
7 import java.util.Arrays;
8 import java.util.Collections;
9 import java.util.Comparator;
10 import java.util.List;
11
12 import org.eclipse.jface.util.PropertyChangeEvent;
13 import org.eclipse.swt.SWT;
14 import org.eclipse.swt.events.DisposeEvent;
15 import org.eclipse.swt.events.DisposeListener;
16 import org.eclipse.swt.events.SelectionEvent;
17 import org.eclipse.swt.events.SelectionListener;
18 import org.eclipse.swt.graphics.Color;
19 import org.eclipse.swt.widgets.Combo;
20 import org.eclipse.swt.widgets.Label;
21 import org.eclipse.swt.widgets.Listener;
22
23 import eu.etaxonomy.cdm.model.common.DefinedTerm;
24 import eu.etaxonomy.cdm.model.common.DefinedTermBase;
25 import eu.etaxonomy.cdm.model.common.TermType;
26 import eu.etaxonomy.cdm.model.common.TermVocabulary;
27 import eu.etaxonomy.taxeditor.model.MessagingUtils;
28 import eu.etaxonomy.taxeditor.preference.PreferencesUtil;
29 import eu.etaxonomy.taxeditor.preference.Resources;
30 import eu.etaxonomy.taxeditor.store.CdmStore;
31 import eu.etaxonomy.taxeditor.store.StoreUtil;
32 import eu.etaxonomy.taxeditor.store.TermManager;
33 import eu.etaxonomy.taxeditor.ui.element.AbstractCdmFormElement;
34 import eu.etaxonomy.taxeditor.ui.element.CdmFormFactory;
35 import eu.etaxonomy.taxeditor.ui.element.CdmPropertyChangeEvent;
36 import eu.etaxonomy.taxeditor.ui.element.ICdmFormElement;
37 import eu.etaxonomy.taxeditor.ui.element.IEnableableFormElement;
38 import eu.etaxonomy.taxeditor.ui.element.ISelectable;
39 import eu.etaxonomy.taxeditor.ui.element.LayoutConstants;
40
41 /**
42 * <p>
43 * Abstract AbstractTermComboElement class.
44 * </p>
45 *
46 * @author n.hoffmann
47 * @created Nov 5, 2009
48 * @version 1.0
49 * @param <T>
50 */
51 public class TermComboElement<T extends DefinedTermBase>
52 extends AbstractCdmFormElement implements SelectionListener,
53 DisposeListener, IEnableableFormElement, ISelectable {
54
55 private static final int DEFAULT_VISIBLE_ITEMS = 10;
56
57 private T selection;
58
59 private T emptyElement;
60 private static String EMPTY_ELEMENT_LABEL = "";
61
62 protected Label label;
63 private final Combo combo;
64
65 private ArrayList<T> terms;
66
67 private Comparator<T> termComparator;
68
69 private final Class<T> termClass;
70
71 private List<T> customPreferredTerms;
72
73 private boolean addEmptyElement;
74
75 public TermComboElement(CdmFormFactory formFactory,
76 ICdmFormElement parentElement, TermType termType, String labelString, T selection, boolean addEmptyElement,
77 int style) {
78 this(formFactory, parentElement, null, termType, null, labelString, selection, addEmptyElement, style);
79 }
80
81 public TermComboElement(CdmFormFactory formFactory,
82 ICdmFormElement parentElement, TermVocabulary<?> termVocabulary, String labelString, T selection, boolean addEmptyElement,
83 int style) {
84 this(formFactory, parentElement, null, null, termVocabulary, labelString, selection, addEmptyElement, style);
85 }
86
87 public TermComboElement(CdmFormFactory formFactory,
88 ICdmFormElement parentElement, Class<T> termClass, String labelString, T selection, boolean addEmptyElement,
89 int style) {
90 this(formFactory, parentElement, termClass, null, null, labelString, selection, addEmptyElement, style);
91 }
92
93 private TermComboElement(CdmFormFactory formFactory,
94 ICdmFormElement parentElement, Class<T> termClass, TermType termType, TermVocabulary<?> termVocabulary, String labelString, T selection, boolean addEmptyElement,
95 int style) {
96 super(formFactory, parentElement);
97
98 if(termClass!=null){
99 this.termClass = termClass;
100 }
101 else{
102 this.termClass = (Class<T>) DefinedTerm.class;
103 }
104 this.addEmptyElement = addEmptyElement;
105
106 if (labelString != null) {
107 label = formFactory.createLabel(getLayoutComposite(), labelString);
108 addControl(label);
109 }
110
111 // create combo
112 combo = new Combo(getLayoutComposite(), SWT.BORDER | SWT.READ_ONLY );//FIXME: removed this parameter seems break windows version: | style
113 addControl(combo);
114 combo.setLayoutData(LayoutConstants.FILL_HORIZONTALLY());
115 combo.setVisibleItemCount(DEFAULT_VISIBLE_ITEMS);
116
117 if(termType!=null){
118 //TODO try to remove generic T and avoid classes to be used
119 populateTerms((List<T>) getTermManager().getPreferredTerms(termType));
120 }
121 else if(termVocabulary!=null){
122 populateTerms((List<T>) getTermManager().getPreferredTerms(termVocabulary));
123 }
124 else if(this.termClass!=null){
125 populateTerms(getPreferredTerms());
126 }
127
128 combo.addSelectionListener(this);
129 combo.addDisposeListener(this);
130 PreferencesUtil.getPreferenceStore().addPropertyChangeListener(this);
131
132 if (selection != null) {
133 setSelection(selection);
134 }
135 }
136
137 /**
138 * <p>
139 * Getter for the field <code>selection</code>.
140 * </p>
141 *
142 * @return a T object.
143 */
144 public T getSelection() {
145 return selection;
146 }
147
148 /**
149 * <p>Sets the selection of the combo to the given T object.</p>
150 * <p>Passing <code>null</code> to this method will set the selection to
151 * the empty element and effectively clear the selection</p>
152 *
153 * @param selection
154 * a T object or <code>null</code> to clear the selection
155 */
156 public void setSelection(T selection) {
157 this.selection = selection;
158
159 Listener[] listeners = combo.getListeners(SWT.Selection);
160
161 for (Listener listener : listeners) {
162 combo.removeListener(SWT.Selection, listener);
163 }
164 int selectedIndex;
165 if(selection == null){
166 // set selection to the emptyElement
167 selectedIndex = 0;
168 }else{
169 selectedIndex = terms.indexOf(selection);
170 if (selectedIndex == -1) {
171 createTermNotInPreferredTerms(selection);
172 selectedIndex = terms.indexOf(selection);
173 }
174 }
175 combo.select(selectedIndex);
176
177 for (Listener listener : listeners) {
178 combo.addListener(SWT.Selection, listener);
179 }
180 }
181
182 /**
183 * Fills the combo with elements and sets up the convenience functions
184 * for selection index
185 *
186 * @param preferredTerms
187 */
188 private void populateTerms(List<T> preferredTerms) {
189
190 combo.removeAll();
191
192 terms = new ArrayList<T>();
193
194 int i = 1;
195 int index = 0;
196
197 if(addEmptyElement){
198 // Add an empty element for when nothing was selected yet
199 combo.add(EMPTY_ELEMENT_LABEL);
200 terms.add(emptyElement);
201 }
202
203 if (termComparator != null) {
204 Collections.sort(preferredTerms, termComparator);
205 }
206 for (T term : preferredTerms) {
207 String label = getLabel(term);
208 if (label == null) {
209 if (term.getTitleCache() != null) {
210 label = term.getTitleCache();
211 MessagingUtils.warn(getClass(),
212 "Term does not have a default language representation: " + label
213 + ", " + term.getUuid());
214 } else {
215 label = "Unknown";
216 MessagingUtils.warn(getClass(),
217 "Representation Label and TitleCache empty for term: "
218 + term + ", " + term.getUuid());
219 }
220
221 }
222
223 combo.add(label);
224 terms.add(term);
225
226 i++;
227 if (selection != null) {
228 if (selection.equals(term)) {
229 index = i;
230 }
231 }
232 }
233
234 if (selection != null && index == 0) {
235 createTermNotInPreferredTerms(selection);
236 }
237
238 combo.select(index);
239 }
240
241 /*
242 * (non-Javadoc)
243 * @see eu.etaxonomy.taxeditor.forms.IEnableableFormElement#setEnabled(boolean)
244 */
245 /** {@inheritDoc} */
246 @Override
247 public void setEnabled(boolean enabled) {
248 combo.setEnabled(enabled);
249 }
250
251 /* (non-Javadoc)
252 * @see eu.etaxonomy.taxeditor.ui.element.IEnableableFormElement#isEnabled()
253 */
254 @Override
255 public boolean isEnabled() {
256 return combo.isEnabled();
257 }
258
259 /**
260 * <p>
261 * preferredTerms
262 * </p>
263 *
264 * @return a {@link java.util.List} object.
265 */
266 protected List<T> getPreferredTerms(){
267 if (customPreferredTerms != null){
268 return customPreferredTerms;
269 }
270 return getTermManager().getPreferredTerms(termClass);
271 }
272
273 /**
274 * May be overridden by derived classes if the desired label string does not
275 * reside in term.getLabel();
276 *
277 * @param term
278 * a T object.
279 * @return a {@link java.lang.String} object.
280 */
281 protected String getLabel(T term) {
282 if (term == null){
283 return "";
284 }else{
285 String termLabel = term.getLabel(CdmStore.getDefaultLanguage());
286 if(term.getVocabulary()!=null){
287 termLabel += " ["+term.getVocabulary().getLabel(CdmStore.getDefaultLanguage())+"]";
288 }
289 return termLabel;
290 }
291 }
292
293 /**
294 *
295 *
296 * @param term
297 */
298 private void createTermNotInPreferredTerms(T term) {
299 List<T> preferredTerms = getPreferredTerms();
300
301 preferredTerms.add(term);
302
303 populateTerms(preferredTerms);
304 }
305
306 /**
307 * <p>
308 * addSelectionListener
309 * </p>
310 *
311 * @param listener
312 * a {@link org.eclipse.swt.events.SelectionListener} object.
313 */
314 public void addSelectionListener(SelectionListener listener) {
315 combo.addSelectionListener(listener);
316 }
317
318 /**
319 * <p>
320 * removeSelectionListener
321 * </p>
322 *
323 * @param listener
324 * a {@link org.eclipse.swt.events.SelectionListener} object.
325 */
326 public void removeSelectionListener(SelectionListener listener) {
327 combo.removeSelectionListener(listener);
328 }
329
330 /*
331 * (non-Javadoc)
332 *
333 * @see
334 * org.eclipse.swt.events.SelectionListener#widgetSelected(org.eclipse.swt
335 * .events.SelectionEvent)
336 */
337 /** {@inheritDoc} */
338 @Override
339 public void widgetSelected(SelectionEvent e) {
340 selection = terms.get(combo.getSelectionIndex());
341 firePropertyChangeEvent(new CdmPropertyChangeEvent(this, e));
342 }
343
344 /*
345 * (non-Javadoc)
346 *
347 * @see java.beans.PropertyChangeListener#propertyChange(java.beans.
348 * PropertyChangeEvent)
349 */
350 /** {@inheritDoc} */
351 @Override
352 public void propertyChange(PropertyChangeEvent event) {
353 super.propertyChange(event);
354 if (event != null
355 && PreferencesUtil.PREFERRED_TERMS_CHANGE.equals(event
356 .getProperty())) {
357 populateTerms(getPreferredTerms());
358 }
359 }
360
361 /** {@inheritDoc} */
362 @Override
363 public void setSelected(boolean selected) {
364 setBackground(selected ? SELECTED : getPersistentBackground());
365 }
366
367 /** {@inheritDoc} */
368 @Override
369 public void widgetDisposed(DisposeEvent e) {
370 PreferencesUtil.getPreferenceStore().removePropertyChangeListener(this);
371 }
372
373 // not used
374 /** {@inheritDoc} */
375 @Override
376 public void widgetDefaultSelected(SelectionEvent e) {
377 }
378
379 /** {@inheritDoc} */
380 @Override
381 public void setIrrelevant(boolean irrelevant) {
382 String colorId = irrelevant ? Resources.COLOR_COMPOSITE_IRRELEVANT
383 : Resources.COLOR_COMPOSITE_BACKGROUND;
384
385 Color color = StoreUtil.getColor(colorId);
386 combo.setBackground(color);
387 }
388
389 /** {@inheritDoc} */
390 @Override
391 public void setBackground(Color color) {
392 if (label != null) {
393 label.setBackground(color);
394 }
395 }
396
397 /**
398 *
399 */
400 protected TermManager getTermManager() {
401 return CdmStore.getTermManager();
402 }
403
404 /**
405 *
406 * @return
407 */
408 public int getVisibleItemCount(){
409 return combo.getVisibleItemCount();
410 }
411
412 /**
413 *
414 * @param count
415 */
416 public void setVisibleItemCount(int count){
417 combo.setVisibleItemCount(count);
418 }
419
420 /**
421 * <p>A {@link List} of term objects may be passed to this combo box. In this case, the default behaviour
422 * of displaying the preferred terms for the T type will be overridden and the combo will only display the
423 * given terms. Also, any previous selection will be reseted.</p>
424 *
425 * <p>To return to the default of displaying the preferred terms, simply pass <code>null</code>.</p>
426 *
427 * @param terms a {@link List} of T objects or <code>null</code> for default preferred terms
428 */
429 public void setTerms(List<T> terms) {
430 setSelection(null);
431 customPreferredTerms = terms;
432 populateTerms(customPreferredTerms);
433 }
434
435 public void removeEmptyElement(){
436 if(addEmptyElement){
437 if(terms.contains(emptyElement)){
438 terms.remove(emptyElement);
439 }
440 if(Arrays.asList(combo.getItems()).contains(EMPTY_ELEMENT_LABEL)){
441 combo.remove(EMPTY_ELEMENT_LABEL);
442 }
443 }
444 }
445 }