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.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.IEditorPart;
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
 * @version 1.0
53
 * @param <T>
54
 */
55
//TODO shouldn't ENTITY be bound with super class ICdmBase for example (AbstractFormSection<ENTITY extends ICdmBase>)?
56
public abstract class AbstractFormSection<ENTITY> extends Section implements ISelectionChangedListener, IEntityElement<ENTITY>, IConversationEnabled {
57

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

    
63
	private ISelectionProvider selectionProvider;
64

    
65
	private ENTITY entity;
66

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

    
69
	protected CdmFormFactory formFactory;
70

    
71
	private List<IPropertyChangeListener> propertyChangeListeners;
72

    
73
	private ICdmFormElement parentElement;
74

    
75
	private Color persistentBackgroundColor;
76

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

    
98
		this.parentElement = parentElement;
99

    
100
		this.formFactory = formFactory;
101

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

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

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

    
112
		client.setLayout(layout);
113

    
114
		this.setClient(client);
115

    
116
	}
117

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
312

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

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

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

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

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

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

    
372
		Object selectedObject = selection.getFirstElement();
373

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

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

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

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

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

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

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

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

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

    
459
		elements.clear();
460
	}
461

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

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

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

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

    
501
		return controls;
502
	}
503

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

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

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

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

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

    
565
	}
566

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

    
582
	        IEditorPart activeEditor = AbstractUtility.getActiveEditor();
583
	        if(activeEditor instanceof IConversationEnabled){
584
	            ConversationHolder conversation = ((IConversationEnabled) AbstractUtility.getActiveEditor()).getConversationHolder();
585
	            return conversation;
586
	        }
587
	    }else if(getParentElement() instanceof IConversationEnabled){
588
	        return ((IConversationEnabled) getParentElement()).getConversationHolder();
589
	    }
590
		MessagingUtils.messageDialog("Could not get conversation for AbstractFormSection",
591
				getClass(), "There is an error in the implementation. There should have been an active editor but it wasn't",
592
				new IllegalArgumentException());
593
		return null;
594

    
595
	}
596

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

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

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

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

    
627

    
628
}
(4-4/44)