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