Project

General

Profile

Download (15.7 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
 * @version 1.0
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<ICdmFormElement>();
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
	 * (non-Javadoc)
175
	 *
176
	 * @see eu.etaxonomy.taxeditor.forms.IEntityElement#getEntity()
177
	 */
178
	/**
179
	 * <p>
180
	 * Getter for the field <code>entity</code>.
181
	 * </p>
182
	 *
183
	 * @return a ENTITY object.
184
	 */
185
	@Override
186
    public ENTITY getEntity() {
187
		return entity;
188
	}
189

    
190
	/**
191
	 * <p>
192
	 * getToggle
193
	 * </p>
194
	 *
195
	 * @return a {@link org.eclipse.ui.forms.widgets.ToggleHyperlink} object.
196
	 */
197
	public ToggleHyperlink getToggle() {
198
		return this.toggle;
199
	}
200

    
201
	/**
202
	 * <p>
203
	 * getSection
204
	 * </p>
205
	 *
206
	 * @return a {@link eu.etaxonomy.taxeditor.ui.element.AbstractFormSection}
207
	 *         object.
208
	 */
209
	public AbstractFormSection<ENTITY> getSection() {
210
		return this;
211
	}
212

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

    
234
	/**
235
	 * Fires a {@link CdmPropertyChangeEvent} with the given object as source.
236
	 *
237
	 * @param object
238
	 *            the object on which the property changed
239
	 */
240
	public void firePropertyChangeEvent(Object object) {
241
		firePropertyChangeEvent(object, null);
242
	}
243

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

    
259
	/*
260
	 * (non-Javadoc)
261
	 *
262
	 * @see org.eclipse.swt.widgets.Composite#setFocus()
263
	 */
264
	/** {@inheritDoc} */
265
	@Override
266
	public boolean setFocus() {
267
		return getClient().setFocus();
268
	}
269

    
270
	/*
271
	 * (non-Javadoc)
272
	 *
273
	 * @see
274
	 * org.eclipse.jface.util.IPropertyChangeListener#propertyChange(org.eclipse
275
	 * .jface.util.PropertyChangeEvent)
276
	 */
277
	/** {@inheritDoc} */
278
	@Override
279
    public void propertyChange(PropertyChangeEvent event) {
280
		firePropertyChangeEvent(new CdmPropertyChangeEvent(this, event));
281
	}
282

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

    
300
	@Override
301
	public void setPersistentBackground(Color color) {
302
		persistentBackgroundColor = color;
303
		setBackground(color);
304
	}
305

    
306
	@Override
307
	public Color getPersistentBackground() {
308
		return persistentBackgroundColor;
309
	}
310

    
311

    
312
	/**
313
	 * <p>
314
	 * widgetSelected
315
	 * </p>
316
	 *
317
	 * @param e
318
	 *            a {@link org.eclipse.swt.events.SelectionEvent} object.
319
	 */
320
	public void widgetSelected(SelectionEvent e) {
321
        Widget widget = e.widget;
322

    
323
        if (widget instanceof Control) {
324
            Control control = (Control) widget;
325
            if (checkControlAncestryForWidget(control)) {
326
                if (getEntity() != null) {
327
                    IStructuredSelection selection = new StructuredSelection(getEntity());
328
                    if (selectionProvider != null) {
329
                        selectionProvider.setSelection(selection);
330
                    }
331
                }
332
            }
333
        }
334
	}
335

    
336
	private boolean checkControlAncestryForWidget(Control control) {
337
		if (control.equals(this)) {
338
			return true;
339
		} else {
340
			Control parent = control.getParent();
341
			if (parent == null) {
342
				return false;
343
			} else {
344
				return checkControlAncestryForWidget(parent);
345
			}
346
		}
347
	}
348

    
349
	/** {@inheritDoc} */
350
	@Override
351
    public void setSelected(boolean selected) {
352
		if (selected) {
353
			setBackground(Display.getCurrent().getSystemColor(
354
					SWT.COLOR_LIST_SELECTION));
355
		} else {
356
			setBackground(Display.getCurrent().getSystemColor(SWT.COLOR_WHITE));
357
		}
358
	}
359

    
360
	/** {@inheritDoc} */
361
	@Override
362
    public void selectionChanged(SelectionChangedEvent event) {
363
		if (event.getSelection() == CdmFormFactory.EMPTY_SELECTION) {
364
			return;
365
		}
366

    
367
		IStructuredSelection selection = (IStructuredSelection) event
368
				.getSelection();
369
		setSelected(false);
370

    
371
		Object selectedObject = selection.getFirstElement();
372

    
373
		if (selectedObject != null && selectedObject.equals(getEntity())) {
374
			setSelected(true);
375
		}
376
	}
377

    
378
	/**
379
	 * <p>
380
	 * addSelectionListener
381
	 * </p>
382
	 *
383
	 * @param listener
384
	 *            a {@link org.eclipse.swt.events.SelectionListener} object.
385
	 */
386
	public void addSelectionListener(SelectionListener listener) {
387
		addListener(SWT.Selection, new TypedListener(listener));
388
	}
389

    
390
	/**
391
	 * <p>
392
	 * removeSelectionListener
393
	 * </p>
394
	 *
395
	 * @param listener
396
	 *            a {@link org.eclipse.swt.events.SelectionListener} object.
397
	 */
398
	public void removeSelectionListener(SelectionListener listener) {
399
		removeListener(SWT.Selection, listener);
400
	}
401

    
402
	/** {@inheritDoc} */
403
	@Override
404
    public void addElement(ICdmFormElement element) {
405
		elements.add(element);
406
	}
407

    
408
	/**
409
	 * <p>
410
	 * removeElement
411
	 * </p>
412
	 *
413
	 * @param element
414
	 *            a {@link eu.etaxonomy.taxeditor.ui.element.ICdmFormElement}
415
	 *            object.
416
	 */
417
	protected void removeElement(ICdmFormElement element) {
418
		elements.remove(element);
419
	}
420

    
421
	/**
422
	 * <p>
423
	 * removeElements
424
	 * </p>
425
	 */
426
	@Override
427
    public void removeElements() {
428
		for (ICdmFormElement childElement : getElements()) {
429
			// recursion
430
			childElement.removeElements();
431

    
432
			// unregister selection arbitrator
433
			if (childElement instanceof ISelectableElement) {
434
				ISelectableElement selectableElement = (ISelectableElement) childElement;
435
				if (selectableElement.getSelectionArbitrator() != null) {
436
					formFactory.destroySelectionArbitrator(selectableElement
437
							.getSelectionArbitrator());
438
				}
439
			}
440

    
441
			// unregister propertyChangeListener
442
			formFactory.removePropertyChangeListener(childElement);
443

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

    
458
		elements.clear();
459
	}
460

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

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

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

    
496
		for (Control control : getChildren()) {
497
			controls.add(control);
498
		}
499

    
500
		return controls;
501
	}
502

    
503
	/** {@inheritDoc} */
504
	@Override
505
	public void dispose() {
506
		removeElements();
507
		super.dispose();
508
	}
509

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

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

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

    
550
	/*
551
	 * (non-Javadoc)
552
	 *
553
	 * @see eu.etaxonomy.taxeditor.forms.ICdmFormElement#refresh()
554
	 */
555
	/**
556
	 * <p>
557
	 * refresh
558
	 * </p>
559
	 */
560
	@Override
561
    public void refresh() {
562
		// empty default implementation
563

    
564
	}
565

    
566
	/**
567
	 * <p>
568
	 * getConversationHolder
569
	 * </p>
570
	 *
571
	 * @return a {@link eu.etaxonomy.cdm.api.conversation.ConversationHolder}
572
	 *         object.
573
	 */
574
	@Override
575
    public ConversationHolder getConversationHolder() {
576
	    if(AbstractUtility.getActivePart() instanceof IConversationEnabled){
577
            return ((IConversationEnabled) AbstractUtility.getActivePart()).getConversationHolder();
578
        }
579
	    if(getParentElement() instanceof RootElement || getParentElement() == null){
580

    
581
	        Object activeEditor = AbstractUtility.getActiveEditor();
582
	        if(activeEditor instanceof IConversationEnabled){
583
	            ConversationHolder conversation = ((IConversationEnabled) AbstractUtility.getActiveEditor()).getConversationHolder();
584
	            return conversation;
585
	        }
586
	    }else if(getParentElement() instanceof IConversationEnabled){
587
	        return ((IConversationEnabled) getParentElement()).getConversationHolder();
588
	    }
589
		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",
590
				new IllegalArgumentException());
591
		return null;
592

    
593
	}
594

    
595
	/** {@inheritDoc} */
596
	@Override
597
    public void update(CdmDataChangeMap changeEvents) {
598

    
599
	}
600

    
601
    public class ExpandListener implements IExpansionListener{
602
		@Override
603
		public void expansionStateChanging(ExpansionEvent e) {
604
		}
605
		@Override
606
		public void expansionStateChanged(ExpansionEvent e) {
607
			PreferencesUtil.getPreferenceStore().setValue(getPrefKey(), e.getState());
608
		}
609
    }
610

    
611
    /**
612
     * Adds a custom implementation of IExpansionListener to this section
613
     * which stores the expansion state in the preferences
614
     */
615
	protected void addExpandListener() {
616
		PreferencesUtil.getPreferenceStore().setDefault(getPrefKey(), isExpanded());
617
		setExpanded(PreferencesUtil.getPreferenceStore().getBoolean(getPrefKey()));
618
		addExpansionListener(new ExpandListener());
619
	}
620

    
621
	private String getPrefKey() {
622
		return this.getClass().getCanonicalName()+";"+entity.getClass().getCanonicalName();
623
	}
624

    
625

    
626
}
(4-4/45)