Merge branch 'release/5.19.0'
[taxeditor.git] / eu.etaxonomy.taxeditor.store / src / main / java / eu / etaxonomy / taxeditor / ui / element / AbstractFormSection.java
1 /**
2 * Copyright (C) 2007 EDIT
3 * European Distributed Institute of Taxonomy
4 * http://www.e-taxonomy.eu
5 *
6 * The contents of this file are subject to the Mozilla Public License Version 1.1
7 * See LICENSE.TXT at the top of this package for the full license terms.
8 */
9 package eu.etaxonomy.taxeditor.ui.element;
10
11 import java.util.ConcurrentModificationException;
12 import java.util.HashSet;
13 import java.util.Iterator;
14 import java.util.List;
15 import java.util.Set;
16
17 import org.eclipse.core.runtime.Assert;
18 import org.eclipse.jface.util.IPropertyChangeListener;
19 import org.eclipse.jface.util.PropertyChangeEvent;
20 import org.eclipse.jface.viewers.ISelectionChangedListener;
21 import org.eclipse.jface.viewers.ISelectionProvider;
22 import org.eclipse.jface.viewers.IStructuredSelection;
23 import org.eclipse.jface.viewers.SelectionChangedEvent;
24 import org.eclipse.jface.viewers.StructuredSelection;
25 import org.eclipse.swt.SWT;
26 import org.eclipse.swt.events.SelectionEvent;
27 import org.eclipse.swt.events.SelectionListener;
28 import org.eclipse.swt.graphics.Color;
29 import org.eclipse.swt.widgets.Composite;
30 import org.eclipse.swt.widgets.Control;
31 import org.eclipse.swt.widgets.Display;
32 import org.eclipse.swt.widgets.TypedListener;
33 import org.eclipse.swt.widgets.Widget;
34 import org.eclipse.ui.forms.widgets.Section;
35 import org.eclipse.ui.forms.widgets.TableWrapLayout;
36 import org.eclipse.ui.forms.widgets.ToggleHyperlink;
37
38 import eu.etaxonomy.cdm.api.conversation.ConversationHolder;
39 import eu.etaxonomy.cdm.api.conversation.IConversationEnabled;
40 import eu.etaxonomy.cdm.persistence.hibernate.CdmDataChangeMap;
41 import eu.etaxonomy.taxeditor.model.AbstractUtility;
42 import eu.etaxonomy.taxeditor.model.MessagingUtils;
43
44 /**
45 * <p>
46 * Abstract super class for a {@link Section} GUI element that visualizes a CDM
47 * entity, manages a conversation and listens to selections
48 * </p>
49 *
50 * @param <ENTITY> A CDM entity which should be visualized by this section.
51 *
52 * @author n.hoffmann
53 * @created Feb 22, 2010
54 */
55 //TODO shouldn't ENTITY be bound with super class ICdmBase for example (AbstractFormSection<ENTITY extends ICdmBase>)?
56 public abstract class AbstractFormSection<ENTITY>
57 extends Section
58 implements ISelectionChangedListener, IEntityElement<ENTITY>, IConversationEnabled {
59
60 /**
61 * The default number of columns in detail sections
62 */
63 public static final int DEFAULT_NUM_COLUMNS = 2;
64
65 private ISelectionProvider selectionProvider;
66
67 private ENTITY entity;
68
69 private final Set<ICdmFormElement> elements = new HashSet<>();
70
71 protected CdmFormFactory formFactory;
72
73 private List<IPropertyChangeListener> propertyChangeListeners;
74
75 private ICdmFormElement parentElement;
76
77 private Color persistentBackgroundColor;
78
79 /**
80 * Constructor for AbstractFormSection.
81 */
82 protected AbstractFormSection(CdmFormFactory formFactory, ICdmFormElement parentElement, int style) {
83 super(parentElement.getLayoutComposite(), style);
84
85 this.parentElement = parentElement;
86
87 this.formFactory = formFactory;
88
89 this.setLayoutData(LayoutConstants.FILL());
90
91 Composite client = formFactory.createComposite(this, SWT.WRAP);
92 client.setBackgroundMode(SWT.INHERIT_DEFAULT);
93
94 TableWrapLayout layout = LayoutConstants.LAYOUT();
95 layout.bottomMargin = 10;
96 layout.rightMargin = 5;
97 layout.horizontalSpacing = 5;
98
99 client.setLayout(layout);
100
101 this.setClient(client);
102 }
103
104 /**
105 * Constructor for AbstractFormSection.
106 */
107 protected AbstractFormSection(CdmFormFactory formFactory, ICdmFormElement parentElement, ISelectionProvider selectionProvider, int style) {
108 this(formFactory, parentElement, style);
109 this.selectionProvider = selectionProvider;
110 }
111
112 /**
113 * Getter for the field <code>propertyChangeListeners</code>.
114 */
115 @Override
116 public List<IPropertyChangeListener> getPropertyChangeListeners() {
117 return propertyChangeListeners;
118 }
119
120 @Override
121 public void setPropertyChangeListeners(
122 List<IPropertyChangeListener> propertyChangeListeners) {
123 this.propertyChangeListeners = propertyChangeListeners;
124 }
125
126 /**
127 * Setter for the field <code>entity</code>.
128 */
129 public void setEntity(ENTITY entity) {
130 this.entity = entity;
131 }
132
133 /**
134 * Getter for the field <code>entity</code>.
135 */
136 @Override
137 public ENTITY getEntity() {
138 return entity;
139 }
140
141 /**
142 * getToggle
143 */
144 public ToggleHyperlink getToggle() {
145 return this.toggle;
146 }
147
148 /**
149 * getSection
150 */
151 public AbstractFormSection<ENTITY> getSection() {
152 return this;
153 }
154
155 @Override
156 public void firePropertyChangeEvent(CdmPropertyChangeEvent event) {
157 Assert.isNotNull(propertyChangeListeners, "No property change listeners.");
158 try {
159 for (Object listener : propertyChangeListeners) {
160 ((IPropertyChangeListener) listener).propertyChange(event);
161 }
162 } catch (ConcurrentModificationException e) {
163 MessagingUtils.warn(getClass(), "ConcurrentModificationException while handling PropertyChangeEvents."
164 + " It seems like this is not critical");
165 }
166 }
167
168 /**
169 * Fires a {@link CdmPropertyChangeEvent} with the given object as source.
170 *
171 * @param object
172 * the object on which the property changed
173 */
174 public void firePropertyChangeEvent(Object object) {
175 firePropertyChangeEvent(object, null);
176 }
177
178 /**
179 * Fires a {@link CdmPropertyChangeEvent} with the given object as source
180 * also containing the originating event
181 *
182 * @param object
183 * the object on which the property changed
184 * @param originatingEvent
185 * the originating event
186 */
187 public void firePropertyChangeEvent(Object object,
188 PropertyChangeEvent originatingEvent) {
189 firePropertyChangeEvent(new CdmPropertyChangeEvent(object,
190 originatingEvent));
191 }
192
193 @Override
194 public boolean setFocus() {
195 return getClient().setFocus();
196 }
197
198 @Override
199 public void propertyChange(PropertyChangeEvent event) {
200 firePropertyChangeEvent(new CdmPropertyChangeEvent(this, event));
201 }
202
203 @Override
204 public void setBackground(Color color) {
205 for (ICdmFormElement element : getElements()) {
206 element.setBackground(color);
207 }
208 getLayoutComposite().setBackground(color);
209 super.setBackground(color);
210 }
211
212 @Override
213 public void setPersistentBackground(Color color) {
214 persistentBackgroundColor = color;
215 setBackground(color);
216 }
217
218 @Override
219 public Color getPersistentBackground() {
220 return persistentBackgroundColor;
221 }
222
223 public void widgetSelected(SelectionEvent e) {
224 Widget widget = e.widget;
225
226 if (widget instanceof Control) {
227 Control control = (Control) widget;
228 if (checkControlAncestryForWidget(control)) {
229 if (getEntity() != null) {
230 IStructuredSelection selection = new StructuredSelection(getEntity());
231 if (selectionProvider != null) {
232 selectionProvider.setSelection(selection);
233 }
234 }
235 }
236 }
237 }
238
239 private boolean checkControlAncestryForWidget(Control control) {
240 if (control.equals(this)) {
241 return true;
242 } else {
243 Control parent = control.getParent();
244 if (parent == null) {
245 return false;
246 } else {
247 return checkControlAncestryForWidget(parent);
248 }
249 }
250 }
251
252 @Override
253 public void setSelected(boolean selected) {
254 if (selected) {
255 setBackground(Display.getCurrent().getSystemColor(
256 SWT.COLOR_LIST_SELECTION));
257 } else {
258 setBackground(Display.getCurrent().getSystemColor(SWT.COLOR_WHITE));
259 }
260 }
261
262 @Override
263 public void selectionChanged(SelectionChangedEvent event) {
264 if (event.getSelection() == CdmFormFactory.EMPTY_SELECTION) {
265 return;
266 }
267
268 IStructuredSelection selection = (IStructuredSelection) event
269 .getSelection();
270 setSelected(false);
271
272 Object selectedObject = selection.getFirstElement();
273
274 if (selectedObject != null && selectedObject.equals(getEntity())) {
275 setSelected(true);
276 }
277 }
278
279 public void addSelectionListener(SelectionListener listener) {
280 addListener(SWT.Selection, new TypedListener(listener));
281 }
282
283 public void removeSelectionListener(SelectionListener listener) {
284 removeListener(SWT.Selection, listener);
285 }
286
287 @Override
288 public void addElement(ICdmFormElement element) {
289 elements.add(element);
290 }
291
292 protected void removeElement(ICdmFormElement element) {
293 elements.remove(element);
294 }
295
296 @Override
297 public void removeElements() {
298 for (Iterator<ICdmFormElement> formElementIterator = getElements().iterator();formElementIterator.hasNext();) {
299 ICdmFormElement childElement = formElementIterator.next();
300 // recursion
301 childElement.removeElements();
302
303 // unregister selection arbitrator
304 if (childElement instanceof ISelectableElement) {
305 ISelectableElement selectableElement = (ISelectableElement) childElement;
306 if (selectableElement.getSelectionArbitrator() != null) {
307 formFactory.destroySelectionArbitrator(selectableElement
308 .getSelectionArbitrator());
309 }
310 }
311
312 // unregister propertyChangeListener
313 formFactory.removePropertyChangeListener(childElement);
314
315 // dispose of the controls
316 for (Iterator<Control> controlIterator = childElement.getControls().iterator();controlIterator.hasNext();) {
317 Control control = controlIterator.next();
318 // we added the layoutComposite of the parental element as the
319 // layout composite to this formElement
320 // but we do not want to destroy it.
321 if (control.equals(childElement.getLayoutComposite())) {
322 continue;
323 } else {
324 control.dispose();
325 control = null;
326 }
327 }
328 }
329
330 elements.clear();
331 }
332
333 /**
334 * Getter for the field <code>parentElement</code>.
335 */
336 @Override
337 public ICdmFormElement getParentElement() {
338 return parentElement;
339 }
340
341 /**
342 * Getter for the field <code>elements</code>.
343 */
344 @Override
345 public Set<ICdmFormElement> getElements() {
346 return elements;
347 }
348
349 @Override
350 public Set<Control> getControls() {
351 Set<Control> controls = new HashSet<>();
352
353 for (Control control : getChildren()) {
354 controls.add(control);
355 }
356
357 return controls;
358 }
359
360 @Override
361 public void dispose() {
362 removeElements();
363 super.dispose();
364 }
365
366 @Override
367 public Composite getLayoutComposite() {
368 return (Composite) getClient();
369 }
370
371 @Override
372 public boolean containsFormElement(ICdmFormElement formElement) {
373 if (formElement == this) {
374 return true;
375 } else {
376 for (ICdmFormElement element : getElements()) {
377 boolean contains = element.containsFormElement(formElement);
378 if (contains == true) {
379 return true;
380 }
381 }
382 return false;
383 }
384 }
385
386 /**
387 * Getter for the field <code>formFactory</code>.
388 */
389 @Override
390 public CdmFormFactory getFormFactory() {
391 return formFactory;
392 }
393
394 @Override
395 public void refresh() {
396 // empty default implementation
397 }
398
399 @Override
400 public ConversationHolder getConversationHolder() {
401 if(AbstractUtility.getActivePart() instanceof IConversationEnabled){
402 return ((IConversationEnabled) AbstractUtility.getActivePart()).getConversationHolder();
403 }
404 if(getParentElement() instanceof RootElement || getParentElement() == null){
405
406 Object activeEditor = AbstractUtility.getActiveEditor();
407 if(activeEditor instanceof IConversationEnabled){
408 ConversationHolder conversation = ((IConversationEnabled) AbstractUtility.getActiveEditor()).getConversationHolder();
409 return conversation;
410 }
411 }else if(getParentElement() instanceof IConversationEnabled){
412 return ((IConversationEnabled) getParentElement()).getConversationHolder();
413 }
414 MessagingUtils.error(getClass(), "Could not get conversation for AbstractFormSection. There is an error in the implementation. There should have been an active editor but it wasn't",
415 new IllegalArgumentException());
416 return null;
417
418 }
419
420 @Override
421 public void update(CdmDataChangeMap changeEvents) {
422
423 }
424
425 }