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