Merge branch 'release/5.0.0'
[taxeditor.git] / eu.etaxonomy.taxeditor.store / src / main / java / eu / etaxonomy / taxeditor / ui / element / AbstractCdmFormElement.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.swt.graphics.Color;
15 import org.eclipse.swt.widgets.Composite;
16 import org.eclipse.swt.widgets.Control;
17 import org.eclipse.ui.forms.widgets.Section;
18
19 import eu.etaxonomy.taxeditor.model.AbstractUtility;
20 import eu.etaxonomy.taxeditor.model.MessagingUtils;
21
22 /**
23 * @author n.hoffmann
24 * @version $Id: $
25 */
26 public abstract class AbstractCdmFormElement implements ICdmFormElement {
27
28 protected CdmFormFactory formFactory;
29
30 private List<IPropertyChangeListener> propertyChangeListeners;
31
32 private Composite layoutComposite;
33
34 private final Set<Control> controls = new HashSet<Control>();
35
36 private final Set<ICdmFormElement> elements = new HashSet<ICdmFormElement>();
37 private ICdmFormElement parentElement;
38
39 private Color persistentBackgroundColor;
40
41
42 protected AbstractCdmFormElement(CdmFormFactory formFactory, Composite layoutComposite){
43 this.layoutComposite = layoutComposite;
44 this.formFactory = formFactory;
45 }
46
47 public AbstractCdmFormElement(CdmFormFactory formFactory, ICdmFormElement formElement) {
48 this(formFactory, formElement.getLayoutComposite());
49 this.parentElement = formElement;
50 // addControl(layoutComposite);
51 }
52
53 @Override
54 public CdmFormFactory getFormFactory() {
55 return formFactory;
56 }
57
58 /**
59 * Delegates the focus to <code>this</code> elements main input control
60 */
61 public void setFocus(){
62 // Override in subclasses where needed
63 }
64
65 /**
66 * Returns all Controls that are managed by this element
67 *
68 * @return a {@link java.util.Set} object.
69 */
70 @Override
71 public Set<Control> getControls(){
72 return controls;
73 }
74
75 /**
76 * adds the control to the set of controls that are managed by this element
77 *
78 * @param child a {@link org.eclipse.swt.widgets.Control} object.
79 */
80 protected void addControl(Control child){
81 controls.add(child);
82 }
83
84 protected void removeControl(Control child){
85 controls.remove(child);
86 }
87
88 /**
89 * <p>Getter for the field <code>elements</code>.</p>
90 *
91 * @return a {@link java.util.Set} object.
92 */
93 @Override
94 public Set<ICdmFormElement> getElements(){
95 return elements;
96 }
97
98 /**
99 * <p>Getter for the field <code>parentElement</code>.</p>
100 *
101 * @return a {@link eu.etaxonomy.taxeditor.ui.element.ICdmFormElement} object.
102 */
103 @Override
104 public ICdmFormElement getParentElement(){
105 return parentElement;
106 }
107
108 /** {@inheritDoc} */
109 @Override
110 public void addElement(ICdmFormElement element){
111 elements.add(element);
112 }
113
114 protected void removeElement(ICdmFormElement element){
115 elements.remove(element);
116 }
117
118 /**
119 * Remove all child {@link ICdmFormElement}s and child {@link Control}s
120 * of the given and the element itself.
121 * @param formElement The element to remove
122 */
123 public void removeElementsAndControls(ICdmFormElement formElement){
124 for(ICdmFormElement childElement : formElement.getElements()){
125 // recursion
126 childElement.removeElements();
127
128 // unregister selection arbitrator
129 if(childElement instanceof ISelectableElement){
130 SelectionArbitrator selectionArbitrator = ((ISelectableElement) childElement).getSelectionArbitrator();
131 if(selectionArbitrator != null){
132 formFactory.destroySelectionArbitrator(selectionArbitrator);
133 }
134 }
135
136 // unregister from property changes
137 formFactory.removePropertyChangeListener(childElement);
138
139 // dispose of the controls
140 removeControls(childElement);
141 }
142 removeControls(formElement);
143 }
144
145 /**
146 * Removes all child {@link ICdmFormElement}s and child {@link Control}s
147 * and the element itself.
148 */
149 @Override
150 public void removeElements(){
151 for(ICdmFormElement childElement : getElements()){
152 // recursion
153 childElement.removeElements();
154
155 // unregister selection arbitrator
156 if(childElement instanceof ISelectableElement){
157 SelectionArbitrator selectionArbitrator = ((ISelectableElement) childElement).getSelectionArbitrator();
158 if(selectionArbitrator != null){
159 formFactory.destroySelectionArbitrator(selectionArbitrator);
160 }
161 }
162
163 // unregister from property changes
164 formFactory.removePropertyChangeListener(childElement);
165
166 // dispose of the controls
167 removeControls(childElement);
168 }
169 if(this instanceof ISelectableElement){
170 SelectionArbitrator selectionArbitrator = ((ISelectableElement) this).getSelectionArbitrator();
171 if(selectionArbitrator != null){
172 formFactory.destroySelectionArbitrator(selectionArbitrator);
173 }
174 }
175 removeControls(this);
176 elements.clear();
177 }
178
179 private void removeControls(ICdmFormElement element){
180 if(element instanceof Section){
181 ((Section) element).dispose();
182 element = null;
183 }else{
184 for(Control control : element.getControls()){
185 // we added the layoutComposite of the parental element as the layout composite to this formElement
186 // but we do not want to destroy it.
187 if(control.equals(element.getLayoutComposite())){
188 continue;
189 }else{
190 control.dispose();
191 control = null;
192 }
193 }
194 }
195 }
196
197 /**
198 * <p>Getter for the field <code>layoutComposite</code>.</p>
199 *
200 * @return a {@link org.eclipse.swt.widgets.Composite} object.
201 */
202 @Override
203 public Composite getLayoutComposite() {
204 return layoutComposite;
205 }
206
207 /**
208 * <p>Setter for the field <code>layoutComposite</code>.</p>
209 *
210 * @param layoutComposite a {@link org.eclipse.swt.widgets.Composite} object.
211 */
212 public void setLayoutComposite(Composite layoutComposite){
213 this.layoutComposite = layoutComposite;
214 }
215
216 /**
217 * <p>Getter for the field <code>propertyChangeListeners</code>.</p>
218 *
219 * @return a {@link java.util.Set} object.
220 */
221 @Override
222 public List<IPropertyChangeListener> getPropertyChangeListeners() {
223 return propertyChangeListeners;
224 }
225
226 /** {@inheritDoc} */
227 @Override
228 public void setPropertyChangeListeners(List<IPropertyChangeListener> propertyChangeListeners){
229 this.propertyChangeListeners = propertyChangeListeners;
230 }
231
232 /** {@inheritDoc} */
233 @Override
234 public void firePropertyChangeEvent(CdmPropertyChangeEvent event) {
235 //TODO: replace propertyChangeListeners with formFactory.getPropertyChangeListeners() and remove member propertyChangeListeners from AbstractCdmFormElement
236 Assert.isNotNull(propertyChangeListeners, "Property change listeners are not present");
237
238 try{
239 for(Object listener : propertyChangeListeners){
240 ((IPropertyChangeListener)listener).propertyChange(event);
241 }
242 }catch(ConcurrentModificationException e){
243 // There are two cases that produce a CME.
244 // Described here: http://dev.e-taxonomy.eu/trac/ticket/2363#comment:2
245 // and here: http://dev.e-taxonomy.eu/trac/ticket/2438
246 // Ignoring the CME because nothing bad is happening
247 MessagingUtils.warn(getClass(), "ConcurrentModificationException. Can be ignored.");
248 }
249 }
250
251 /**
252 * Fires a {@link CdmPropertyChangeEvent} with the given object as source.
253 *
254 * @param object the object on which the property changed
255 */
256 public void firePropertyChangeEvent(Object object){
257 firePropertyChangeEvent(object, null);
258 }
259
260 /**
261 * Fires a {@link CdmPropertyChangeEvent} with the given object as source also containing the
262 * originating event
263 *
264 * @param object the object on which the property changed
265 * @param originatingEvent the originating event
266 */
267 public void firePropertyChangeEvent(Object object, PropertyChangeEvent originatingEvent){
268 firePropertyChangeEvent(new CdmPropertyChangeEvent(object, originatingEvent));
269 }
270
271
272 /**
273 * {@inheritDoc}
274 *
275 * This method gets called whenever the toolkit this composite was created with gets a property change notification.
276 *
277 * It is good advice to check whether the PropertyChangeEvent is destined for the implementing composite.
278 * Implementations should also check for null PropertyChangeEvents and return immediately in that case.
279 * @see eu.etaxonomy.taxeditor.ui.element.ICdmFormElement#propertyChange(org.eclipse.jface.util.PropertyChangeEvent)
280 */
281 @Override
282 public void propertyChange(PropertyChangeEvent event) {
283 // implement in subclasses
284 }
285
286 /** {@inheritDoc} */
287 @Override
288 public boolean containsFormElement(ICdmFormElement formElement){
289 if(formElement == this){
290 return true;
291 }else{
292 for(ICdmFormElement element : getElements()){
293 boolean contains = element.containsFormElement(formElement);
294 if(contains == true){
295 return true;
296 }
297 }
298 return false;
299 }
300 }
301
302 @Override
303 public void refresh() {
304 // empty default implementation
305 }
306
307
308 /** {@inheritDoc} */
309 @Override
310 public void setBackground(Color color) {
311 for(ICdmFormElement element : getElements()){
312 element.setBackground(color);
313 }
314 }
315
316 @Override
317 public void setPersistentBackground(Color color) {
318 persistentBackgroundColor = color;
319 setBackground(color);
320 }
321
322 @Override
323 public Color getPersistentBackground() {
324 return persistentBackgroundColor;
325 }
326
327 public Color getColor(String colorId){
328 return AbstractUtility.getColor(colorId);
329 }
330 }