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