Project

General

Profile

Download (12.3 KB) Statistics
| Branch: | Tag: | Revision:
1
/**
2
* Copyright (C) 2018 EDIT
3
* European Distributed Institute of Taxonomy
4
* http://www.e-taxonomy.eu
5
*
6
* The contents of this file are subject to the Mozilla Public License Version 1.1
7
* See LICENSE.TXT at the top of this package for the full license terms.
8
*/
9
package eu.etaxonomy.taxeditor.ui.section;
10

    
11
import java.util.ArrayList;
12
import java.util.Collection;
13
import java.util.Collections;
14
import java.util.Comparator;
15
import java.util.EnumSet;
16
import java.util.List;
17
import java.util.Observable;
18
import java.util.Observer;
19

    
20
import org.eclipse.jface.action.Action;
21
import org.eclipse.jface.action.IAction;
22
import org.eclipse.jface.action.ToolBarManager;
23
import org.eclipse.jface.resource.ImageDescriptor;
24
import org.eclipse.swt.SWT;
25
import org.eclipse.swt.events.DisposeEvent;
26
import org.eclipse.swt.events.DisposeListener;
27
import org.eclipse.swt.events.SelectionAdapter;
28
import org.eclipse.swt.events.SelectionEvent;
29
import org.eclipse.swt.events.SelectionListener;
30
import org.eclipse.swt.graphics.Color;
31
import org.eclipse.swt.graphics.ImageData;
32
import org.eclipse.swt.widgets.Composite;
33
import org.eclipse.swt.widgets.Control;
34
import org.eclipse.swt.widgets.Label;
35
import org.eclipse.ui.forms.events.ExpansionEvent;
36
import org.eclipse.ui.forms.events.IExpansionListener;
37
import org.eclipse.ui.forms.widgets.ExpandableComposite;
38

    
39
import eu.etaxonomy.cdm.api.conversation.ConversationHolder;
40
import eu.etaxonomy.cdm.common.CdmUtils;
41
import eu.etaxonomy.cdm.model.common.CdmBase;
42
import eu.etaxonomy.cdm.model.permission.CRUD;
43
import eu.etaxonomy.taxeditor.model.AbstractUtility;
44
import eu.etaxonomy.taxeditor.model.ImageResources;
45
import eu.etaxonomy.taxeditor.preference.IPreferenceKeys;
46
import eu.etaxonomy.taxeditor.preference.PreferencesUtil;
47
import eu.etaxonomy.taxeditor.preference.Resources;
48
import eu.etaxonomy.taxeditor.store.CdmStore;
49
import eu.etaxonomy.taxeditor.store.LoginManager;
50
import eu.etaxonomy.taxeditor.store.StoreUtil;
51
import eu.etaxonomy.taxeditor.ui.element.AbstractFormSection;
52
import eu.etaxonomy.taxeditor.ui.element.CdmFormFactory;
53
import eu.etaxonomy.taxeditor.ui.element.ICdmFormElement;
54
import eu.etaxonomy.taxeditor.ui.element.IEnableableFormElement;
55

    
56
/**
57
 * This class visualizes an CDM entity of type ENTITY and additionally provides
58
 * the functionality to add other elements of type ELEMENT to them.
59
 *
60
 * @param <ENTITY> A CDM entity which should be visualized by this section.
61
 * @param <ELEMENT> An element that can be added (multiple times) to this entity.
62
 *
63
 * @author n.hoffmann
64
 */
65
public abstract class AbstractEntityCollectionSection<ENTITY, ELEMENT>
66
        extends AbstractFormSection<ENTITY>
67
        implements IExpansionListener, Observer, IEnableableFormElement {
68

    
69
    private static final EnumSet<CRUD> UPDATE = EnumSet.of(CRUD.UPDATE);
70

    
71
    protected Composite container;
72

    
73
	private Label label_empty;
74

    
75
	private String title;
76

    
77
    private AbstractEntityCollectionElement<ENTITY> entityCollectionElement;
78
    
79
    private boolean isEnabled = true;
80

    
81
	public AbstractEntityCollectionSection(CdmFormFactory formFactory, ConversationHolder conversation, ICdmFormElement parentElement, String title, int style) {
82
		super(formFactory, parentElement, ExpandableComposite.CLIENT_INDENT | style);
83
		this.title = title;
84
		this.setText(getTitleString());
85
		updateToolbar();
86
		layout();
87
		addExpansionListener(this);
88

    
89
		CdmStore.getLoginManager().addObserver(this);
90
		addDisposeListener(new DisposeListener() {
91
            @Override
92
            public void widgetDisposed(DisposeEvent e) {
93
                CdmStore.getLoginManager().deleteObserver(AbstractEntityCollectionSection.this);
94
            }
95
        });
96
	}
97

    
98
	protected Control createToolbar() {
99
		ToolBarManager toolBarManager = new ToolBarManager(SWT.FLAT);
100

    
101
		Action addAction = new Action("Add", IAction.AS_PUSH_BUTTON){
102
			@Override
103
			public void run() {
104
			    ELEMENT element = createNewElement();
105
			    if(element != null){
106
			        addElement(element);
107
			        if(! getSection().isExpanded()) {
108
			            getSection().setExpanded(true);
109
			        }
110
			        internalUpdateSection(true);
111
			    }
112
			}
113
		};
114
		addAction.setImageDescriptor(new ImageDescriptor() {
115

    
116
			@Override
117
			public ImageData getImageData() {
118
				return ImageResources.getImage(ImageResources.ADD_ICON).getImageData();
119
			}
120
		});
121
		addAction.setToolTipText(getTooltipString());
122

    
123
		Action browseAction = null;
124
		if(allowAddExisting()){
125
		    browseAction = new Action("Browse", IAction.AS_PUSH_BUTTON){
126
		        @Override
127
		        public void run() {
128
		            ELEMENT element = addExisting();
129
		            if(element != null){
130
		                addElement(element);
131
		                if(! getSection().isExpanded()) {
132
		                    getSection().setExpanded(true);
133
		                }
134
		                internalUpdateSection(true);
135
		            }
136
		        }
137
		    };
138
		    browseAction.setImageDescriptor(new ImageDescriptor() {
139

    
140
		        @Override
141
		        public ImageData getImageData() {
142
		            return ImageResources.getImage(ImageResources.BROWSE_ICON).getImageData();
143
		        }
144
		    });
145
		    browseAction.setToolTipText("Browse");
146
		}
147

    
148
		toolBarManager.add(addAction);
149
		if(browseAction!=null){
150
		    toolBarManager.add(browseAction);
151
		}
152

    
153
		addAction(toolBarManager);
154

    
155
		return toolBarManager.createControl(this);
156
	}
157

    
158
    protected void addAction(ToolBarManager toolBarManager) {
159
        // default implementation empty
160
    }
161

    
162
    /**
163
	 * using this method is discouraged, use updateToolBar() instead
164
	 */
165
	public void showToolbar(){
166
		setTextClient(createToolbar());
167
	}
168

    
169
    /**
170
     * using this method is discouraged, use updateToolBar() instead
171
     */
172
	public void removeToolbar(){
173
		setTextClient(null);
174
	}
175

    
176
	@Override
177
	public void setEntity(ENTITY entity) {
178
		if(entity != null){
179
			super.setEntity(entity);
180
			internalUpdateSection(false);
181
		}
182
		setSectionTitle();
183
		updateToolbar();
184
		layout();
185
	}
186

    
187
	/**
188
	 * Sets the title for the section. Adds a "+" sign if the collection is not empty for this section.
189
	 * Override in subclasses if you want to have a different behaviour.
190
	 */
191
	protected void setSectionTitle() {
192
	    ENTITY entity = getEntity();
193
		Collection<ELEMENT> collection = getCollection(entity);
194
		if(collection != null && collection.size() > 0){
195
			this.setText(getTitleString() + " +");
196
		}else{
197
			this.setText(getTitleString());
198
		}
199
	}
200

    
201
	/**
202
	 * Removes all content from the container
203
	 */
204
	protected void destroyDynamicContent(){
205
		if(label_empty != null){
206
			label_empty.dispose();
207
			label_empty = null;
208
		}
209
		removeElements();
210
	}
211

    
212
	/**
213
	 * Call this method after dynamically changing the client area.
214
	 * If the options changed is set to <code>true</code>, will also fire a state changed
215
	 * event to inform the user of unsaved changes.
216
	 *
217
	 * @param changed a boolean.
218
	 */
219
	protected void internalUpdateSection(boolean changed){
220
	    setSectionTitle();
221
		destroyDynamicContent();
222
		if(isExpanded() || expandSectionWhenContentAvailable()) {
223
            renderContent(isExpanded());
224
        }
225
		if(changed) {
226
            firePropertyChangeEvent(this);
227
        }
228
	}
229

    
230
	/**
231
	 * Create the elements to be shown in this section client area
232
	 */
233
	protected void renderContent(boolean forceExpansion){
234
		Collection<ELEMENT> collection = getCollection(getEntity());
235

    
236
		if(collection == null || collection.isEmpty()){
237
			createEmptyContent();
238
		}else{
239
		    List<ELEMENT> elements = new ArrayList<>(collection);
240
		    Collections.sort(elements, getComparator());
241
			createDynamicContents(elements);
242
			forceExpansion = true;
243
		}
244

    
245
		this.setExpanded(forceExpansion);
246

    
247
		reflow();
248
	}
249

    
250
	protected void createEmptyContent(){
251
		if (label_empty == null){
252
			label_empty = formFactory.createLabel(getLayoutComposite(), getEmptyString());
253
		}
254
	}
255

    
256
	/**
257
	 * Creates the widgets for the collection
258
	 */
259
	protected void createDynamicContents(Collection<ELEMENT> elements)
260
	{
261
		int i = 0;
262
		for(final ELEMENT element : elements){
263
			SelectionAdapter removeListener = new SelectionAdapter(){
264
				@Override
265
				public void widgetSelected(SelectionEvent e) {
266
					removeElement(element);
267
					internalUpdateSection(true);
268
				}
269
			};
270
			boolean modulo = i++%2 == 0;
271
			String colorResource = modulo ? Resources.COLOR_LIST_EVEN : Resources.COLOR_LIST_ODD;
272
			createElementComposite(element, removeListener, AbstractUtility.getColor(colorResource));
273
		}
274
	}
275

    
276
	/**
277
	 * Create the specific widget for the element
278
	 *
279
	 * @param element a ELEMENT object.
280
	 * @param removeListener a {@link org.eclipse.swt.events.SelectionListener} object.
281
	 * @param backgroundColor a {@link org.eclipse.swt.graphics.Color} object.
282
	 */
283
	protected void createElementComposite(ELEMENT element, SelectionListener removeListener, Color backgroundColor){
284
		entityCollectionElement = formFactory.createEntityCollectionElement(this, element, removeListener, backgroundColor, SWT.NULL);
285
		entityCollectionElement.setEnabled(isEnabled);
286
	}
287

    
288
	@Override
289
	public void setBackground(Color color) {
290
		if(label_empty != null && !label_empty.isDisposed()){
291
			label_empty.setBackground(color);
292
		}
293
		super.setBackground(color);
294
	}
295

    
296
	/**
297
	 * getTitleString
298
	 */
299
	public String getTitleString() {
300
		return CdmUtils.Nz(title);
301
	}
302

    
303
	/**
304
	 * setTitleString
305
	 */
306
	public void setTitleString(String title){
307
		this.title = title;
308
		setSectionTitle();
309
		layout();
310
	}
311

    
312
	@Override
313
    public void expansionStateChanging(ExpansionEvent e) {
314
//		logger.warn("Expansion State Changing");
315
	}
316

    
317
	@Override
318
    public void expansionStateChanged(ExpansionEvent e) {
319
		if(isExpanded()){
320
			renderContent(isExpanded());
321
		}else{
322
			destroyDynamicContent();
323
		}
324
	}
325

    
326
	protected boolean expandSectionWhenContentAvailable(){
327
		return PreferencesUtil.getBooleanValue(IPreferenceKeys.SHOULD_EXPAND_SECTION_WHEN_DATA_AVAILABLE, true);
328
	}
329

    
330
	/**
331
	 * Remove an element from the entities collection and update the section
332
	 *
333
	 * @param element a ELEMENT object.
334
	 */
335
	public void removeElementAndUpdate(ELEMENT element) {
336
		removeElement(element);
337
		internalUpdateSection(true);
338
	}
339

    
340
	@Override
341
    public void update(Observable o, Object arg){
342
	    if(o instanceof LoginManager){
343
	        updateToolbar();
344
	    }
345
	}
346

    
347
    protected void updateToolbar() {
348
        if( !(getEntity() instanceof CdmBase) || (getEntity() != null && CdmStore.currentAuthentiationHasPermission(StoreUtil.getCdmEntity(getEntity()), UPDATE)) && isEnabled){
349
            showToolbar();
350
        } else {
351
            removeToolbar();
352
        }
353
    }
354

    
355
    public AbstractEntityCollectionElement<ENTITY> getEntityCollectionElement() {
356
        return entityCollectionElement;
357
    }
358

    
359
    /**
360
     * Returns the {@link Comparator} specific for the ELEMENTs
361
     * which is used to sort the elements
362
     * @return the comparator for ELEMENT
363
     */
364
    public abstract Comparator<ELEMENT> getComparator();
365

    
366
	/**
367
	 * Get the specific collection of this entity
368
	 *
369
	 * @param entity a ENTITY object.
370
	 * @return a {@link java.util.Collection} object.
371
	 */
372
	public abstract Collection<ELEMENT> getCollection(ENTITY entity);
373

    
374

    
375
	/**
376
	 * Create a new Element for this collection
377
	 *
378
	 * @return a ELEMENT object.
379
	 */
380
	public abstract ELEMENT createNewElement();
381

    
382
	/**
383
	 * Add an element to the entities collection
384
	 *
385
	 * @param element a ELEMENT object.
386
	 */
387
	public abstract void addElement(ELEMENT element);
388

    
389
	/**
390
	 * Add an existing element to the entities collection.
391
	 * @return the existing element
392
	 */
393
	public abstract ELEMENT addExisting();
394

    
395
	/**
396
	 * If <code>true</code> the section will also display
397
	 * a browse icon to choose from existing elements.
398
	 * <br>
399
	 * <b>Note:</b> when returning true you have to make sure
400
	 * to implement the {@link #addExisting()} method
401
	 * @return true if existing entities can be added;
402
	 * false otherwise
403
	 */
404
	public abstract boolean allowAddExisting();
405

    
406
	/**
407
	 * Remove an element from the entities collection
408
	 *
409
	 * @param element a ELEMENT object.
410
	 */
411
	public abstract void removeElement(ELEMENT element);
412

    
413
	/**
414
	 * String to display when the collection is empty
415
	 *
416
	 * @return a {@link java.lang.String} object.
417
	 */
418
	public abstract String getEmptyString();
419

    
420
	/**
421
	 * <p>getTooltipString</p>
422
	 *
423
	 * @return String to display when hovering the add button
424
	 */
425
	protected abstract String getTooltipString();
426
	
427
	public boolean isEnabled(){
428
		return isEnabled;
429
	}
430
	
431
	public void setEnabled(boolean enabled){
432
		isEnabled=enabled;
433
		if (!isEnabled){
434
			removeToolbar();
435
		}
436
		
437
		for (ICdmFormElement element: getElements()){
438
			if (element instanceof IEnableableFormElement){
439
				((IEnableableFormElement)element).setEnabled(isEnabled);
440
			}
441
		}
442
		
443
	}
444
}
(4-4/9)