cdmlib version change
[taxeditor.git] / eu.etaxonomy.taxeditor.store / src / main / java / eu / etaxonomy / taxeditor / ui / forms / AbstractFormSection.java
1 /**
2 *
3 */
4 package eu.etaxonomy.taxeditor.ui.forms;
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.forms.widgets.Section;
29 import org.eclipse.ui.forms.widgets.TableWrapLayout;
30 import org.eclipse.ui.forms.widgets.ToggleHyperlink;
31
32 import eu.etaxonomy.cdm.api.conversation.ConversationHolder;
33 import eu.etaxonomy.cdm.api.conversation.IConversationEnabled;
34 import eu.etaxonomy.cdm.persistence.hibernate.CdmDataChangeMap;
35 import eu.etaxonomy.taxeditor.store.StoreUtil;
36
37 /**
38 * <p>
39 * Abstract AbstractFormSection class.
40 * </p>
41 *
42 * @author n.hoffmann
43 * @created Feb 22, 2010
44 * @version 1.0
45 * @param <T>
46 */
47 public abstract class AbstractFormSection<ENTITY> extends Section implements
48 ISelectionChangedListener, ICdmFormElement, IEntityElement<ENTITY>,
49 IConversationEnabled {
50
51 private ISelectionProvider selectionProvider;
52
53 private ENTITY entity;
54
55 private Set<ICdmFormElement> elements = new HashSet<ICdmFormElement>();
56
57 protected CdmFormFactory formFactory;
58
59 private List<IPropertyChangeListener> propertyChangeListeners;
60
61 private ICdmFormElement parentElement;
62
63 private ConversationHolder conversation;
64
65 private boolean handlingPropertyChange;
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.forms.CdmFormFactory}
80 * object.
81 * @param parentElement
82 * a {@link eu.etaxonomy.taxeditor.ui.forms.ICdmFormElement}
83 * object.
84 * @param <ENTITY>
85 * a ENTITY object.
86 */
87 protected AbstractFormSection(CdmFormFactory formFactory,
88 ConversationHolder conversation, ICdmFormElement parentElement,
89 int style) {
90 super(parentElement.getLayoutComposite(), style);
91
92 this.parentElement = parentElement;
93
94 this.formFactory = formFactory;
95
96 this.conversation = conversation;
97
98 this.setLayoutData(CdmFormFactory.FILL());
99
100 Composite client = formFactory.createComposite(this, SWT.WRAP);
101 client.setBackgroundMode(SWT.INHERIT_DEFAULT);
102
103 TableWrapLayout layout = CdmFormFactory.LAYOUT();
104 layout.bottomMargin = 10;
105 layout.rightMargin = 5;
106
107 client.setLayout(layout);
108
109 this.setClient(client);
110 }
111
112 /**
113 * <p>
114 * Constructor for AbstractFormSection.
115 * </p>
116 *
117 * @param formFactory
118 * a {@link eu.etaxonomy.taxeditor.ui.forms.CdmFormFactory}
119 * object.
120 * @param conversation
121 * a {@link eu.etaxonomy.cdm.api.conversation.ConversationHolder}
122 * object.
123 * @param parentElement
124 * a {@link eu.etaxonomy.taxeditor.ui.forms.ICdmFormElement}
125 * object.
126 * @param selectionProvider
127 * a {@link org.eclipse.jface.viewers.ISelectionProvider} object.
128 * @param style
129 * a int.
130 */
131 protected AbstractFormSection(CdmFormFactory formFactory,
132 ConversationHolder conversation, ICdmFormElement parentElement,
133 ISelectionProvider selectionProvider, int style) {
134 this(formFactory, conversation, 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 public List<IPropertyChangeListener> getPropertyChangeListeners() {
146 return propertyChangeListeners;
147 }
148
149 /** {@inheritDoc} */
150 public void setPropertyChangeListeners(
151 List<IPropertyChangeListener> propertyChangeListeners) {
152 this.propertyChangeListeners = propertyChangeListeners;
153 }
154
155 /**
156 * <p>
157 * Setter for the field <code>entity</code>.
158 * </p>
159 *
160 * @param entity
161 * a ENTITY object.
162 */
163 public void setEntity(ENTITY entity) {
164 this.entity = entity;
165 }
166
167 /*
168 * (non-Javadoc)
169 *
170 * @see eu.etaxonomy.taxeditor.forms.IEntityElement#getEntity()
171 */
172 /**
173 * <p>
174 * Getter for the field <code>entity</code>.
175 * </p>
176 *
177 * @return a ENTITY object.
178 */
179 public ENTITY getEntity() {
180 return entity;
181 }
182
183 /**
184 * <p>
185 * getToggle
186 * </p>
187 *
188 * @return a {@link org.eclipse.ui.forms.widgets.ToggleHyperlink} object.
189 */
190 public ToggleHyperlink getToggle() {
191 return this.toggle;
192 }
193
194 /**
195 * <p>
196 * getSection
197 * </p>
198 *
199 * @return a {@link eu.etaxonomy.taxeditor.ui.forms.AbstractFormSection}
200 * object.
201 */
202 public AbstractFormSection<ENTITY> getSection() {
203 return this;
204 }
205
206 /*
207 * (non-Javadoc)
208 *
209 * @see
210 * eu.etaxonomy.taxeditor.forms.IPropertyChangeEmitter#firePropertyChangeEvent
211 * ()
212 */
213 /** {@inheritDoc} */
214 public void firePropertyChangeEvent(CdmPropertyChangeEvent event) {
215 Assert.isNotNull(propertyChangeListeners,
216 "No property change listeners.");
217 try {
218 for (Object listener : propertyChangeListeners) {
219 ((IPropertyChangeListener) listener).propertyChange(event);
220 }
221 } catch (ConcurrentModificationException e) {
222 StoreUtil.warn(getClass(),
223 "ConcurrentModificationException while handling PropertyChangeEvents."
224 + " It seems like this is not critical");
225 }
226 }
227
228 /**
229 * Fires a {@link CdmPropertyChangeEvent} with the given object as source.
230 *
231 * @param object
232 * the object on which the property changed
233 */
234 public void firePropertyChangeEvent(Object object) {
235 firePropertyChangeEvent(object, null);
236 }
237
238 /**
239 * Fires a {@link CdmPropertyChangeEvent} with the given object as source
240 * also containing the originating event
241 *
242 * @param object
243 * the object on which the property changed
244 * @param originatingEvent
245 * the originating event
246 */
247 public void firePropertyChangeEvent(Object object,
248 PropertyChangeEvent originatingEvent) {
249 firePropertyChangeEvent(new CdmPropertyChangeEvent(object,
250 originatingEvent));
251 }
252
253 /*
254 * (non-Javadoc)
255 *
256 * @see org.eclipse.swt.widgets.Composite#setFocus()
257 */
258 /** {@inheritDoc} */
259 @Override
260 public boolean setFocus() {
261 return getClient().setFocus();
262 }
263
264 /*
265 * (non-Javadoc)
266 *
267 * @see
268 * org.eclipse.jface.util.IPropertyChangeListener#propertyChange(org.eclipse
269 * .jface.util.PropertyChangeEvent)
270 */
271 /** {@inheritDoc} */
272 public void propertyChange(PropertyChangeEvent event) {
273 firePropertyChangeEvent(new CdmPropertyChangeEvent(this, event));
274 }
275
276 /*
277 * (non-Javadoc)
278 *
279 * @see
280 * org.eclipse.swt.widgets.Control#setBackground(org.eclipse.swt.graphics
281 * .Color)
282 */
283 /** {@inheritDoc} */
284 @Override
285 public void setBackground(Color color) {
286 for (ICdmFormElement element : getElements()) {
287 element.setBackground(color);
288 }
289 getLayoutComposite().setBackground(color);
290 super.setBackground(color);
291 }
292
293 @Override
294 public void setPersistentBackground(Color color) {
295 persistentBackgroundColor = color;
296 setBackground(color);
297 }
298
299 @Override
300 public Color getPersistentBackground() {
301 return persistentBackgroundColor;
302 }
303
304
305 /**
306 * <p>
307 * widgetSelected
308 * </p>
309 *
310 * @param e
311 * a {@link org.eclipse.swt.events.SelectionEvent} object.
312 */
313 public void widgetSelected(SelectionEvent e) {
314 Widget widget = e.widget;
315
316 if (widget instanceof Control) {
317 Control control = (Control) widget;
318 if (checkControlAncestryForWidget(control)) {
319 if (getEntity() != null) {
320 IStructuredSelection selection = new StructuredSelection(
321 getEntity());
322 if (selectionProvider != null) {
323 selectionProvider.setSelection(selection);
324 }
325 }
326 }
327 }
328 }
329
330 private boolean checkControlAncestryForWidget(Control control) {
331 if (control.equals(this)) {
332 return true;
333 } else {
334 Control parent = control.getParent();
335 if (parent == null) {
336 return false;
337 } else {
338 return checkControlAncestryForWidget(parent);
339 }
340 }
341 }
342
343 /** {@inheritDoc} */
344 public void setSelected(boolean selected) {
345 if (selected) {
346 setBackground(Display.getCurrent().getSystemColor(
347 SWT.COLOR_LIST_SELECTION));
348 } else {
349 setBackground(Display.getCurrent().getSystemColor(SWT.COLOR_WHITE));
350 }
351 }
352
353 /** {@inheritDoc} */
354 public void selectionChanged(SelectionChangedEvent event) {
355 if (event.getSelection() == CdmFormFactory.EMPTY_SELECTION) {
356 return;
357 }
358
359 IStructuredSelection selection = (IStructuredSelection) event
360 .getSelection();
361 setSelected(false);
362
363 Object selectedObject = selection.getFirstElement();
364
365 if (selectedObject != null && selectedObject.equals(getEntity())) {
366 setSelected(true);
367 }
368 }
369
370 /**
371 * <p>
372 * addSelectionListener
373 * </p>
374 *
375 * @param listener
376 * a {@link org.eclipse.swt.events.SelectionListener} object.
377 */
378 public void addSelectionListener(SelectionListener listener) {
379 addListener(SWT.Selection, new TypedListener(listener));
380 }
381
382 /**
383 * <p>
384 * removeSelectionListener
385 * </p>
386 *
387 * @param listener
388 * a {@link org.eclipse.swt.events.SelectionListener} object.
389 */
390 public void removeSelectionListener(SelectionListener listener) {
391 removeListener(SWT.Selection, listener);
392 }
393
394 /** {@inheritDoc} */
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.forms.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 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 != null
426 && 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.forms.ICdmFormElement} object.
458 */
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 public Set<ICdmFormElement> getElements() {
471 return elements;
472 }
473
474 /**
475 * <p>
476 * getControls
477 * </p>
478 *
479 * @return a {@link java.util.Set} object.
480 */
481 public Set<Control> getControls() {
482 Set<Control> controls = new HashSet<Control>();
483
484 for (Control control : getChildren()) {
485 controls.add(control);
486 }
487
488 return controls;
489 }
490
491 /** {@inheritDoc} */
492 @Override
493 public void dispose() {
494 removeElements();
495 super.dispose();
496 }
497
498 /**
499 * <p>
500 * getLayoutComposite
501 * </p>
502 *
503 * @return a {@link org.eclipse.swt.widgets.Composite} object.
504 */
505 public Composite getLayoutComposite() {
506 return (Composite) getClient();
507 }
508
509 /** {@inheritDoc} */
510 public boolean containsFormElement(ICdmFormElement formElement) {
511 if (formElement == this) {
512 return true;
513 } else {
514 for (ICdmFormElement element : getElements()) {
515 boolean contains = element.containsFormElement(formElement);
516 if (contains == true) {
517 return true;
518 }
519 }
520 return false;
521 }
522 }
523
524 /**
525 * <p>
526 * Getter for the field <code>formFactory</code>.
527 * </p>
528 *
529 * @return a {@link eu.etaxonomy.taxeditor.ui.forms.CdmFormFactory} object.
530 */
531 public CdmFormFactory getFormFactory() {
532 return formFactory;
533 }
534
535 /*
536 * (non-Javadoc)
537 *
538 * @see eu.etaxonomy.taxeditor.forms.ICdmFormElement#refresh()
539 */
540 /**
541 * <p>
542 * refresh
543 * </p>
544 */
545 public void refresh() {
546 // empty default implementation
547
548 }
549
550 /**
551 * <p>
552 * getConversationHolder
553 * </p>
554 *
555 * @return a {@link eu.etaxonomy.cdm.api.conversation.ConversationHolder}
556 * object.
557 */
558 public ConversationHolder getConversationHolder() {
559 return conversation;
560 }
561
562 /** {@inheritDoc} */
563 public void update(CdmDataChangeMap changeEvents) {
564 }
565 }