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