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