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