Merge branch 'release/3.12.0'
[taxeditor.git] / eu.etaxonomy.taxeditor.store / src / main / java / eu / etaxonomy / taxeditor / ui / element / AbstractFormSection.java
1 /**
2 *
3 */
4 package eu.etaxonomy.taxeditor.ui.element;
5
6 import java.util.ConcurrentModificationException;
7 import java.util.HashSet;
8 import java.util.List;
9 import java.util.Set;
10
11 import org.eclipse.core.runtime.Assert;
12 import org.eclipse.jface.util.IPropertyChangeListener;
13 import org.eclipse.jface.util.PropertyChangeEvent;
14 import org.eclipse.jface.viewers.ISelectionChangedListener;
15 import org.eclipse.jface.viewers.ISelectionProvider;
16 import org.eclipse.jface.viewers.IStructuredSelection;
17 import org.eclipse.jface.viewers.SelectionChangedEvent;
18 import org.eclipse.jface.viewers.StructuredSelection;
19 import org.eclipse.swt.SWT;
20 import org.eclipse.swt.events.SelectionEvent;
21 import org.eclipse.swt.events.SelectionListener;
22 import org.eclipse.swt.graphics.Color;
23 import org.eclipse.swt.widgets.Composite;
24 import org.eclipse.swt.widgets.Control;
25 import org.eclipse.swt.widgets.Display;
26 import org.eclipse.swt.widgets.TypedListener;
27 import org.eclipse.swt.widgets.Widget;
28 import org.eclipse.ui.IEditorPart;
29 import org.eclipse.ui.forms.widgets.Section;
30 import org.eclipse.ui.forms.widgets.TableWrapLayout;
31 import org.eclipse.ui.forms.widgets.ToggleHyperlink;
32
33 import eu.etaxonomy.cdm.api.conversation.ConversationHolder;
34 import eu.etaxonomy.cdm.api.conversation.IConversationEnabled;
35 import eu.etaxonomy.cdm.persistence.hibernate.CdmDataChangeMap;
36 import eu.etaxonomy.taxeditor.model.AbstractUtility;
37 import eu.etaxonomy.taxeditor.model.MessagingUtils;
38
39 /**
40 * <p>
41 * Abstract super class for a {@link Section} GUI element that visualizes a CDM
42 * entity, manages a conversation and listens to selections
43 * </p>
44 *
45 * @param <ENTITY> A CDM entity which should be visualized by this section.
46 *
47 * @author n.hoffmann
48 * @created Feb 22, 2010
49 * @version 1.0
50 * @param <T>
51 */
52 //TODO shouldn't ENTITY be bound with super class ICdmBase for example (AbstractFormSection<ENTITY extends ICdmBase>)?
53 public abstract class AbstractFormSection<ENTITY> extends Section implements ISelectionChangedListener, IEntityElement<ENTITY>, IConversationEnabled {
54
55 /**
56 * The default number of columns in detail sections
57 */
58 public static final int DEFAULT_NUM_COLUMNS = 2;
59
60 private ISelectionProvider selectionProvider;
61
62 private ENTITY entity;
63
64 private final Set<ICdmFormElement> elements = new HashSet<ICdmFormElement>();
65
66 protected CdmFormFactory formFactory;
67
68 private List<IPropertyChangeListener> propertyChangeListeners;
69
70 private ICdmFormElement parentElement;
71
72 private Color persistentBackgroundColor;
73
74 /**
75 * <p>
76 * Constructor for AbstractFormSection.
77 * </p>
78 *
79 * @param conversation
80 * TODO
81 * @param style
82 * a int.
83 * @param formFactory
84 * a {@link eu.etaxonomy.taxeditor.ui.element.CdmFormFactory}
85 * object.
86 * @param parentElement
87 * a {@link eu.etaxonomy.taxeditor.ui.element.ICdmFormElement}
88 * object.
89 * @param <ENTITY>
90 * a ENTITY object.
91 */
92 protected AbstractFormSection(CdmFormFactory formFactory, ICdmFormElement parentElement, int style) {
93 super(parentElement.getLayoutComposite(), style);
94
95 this.parentElement = parentElement;
96
97 this.formFactory = formFactory;
98
99 this.setLayoutData(LayoutConstants.FILL());
100
101 Composite client = formFactory.createComposite(this, SWT.WRAP);
102 client.setBackgroundMode(SWT.INHERIT_DEFAULT);
103
104 TableWrapLayout layout = LayoutConstants.LAYOUT();
105 layout.bottomMargin = 10;
106 layout.rightMargin = 5;
107
108 client.setLayout(layout);
109
110 this.setClient(client);
111
112 }
113
114 /**
115 * <p>
116 * Constructor for AbstractFormSection.
117 * </p>
118 *
119 * @param formFactory
120 * a {@link eu.etaxonomy.taxeditor.ui.element.CdmFormFactory}
121 * object.
122 * @param conversation
123 * a {@link eu.etaxonomy.cdm.api.conversation.ConversationHolder}
124 * object.
125 * @param parentElement
126 * a {@link eu.etaxonomy.taxeditor.ui.element.ICdmFormElement}
127 * object.
128 * @param selectionProvider
129 * a {@link org.eclipse.jface.viewers.ISelectionProvider} object.
130 * @param style
131 * a int.
132 */
133 protected AbstractFormSection(CdmFormFactory formFactory, ICdmFormElement parentElement, ISelectionProvider selectionProvider, int style) {
134 this(formFactory, parentElement, style);
135 this.selectionProvider = selectionProvider;
136 }
137
138 /**
139 * <p>
140 * Getter for the field <code>propertyChangeListeners</code>.
141 * </p>
142 *
143 * @return a {@link java.util.Set} object.
144 */
145 @Override
146 public List<IPropertyChangeListener> getPropertyChangeListeners() {
147 return propertyChangeListeners;
148 }
149
150 /** {@inheritDoc} */
151 @Override
152 public void setPropertyChangeListeners(
153 List<IPropertyChangeListener> propertyChangeListeners) {
154 this.propertyChangeListeners = propertyChangeListeners;
155 }
156
157 /**
158 * <p>
159 * Setter for the field <code>entity</code>.
160 * </p>
161 *
162 * @param entity
163 * a ENTITY object.
164 */
165 public void setEntity(ENTITY entity) {
166 this.entity = entity;
167 }
168
169 /*
170 * (non-Javadoc)
171 *
172 * @see eu.etaxonomy.taxeditor.forms.IEntityElement#getEntity()
173 */
174 /**
175 * <p>
176 * Getter for the field <code>entity</code>.
177 * </p>
178 *
179 * @return a ENTITY object.
180 */
181 @Override
182 public ENTITY getEntity() {
183 return entity;
184 }
185
186 /**
187 * <p>
188 * getToggle
189 * </p>
190 *
191 * @return a {@link org.eclipse.ui.forms.widgets.ToggleHyperlink} object.
192 */
193 public ToggleHyperlink getToggle() {
194 return this.toggle;
195 }
196
197 /**
198 * <p>
199 * getSection
200 * </p>
201 *
202 * @return a {@link eu.etaxonomy.taxeditor.ui.element.AbstractFormSection}
203 * object.
204 */
205 public AbstractFormSection<ENTITY> getSection() {
206 return this;
207 }
208
209 /*
210 * (non-Javadoc)
211 *
212 * @see
213 * eu.etaxonomy.taxeditor.forms.IPropertyChangeEmitter#firePropertyChangeEvent
214 * ()
215 */
216 /** {@inheritDoc} */
217 @Override
218 public void firePropertyChangeEvent(CdmPropertyChangeEvent event) {
219 Assert.isNotNull(propertyChangeListeners, "No property change listeners.");
220 try {
221 for (Object listener : propertyChangeListeners) {
222 ((IPropertyChangeListener) listener).propertyChange(event);
223 }
224 } catch (ConcurrentModificationException e) {
225 MessagingUtils.warn(getClass(), "ConcurrentModificationException while handling PropertyChangeEvents."
226 + " It seems like this is not critical");
227 }
228 }
229
230 /**
231 * Fires a {@link CdmPropertyChangeEvent} with the given object as source.
232 *
233 * @param object
234 * the object on which the property changed
235 */
236 public void firePropertyChangeEvent(Object object) {
237 firePropertyChangeEvent(object, null);
238 }
239
240 /**
241 * Fires a {@link CdmPropertyChangeEvent} with the given object as source
242 * also containing the originating event
243 *
244 * @param object
245 * the object on which the property changed
246 * @param originatingEvent
247 * the originating event
248 */
249 public void firePropertyChangeEvent(Object object,
250 PropertyChangeEvent originatingEvent) {
251 firePropertyChangeEvent(new CdmPropertyChangeEvent(object,
252 originatingEvent));
253 }
254
255 /*
256 * (non-Javadoc)
257 *
258 * @see org.eclipse.swt.widgets.Composite#setFocus()
259 */
260 /** {@inheritDoc} */
261 @Override
262 public boolean setFocus() {
263 return getClient().setFocus();
264 }
265
266 /*
267 * (non-Javadoc)
268 *
269 * @see
270 * org.eclipse.jface.util.IPropertyChangeListener#propertyChange(org.eclipse
271 * .jface.util.PropertyChangeEvent)
272 */
273 /** {@inheritDoc} */
274 @Override
275 public void propertyChange(PropertyChangeEvent event) {
276 firePropertyChangeEvent(new CdmPropertyChangeEvent(this, event));
277 }
278
279 /*
280 * (non-Javadoc)
281 *
282 * @see
283 * org.eclipse.swt.widgets.Control#setBackground(org.eclipse.swt.graphics
284 * .Color)
285 */
286 /** {@inheritDoc} */
287 @Override
288 public void setBackground(Color color) {
289 for (ICdmFormElement element : getElements()) {
290 element.setBackground(color);
291 }
292 getLayoutComposite().setBackground(color);
293 super.setBackground(color);
294 }
295
296 @Override
297 public void setPersistentBackground(Color color) {
298 persistentBackgroundColor = color;
299 setBackground(color);
300 }
301
302 @Override
303 public Color getPersistentBackground() {
304 return persistentBackgroundColor;
305 }
306
307
308 /**
309 * <p>
310 * widgetSelected
311 * </p>
312 *
313 * @param e
314 * a {@link org.eclipse.swt.events.SelectionEvent} object.
315 */
316 public void widgetSelected(SelectionEvent e) {
317 Widget widget = e.widget;
318
319 if (widget instanceof Control) {
320 Control control = (Control) widget;
321 if (checkControlAncestryForWidget(control)) {
322 if (getEntity() != null) {
323 IStructuredSelection selection = new StructuredSelection(getEntity());
324 if (selectionProvider != null) {
325 selectionProvider.setSelection(selection);
326 }
327 }
328 }
329 }
330 }
331
332 private boolean checkControlAncestryForWidget(Control control) {
333 if (control.equals(this)) {
334 return true;
335 } else {
336 Control parent = control.getParent();
337 if (parent == null) {
338 return false;
339 } else {
340 return checkControlAncestryForWidget(parent);
341 }
342 }
343 }
344
345 /** {@inheritDoc} */
346 @Override
347 public void setSelected(boolean selected) {
348 if (selected) {
349 setBackground(Display.getCurrent().getSystemColor(
350 SWT.COLOR_LIST_SELECTION));
351 } else {
352 setBackground(Display.getCurrent().getSystemColor(SWT.COLOR_WHITE));
353 }
354 }
355
356 /** {@inheritDoc} */
357 @Override
358 public void selectionChanged(SelectionChangedEvent event) {
359 if (event.getSelection() == CdmFormFactory.EMPTY_SELECTION) {
360 return;
361 }
362
363 IStructuredSelection selection = (IStructuredSelection) event
364 .getSelection();
365 setSelected(false);
366
367 Object selectedObject = selection.getFirstElement();
368
369 if (selectedObject != null && selectedObject.equals(getEntity())) {
370 setSelected(true);
371 }
372 }
373
374 /**
375 * <p>
376 * addSelectionListener
377 * </p>
378 *
379 * @param listener
380 * a {@link org.eclipse.swt.events.SelectionListener} object.
381 */
382 public void addSelectionListener(SelectionListener listener) {
383 addListener(SWT.Selection, new TypedListener(listener));
384 }
385
386 /**
387 * <p>
388 * removeSelectionListener
389 * </p>
390 *
391 * @param listener
392 * a {@link org.eclipse.swt.events.SelectionListener} object.
393 */
394 public void removeSelectionListener(SelectionListener listener) {
395 removeListener(SWT.Selection, listener);
396 }
397
398 /** {@inheritDoc} */
399 @Override
400 public void addElement(ICdmFormElement element) {
401 elements.add(element);
402 }
403
404 /**
405 * <p>
406 * removeElement
407 * </p>
408 *
409 * @param element
410 * a {@link eu.etaxonomy.taxeditor.ui.element.ICdmFormElement}
411 * object.
412 */
413 protected void removeElement(ICdmFormElement element) {
414 elements.remove(element);
415 }
416
417 /**
418 * <p>
419 * removeElements
420 * </p>
421 */
422 @Override
423 public void removeElements() {
424 for (ICdmFormElement childElement : getElements()) {
425 // recursion
426 childElement.removeElements();
427
428 // unregister selection arbitrator
429 if (childElement instanceof ISelectableElement) {
430 ISelectableElement selectableElement = (ISelectableElement) childElement;
431 if (selectableElement.getSelectionArbitrator() != null) {
432 formFactory.destroySelectionArbitrator(selectableElement
433 .getSelectionArbitrator());
434 }
435 }
436
437 // unregister propertyChangeListener
438 formFactory.removePropertyChangeListener(childElement);
439
440 // dispose of the controls
441 for (Control control : childElement.getControls()) {
442 // we added the layoutComposite of the parental element as the
443 // layout composite to this formElement
444 // but we do not want to destroy it.
445 if (control.equals(childElement.getLayoutComposite())) {
446 continue;
447 } else {
448 control.dispose();
449 control = null;
450 }
451 }
452 }
453
454 elements.clear();
455 }
456
457 /**
458 * <p>
459 * Getter for the field <code>parentElement</code>.
460 * </p>
461 *
462 * @return a {@link eu.etaxonomy.taxeditor.ui.element.ICdmFormElement} object.
463 */
464 @Override
465 public ICdmFormElement getParentElement() {
466 return parentElement;
467 }
468
469 /**
470 * <p>
471 * Getter for the field <code>elements</code>.
472 * </p>
473 *
474 * @return a {@link java.util.Set} object.
475 */
476 @Override
477 public Set<ICdmFormElement> getElements() {
478 return elements;
479 }
480
481 /**
482 * <p>
483 * getControls
484 * </p>
485 *
486 * @return a {@link java.util.Set} object.
487 */
488 @Override
489 public Set<Control> getControls() {
490 Set<Control> controls = new HashSet<Control>();
491
492 for (Control control : getChildren()) {
493 controls.add(control);
494 }
495
496 return controls;
497 }
498
499 /** {@inheritDoc} */
500 @Override
501 public void dispose() {
502 removeElements();
503 super.dispose();
504 }
505
506 /**
507 * <p>
508 * getLayoutComposite
509 * </p>
510 *
511 * @return a {@link org.eclipse.swt.widgets.Composite} object.
512 */
513 @Override
514 public Composite getLayoutComposite() {
515 return (Composite) getClient();
516 }
517
518 /** {@inheritDoc} */
519 @Override
520 public boolean containsFormElement(ICdmFormElement formElement) {
521 if (formElement == this) {
522 return true;
523 } else {
524 for (ICdmFormElement element : getElements()) {
525 boolean contains = element.containsFormElement(formElement);
526 if (contains == true) {
527 return true;
528 }
529 }
530 return false;
531 }
532 }
533
534 /**
535 * <p>
536 * Getter for the field <code>formFactory</code>.
537 * </p>
538 *
539 * @return a {@link eu.etaxonomy.taxeditor.ui.element.CdmFormFactory} object.
540 */
541 @Override
542 public CdmFormFactory getFormFactory() {
543 return formFactory;
544 }
545
546 /*
547 * (non-Javadoc)
548 *
549 * @see eu.etaxonomy.taxeditor.forms.ICdmFormElement#refresh()
550 */
551 /**
552 * <p>
553 * refresh
554 * </p>
555 */
556 @Override
557 public void refresh() {
558 // empty default implementation
559
560 }
561
562 /**
563 * <p>
564 * getConversationHolder
565 * </p>
566 *
567 * @return a {@link eu.etaxonomy.cdm.api.conversation.ConversationHolder}
568 * object.
569 */
570 @Override
571 public ConversationHolder getConversationHolder() {
572 if(AbstractUtility.getActivePart() instanceof IConversationEnabled){
573 return ((IConversationEnabled) AbstractUtility.getActivePart()).getConversationHolder();
574 }
575 if(getParentElement() instanceof RootElement || getParentElement() == null){
576
577 IEditorPart activeEditor = AbstractUtility.getActiveEditor();
578 if(activeEditor instanceof IConversationEnabled){
579 ConversationHolder conversation = ((IConversationEnabled) AbstractUtility.getActiveEditor()).getConversationHolder();
580 return conversation;
581 }
582 }else if(getParentElement() instanceof IConversationEnabled){
583 return ((IConversationEnabled) getParentElement()).getConversationHolder();
584 }
585 MessagingUtils.messageDialog("Could not get conversation for AbstractFormSection",
586 getClass(), "There is an error in the implementation. There should have been an active editor but it wasn't",
587 new IllegalArgumentException());
588 return null;
589
590 }
591
592 /** {@inheritDoc} */
593
594 @Override
595 public void update(CdmDataChangeMap changeEvents) {
596
597 }
598
599
600 }