Project

General

Profile

Download (15.8 KB) Statistics
| Branch: | Tag: | Revision:
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.jface.viewers.ISelectionChangedListener;
16
import org.eclipse.jface.viewers.ISelectionProvider;
17
import org.eclipse.jface.viewers.IStructuredSelection;
18
import org.eclipse.jface.viewers.SelectionChangedEvent;
19
import org.eclipse.jface.viewers.StructuredSelection;
20
import org.eclipse.swt.SWT;
21
import org.eclipse.swt.events.SelectionEvent;
22
import org.eclipse.swt.events.SelectionListener;
23
import org.eclipse.swt.graphics.Color;
24
import org.eclipse.swt.widgets.Composite;
25
import org.eclipse.swt.widgets.Control;
26
import org.eclipse.swt.widgets.Display;
27
import org.eclipse.swt.widgets.TypedListener;
28
import org.eclipse.swt.widgets.Widget;
29
import org.eclipse.ui.forms.events.ExpansionEvent;
30
import org.eclipse.ui.forms.events.IExpansionListener;
31
import org.eclipse.ui.forms.widgets.Section;
32
import org.eclipse.ui.forms.widgets.TableWrapLayout;
33
import org.eclipse.ui.forms.widgets.ToggleHyperlink;
34

    
35
import eu.etaxonomy.cdm.api.conversation.ConversationHolder;
36
import eu.etaxonomy.cdm.api.conversation.IConversationEnabled;
37
import eu.etaxonomy.cdm.persistence.hibernate.CdmDataChangeMap;
38
import eu.etaxonomy.taxeditor.model.AbstractUtility;
39
import eu.etaxonomy.taxeditor.model.MessagingUtils;
40
import eu.etaxonomy.taxeditor.preference.PreferencesUtil;
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
 * @param <T>
53
 */
54
//TODO shouldn't ENTITY be bound with super class ICdmBase for example (AbstractFormSection<ENTITY extends ICdmBase>)?
55
public abstract class AbstractFormSection<ENTITY> extends Section implements ISelectionChangedListener, IEntityElement<ENTITY>, IConversationEnabled {
56

    
57
    /**
58
     * The default number of columns in detail sections
59
     */
60
    public static final int DEFAULT_NUM_COLUMNS = 2;
61

    
62
	private ISelectionProvider selectionProvider;
63

    
64
	private ENTITY entity;
65

    
66
	private final Set<ICdmFormElement> elements = new HashSet<>();
67

    
68
	protected CdmFormFactory formFactory;
69

    
70
	private List<IPropertyChangeListener> propertyChangeListeners;
71

    
72
	private ICdmFormElement parentElement;
73

    
74
	private Color persistentBackgroundColor;
75

    
76
	/**
77
	 * <p>
78
	 * Constructor for AbstractFormSection.
79
	 * </p>
80
	 *
81
	 * @param conversation
82
	 *            TODO
83
	 * @param style
84
	 *            a int.
85
	 * @param formFactory
86
	 *            a {@link eu.etaxonomy.taxeditor.ui.element.CdmFormFactory}
87
	 *            object.
88
	 * @param parentElement
89
	 *            a {@link eu.etaxonomy.taxeditor.ui.element.ICdmFormElement}
90
	 *            object.
91
	 * @param <ENTITY>
92
	 *            a ENTITY object.
93
	 */
94
    protected AbstractFormSection(CdmFormFactory formFactory, ICdmFormElement parentElement, int style) {
95
		super(parentElement.getLayoutComposite(), style);
96

    
97
		this.parentElement = parentElement;
98

    
99
		this.formFactory = formFactory;
100

    
101
		this.setLayoutData(LayoutConstants.FILL());
102

    
103
		Composite client = formFactory.createComposite(this, SWT.WRAP);
104
		client.setBackgroundMode(SWT.INHERIT_DEFAULT);
105

    
106
		TableWrapLayout layout = LayoutConstants.LAYOUT();
107
		layout.bottomMargin = 10;
108
		layout.rightMargin = 5;
109
		layout.horizontalSpacing = 5;
110

    
111
		client.setLayout(layout);
112

    
113
		this.setClient(client);
114

    
115
	}
116

    
117
	    /**
118
     * <p>
119
     * Constructor for AbstractFormSection.
120
     * </p>
121
     *
122
     * @param formFactory
123
     *            a {@link eu.etaxonomy.taxeditor.ui.element.CdmFormFactory}
124
     *            object.
125
     * @param conversation
126
     *            a {@link eu.etaxonomy.cdm.api.conversation.ConversationHolder}
127
     *            object.
128
     * @param parentElement
129
     *            a {@link eu.etaxonomy.taxeditor.ui.element.ICdmFormElement}
130
     *            object.
131
     * @param selectionProvider
132
     *            a {@link org.eclipse.jface.viewers.ISelectionProvider} object.
133
     * @param style
134
     *            a int.
135
     */
136
    protected AbstractFormSection(CdmFormFactory formFactory, ICdmFormElement parentElement, ISelectionProvider selectionProvider, int style) {
137
        this(formFactory, parentElement, style);
138
        this.selectionProvider = selectionProvider;
139
    }
140

    
141
	/**
142
	 * <p>
143
	 * Getter for the field <code>propertyChangeListeners</code>.
144
	 * </p>
145
	 *
146
	 * @return a {@link java.util.Set} object.
147
	 */
148
	@Override
149
    public List<IPropertyChangeListener> getPropertyChangeListeners() {
150
		return propertyChangeListeners;
151
	}
152

    
153
	/** {@inheritDoc} */
154
	@Override
155
    public void setPropertyChangeListeners(
156
			List<IPropertyChangeListener> propertyChangeListeners) {
157
		this.propertyChangeListeners = propertyChangeListeners;
158
	}
159

    
160
	/**
161
	 * <p>
162
	 * Setter for the field <code>entity</code>.
163
	 * </p>
164
	 *
165
	 * @param entity
166
	 *            a ENTITY object.
167
	 */
168
	public void setEntity(ENTITY entity) {
169
		this.entity = entity;
170
		addExpandListener();
171
	}
172

    
173
	/**
174
	 * <p>
175
	 * Getter for the field <code>entity</code>.
176
	 * </p>
177
	 *
178
	 * @return a ENTITY object.
179
	 */
180
	@Override
181
    public ENTITY getEntity() {
182
		return entity;
183
	}
184

    
185
	/**
186
	 * <p>
187
	 * getToggle
188
	 * </p>
189
	 *
190
	 * @return a {@link org.eclipse.ui.forms.widgets.ToggleHyperlink} object.
191
	 */
192
	public ToggleHyperlink getToggle() {
193
		return this.toggle;
194
	}
195

    
196
	/**
197
	 * <p>
198
	 * getSection
199
	 * </p>
200
	 *
201
	 * @return a {@link eu.etaxonomy.taxeditor.ui.element.AbstractFormSection}
202
	 *         object.
203
	 */
204
	public AbstractFormSection<ENTITY> getSection() {
205
		return this;
206
	}
207

    
208
	/*
209
	 * (non-Javadoc)
210
	 *
211
	 * @see
212
	 * eu.etaxonomy.taxeditor.forms.IPropertyChangeEmitter#firePropertyChangeEvent
213
	 * ()
214
	 */
215
	/** {@inheritDoc} */
216
	@Override
217
    public void firePropertyChangeEvent(CdmPropertyChangeEvent event) {
218
        Assert.isNotNull(propertyChangeListeners, "No property change listeners.");
219
        try {
220
            for (Object listener : propertyChangeListeners) {
221
                ((IPropertyChangeListener) listener).propertyChange(event);
222
            }
223
        } catch (ConcurrentModificationException e) {
224
            MessagingUtils.warn(getClass(), "ConcurrentModificationException while handling PropertyChangeEvents."
225
                    + " It seems like this is not critical");
226
        }
227
	}
228

    
229
	/**
230
	 * Fires a {@link CdmPropertyChangeEvent} with the given object as source.
231
	 *
232
	 * @param object
233
	 *            the object on which the property changed
234
	 */
235
	public void firePropertyChangeEvent(Object object) {
236
		firePropertyChangeEvent(object, null);
237
	}
238

    
239
	/**
240
	 * Fires a {@link CdmPropertyChangeEvent} with the given object as source
241
	 * also containing the originating event
242
	 *
243
	 * @param object
244
	 *            the object on which the property changed
245
	 * @param originatingEvent
246
	 *            the originating event
247
	 */
248
	public void firePropertyChangeEvent(Object object,
249
			PropertyChangeEvent originatingEvent) {
250
		firePropertyChangeEvent(new CdmPropertyChangeEvent(object,
251
				originatingEvent));
252
	}
253

    
254
	/*
255
	 * (non-Javadoc)
256
	 *
257
	 * @see org.eclipse.swt.widgets.Composite#setFocus()
258
	 */
259
	/** {@inheritDoc} */
260
	@Override
261
	public boolean setFocus() {
262
		return getClient().setFocus();
263
	}
264

    
265
	/*
266
	 * (non-Javadoc)
267
	 *
268
	 * @see
269
	 * org.eclipse.jface.util.IPropertyChangeListener#propertyChange(org.eclipse
270
	 * .jface.util.PropertyChangeEvent)
271
	 */
272
	/** {@inheritDoc} */
273
	@Override
274
    public void propertyChange(PropertyChangeEvent event) {
275
		firePropertyChangeEvent(new CdmPropertyChangeEvent(this, event));
276
	}
277

    
278
	/*
279
	 * (non-Javadoc)
280
	 *
281
	 * @see
282
	 * org.eclipse.swt.widgets.Control#setBackground(org.eclipse.swt.graphics
283
	 * .Color)
284
	 */
285
	/** {@inheritDoc} */
286
	@Override
287
	public void setBackground(Color color) {
288
		for (ICdmFormElement element : getElements()) {
289
			element.setBackground(color);
290
		}
291
		getLayoutComposite().setBackground(color);
292
		super.setBackground(color);
293
	}
294

    
295
	@Override
296
	public void setPersistentBackground(Color color) {
297
		persistentBackgroundColor = color;
298
		setBackground(color);
299
	}
300

    
301
	@Override
302
	public Color getPersistentBackground() {
303
		return persistentBackgroundColor;
304
	}
305

    
306

    
307
	/**
308
	 * <p>
309
	 * widgetSelected
310
	 * </p>
311
	 *
312
	 * @param e
313
	 *            a {@link org.eclipse.swt.events.SelectionEvent} object.
314
	 */
315
	public void widgetSelected(SelectionEvent e) {
316
        Widget widget = e.widget;
317

    
318
        if (widget instanceof Control) {
319
            Control control = (Control) widget;
320
            if (checkControlAncestryForWidget(control)) {
321
                if (getEntity() != null) {
322
                    IStructuredSelection selection = new StructuredSelection(getEntity());
323
                    if (selectionProvider != null) {
324
                        selectionProvider.setSelection(selection);
325
                    }
326
                }
327
            }
328
        }
329
	}
330

    
331
	private boolean checkControlAncestryForWidget(Control control) {
332
		if (control.equals(this)) {
333
			return true;
334
		} else {
335
			Control parent = control.getParent();
336
			if (parent == null) {
337
				return false;
338
			} else {
339
				return checkControlAncestryForWidget(parent);
340
			}
341
		}
342
	}
343

    
344
	/** {@inheritDoc} */
345
	@Override
346
    public void setSelected(boolean selected) {
347
		if (selected) {
348
			setBackground(Display.getCurrent().getSystemColor(
349
					SWT.COLOR_LIST_SELECTION));
350
		} else {
351
			setBackground(Display.getCurrent().getSystemColor(SWT.COLOR_WHITE));
352
		}
353
	}
354

    
355
	/** {@inheritDoc} */
356
	@Override
357
    public void selectionChanged(SelectionChangedEvent event) {
358
		if (event.getSelection() == CdmFormFactory.EMPTY_SELECTION) {
359
			return;
360
		}
361

    
362
		IStructuredSelection selection = (IStructuredSelection) event
363
				.getSelection();
364
		setSelected(false);
365

    
366
		Object selectedObject = selection.getFirstElement();
367

    
368
		if (selectedObject != null && selectedObject.equals(getEntity())) {
369
			setSelected(true);
370
		}
371
	}
372

    
373
	/**
374
	 * <p>
375
	 * addSelectionListener
376
	 * </p>
377
	 *
378
	 * @param listener
379
	 *            a {@link org.eclipse.swt.events.SelectionListener} object.
380
	 */
381
	public void addSelectionListener(SelectionListener listener) {
382
		addListener(SWT.Selection, new TypedListener(listener));
383
	}
384

    
385
	/**
386
	 * <p>
387
	 * removeSelectionListener
388
	 * </p>
389
	 *
390
	 * @param listener
391
	 *            a {@link org.eclipse.swt.events.SelectionListener} object.
392
	 */
393
	public void removeSelectionListener(SelectionListener listener) {
394
		removeListener(SWT.Selection, listener);
395
	}
396

    
397
	/** {@inheritDoc} */
398
	@Override
399
    public void addElement(ICdmFormElement element) {
400
		elements.add(element);
401
	}
402

    
403
	/**
404
	 * <p>
405
	 * removeElement
406
	 * </p>
407
	 *
408
	 * @param element
409
	 *            a {@link eu.etaxonomy.taxeditor.ui.element.ICdmFormElement}
410
	 *            object.
411
	 */
412
	protected void removeElement(ICdmFormElement element) {
413
		elements.remove(element);
414
	}
415

    
416
	/**
417
	 * <p>
418
	 * removeElements
419
	 * </p>
420
	 */
421
	@Override
422
    public void removeElements() {
423
		for (Iterator<ICdmFormElement> formElementIterator = getElements().iterator();formElementIterator.hasNext();) {
424
		    ICdmFormElement childElement = formElementIterator.next();
425
			// recursion
426
			childElement.removeElements();
427

    
428
			// unregister selection arbitrator
429
			if (childElement instanceof ISelectableElement) {
430
				ISelectableElement selectableElement = (ISelectableElement) childElement;
431
				if (selectableElement.getSelectionArbitrator() != null) {
432
					formFactory.destroySelectionArbitrator(selectableElement
433
							.getSelectionArbitrator());
434
				}
435
			}
436

    
437
			// unregister propertyChangeListener
438
			formFactory.removePropertyChangeListener(childElement);
439

    
440
			// dispose of the controls
441
			for (Iterator<Control> controlIterator = childElement.getControls().iterator();controlIterator.hasNext();) {
442
			    Control control = controlIterator.next();
443
				// we added the layoutComposite of the parental element as the
444
				// layout composite to this formElement
445
				// but we do not want to destroy it.
446
				if (control.equals(childElement.getLayoutComposite())) {
447
					continue;
448
				} else {
449
					control.dispose();
450
					control = null;
451
				}
452
			}
453
		}
454

    
455
		elements.clear();
456
	}
457

    
458
	/**
459
	 * <p>
460
	 * Getter for the field <code>parentElement</code>.
461
	 * </p>
462
	 *
463
	 * @return a {@link eu.etaxonomy.taxeditor.ui.element.ICdmFormElement} object.
464
	 */
465
	@Override
466
    public ICdmFormElement getParentElement() {
467
		return parentElement;
468
	}
469

    
470
	/**
471
	 * <p>
472
	 * Getter for the field <code>elements</code>.
473
	 * </p>
474
	 *
475
	 * @return a {@link java.util.Set} object.
476
	 */
477
	@Override
478
    public Set<ICdmFormElement> getElements() {
479
		return elements;
480
	}
481

    
482
	/**
483
	 * <p>
484
	 * getControls
485
	 * </p>
486
	 *
487
	 * @return a {@link java.util.Set} object.
488
	 */
489
	@Override
490
    public Set<Control> getControls() {
491
		Set<Control> controls = new HashSet<>();
492

    
493
		for (Control control : getChildren()) {
494
			controls.add(control);
495
		}
496

    
497
		return controls;
498
	}
499

    
500
	/** {@inheritDoc} */
501
	@Override
502
	public void dispose() {
503
		removeElements();
504
		super.dispose();
505
	}
506

    
507
	/**
508
	 * <p>
509
	 * getLayoutComposite
510
	 * </p>
511
	 *
512
	 * @return a {@link org.eclipse.swt.widgets.Composite} object.
513
	 */
514
	@Override
515
    public Composite getLayoutComposite() {
516
		return (Composite) getClient();
517
	}
518

    
519
	/** {@inheritDoc} */
520
	@Override
521
    public boolean containsFormElement(ICdmFormElement formElement) {
522
		if (formElement == this) {
523
			return true;
524
		} else {
525
			for (ICdmFormElement element : getElements()) {
526
				boolean contains = element.containsFormElement(formElement);
527
				if (contains == true) {
528
					return true;
529
				}
530
			}
531
			return false;
532
		}
533
	}
534

    
535
	/**
536
	 * <p>
537
	 * Getter for the field <code>formFactory</code>.
538
	 * </p>
539
	 *
540
	 * @return a {@link eu.etaxonomy.taxeditor.ui.element.CdmFormFactory} object.
541
	 */
542
	@Override
543
    public CdmFormFactory getFormFactory() {
544
		return formFactory;
545
	}
546

    
547
	/*
548
	 * (non-Javadoc)
549
	 *
550
	 * @see eu.etaxonomy.taxeditor.forms.ICdmFormElement#refresh()
551
	 */
552
	@Override
553
    public void refresh() {
554
		// empty default implementation
555

    
556
	}
557

    
558
	/**
559
	 * <p>
560
	 * getConversationHolder
561
	 * </p>
562
	 *
563
	 * @return a {@link eu.etaxonomy.cdm.api.conversation.ConversationHolder}
564
	 *         object.
565
	 */
566
	@Override
567
    public ConversationHolder getConversationHolder() {
568
	    if(AbstractUtility.getActivePart() instanceof IConversationEnabled){
569
            return ((IConversationEnabled) AbstractUtility.getActivePart()).getConversationHolder();
570
        }
571
	    if(getParentElement() instanceof RootElement || getParentElement() == null){
572

    
573
	        Object activeEditor = AbstractUtility.getActiveEditor();
574
	        if(activeEditor instanceof IConversationEnabled){
575
	            ConversationHolder conversation = ((IConversationEnabled) AbstractUtility.getActiveEditor()).getConversationHolder();
576
	            return conversation;
577
	        }
578
	    }else if(getParentElement() instanceof IConversationEnabled){
579
	        return ((IConversationEnabled) getParentElement()).getConversationHolder();
580
	    }
581
		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",
582
				new IllegalArgumentException());
583
		return null;
584

    
585
	}
586

    
587
	/** {@inheritDoc} */
588
	@Override
589
    public void update(CdmDataChangeMap changeEvents) {
590

    
591
	}
592

    
593
    public class ExpandListener implements IExpansionListener{
594
		@Override
595
		public void expansionStateChanging(ExpansionEvent e) {
596
		}
597
		@Override
598
		public void expansionStateChanged(ExpansionEvent e) {
599
			PreferencesUtil.getPreferenceStore().setValue(getPrefKey(), e.getState());
600
		}
601
    }
602

    
603
    /**
604
     * Adds a custom implementation of IExpansionListener to this section
605
     * which stores the expansion state in the preferences
606
     */
607
	protected void addExpandListener() {
608
		PreferencesUtil.getPreferenceStore().setDefault(getPrefKey(), isExpanded());
609
		setExpanded(PreferencesUtil.getPreferenceStore().getBoolean(getPrefKey()));
610
		addExpansionListener(new ExpandListener());
611
	}
612

    
613
	private String getPrefKey() {
614
		return this.getClass().getCanonicalName()+";"+entity.getClass().getCanonicalName();
615
	}
616

    
617

    
618
}
(4-4/47)