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