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