Project

General

Profile

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

    
34
import eu.etaxonomy.cdm.api.conversation.ConversationHolder;
35
import eu.etaxonomy.cdm.api.conversation.IConversationEnabled;
36
import eu.etaxonomy.cdm.persistence.hibernate.CdmDataChangeMap;
37
import eu.etaxonomy.taxeditor.model.AbstractUtility;
38
import eu.etaxonomy.taxeditor.model.MessagingUtils;
39
import eu.etaxonomy.taxeditor.preference.PreferencesUtil;
40

    
41
/**
42
 * <p>
43
 * Abstract super class for a {@link Section} GUI element that visualizes a CDM
44
 * entity, manages a conversation and listens to selections
45
 * </p>
46
 *
47
 * @param <ENTITY> A CDM entity which should be visualized by this section.
48
 *
49
 * @author n.hoffmann
50
 * @created Feb 22, 2010
51
 * @param <T>
52
 */
53
//TODO shouldn't ENTITY be bound with super class ICdmBase for example (AbstractFormSection<ENTITY extends ICdmBase>)?
54
public abstract class AbstractFormSection<ENTITY> extends Section implements ISelectionChangedListener, IEntityElement<ENTITY>, IConversationEnabled {
55

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

    
61
	private ISelectionProvider selectionProvider;
62

    
63
	private ENTITY entity;
64

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

    
67
	protected CdmFormFactory formFactory;
68

    
69
	private List<IPropertyChangeListener> propertyChangeListeners;
70

    
71
	private ICdmFormElement parentElement;
72

    
73
	private Color persistentBackgroundColor;
74

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

    
96
		this.parentElement = parentElement;
97

    
98
		this.formFactory = formFactory;
99

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

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

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

    
110
		client.setLayout(layout);
111

    
112
		this.setClient(client);
113

    
114
	}
115

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
305

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

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

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

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

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

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

    
365
		Object selectedObject = selection.getFirstElement();
366

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

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

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

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

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

    
415
	/**
416
	 * <p>
417
	 * removeElements
418
	 * </p>
419
	 */
420
	@Override
421
    public void removeElements() {
422
		for (ICdmFormElement childElement : getElements()) {
423
			// recursion
424
			childElement.removeElements();
425

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

    
435
			// unregister propertyChangeListener
436
			formFactory.removePropertyChangeListener(childElement);
437

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

    
452
		elements.clear();
453
	}
454

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

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

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

    
490
		for (Control control : getChildren()) {
491
			controls.add(control);
492
		}
493

    
494
		return controls;
495
	}
496

    
497
	/** {@inheritDoc} */
498
	@Override
499
	public void dispose() {
500
		removeElements();
501
		super.dispose();
502
	}
503

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

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

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

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

    
553
	}
554

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

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

    
582
	}
583

    
584
	/** {@inheritDoc} */
585
	@Override
586
    public void update(CdmDataChangeMap changeEvents) {
587

    
588
	}
589

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

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

    
610
	private String getPrefKey() {
611
		return this.getClass().getCanonicalName()+";"+entity.getClass().getCanonicalName();
612
	}
613

    
614

    
615
}
(4-4/49)