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.common.CdmUtils;
40
import eu.etaxonomy.cdm.model.common.CdmBase;
41
import eu.etaxonomy.cdm.model.permission.CRUD;
42
import eu.etaxonomy.taxeditor.model.AbstractUtility;
43
import eu.etaxonomy.taxeditor.model.ImageResources;
44
import eu.etaxonomy.taxeditor.preference.IPreferenceKeys;
45
import eu.etaxonomy.taxeditor.preference.PreferencesUtil;
46
import eu.etaxonomy.taxeditor.preference.Resources;
47
import eu.etaxonomy.taxeditor.store.CdmStore;
48
import eu.etaxonomy.taxeditor.store.LoginManager;
49
import eu.etaxonomy.taxeditor.store.StoreUtil;
50
import eu.etaxonomy.taxeditor.ui.element.AbstractFormSection;
51
import eu.etaxonomy.taxeditor.ui.element.CdmFormFactory;
52
import eu.etaxonomy.taxeditor.ui.element.ICdmFormElement;
53
import eu.etaxonomy.taxeditor.ui.element.IEnableableFormElement;
54

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

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

    
70
    protected Composite container;
71

    
72
	private Label label_empty;
73

    
74
	private String title;
75

    
76
    private AbstractEntityCollectionElement<ENTITY> entityCollectionElement;
77

    
78
    private boolean isEnabled = true;
79

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

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

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

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

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

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

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

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

    
152
		addAction(toolBarManager);
153

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

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

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

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

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

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

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

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

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

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

    
244
		this.setExpanded(forceExpansion);
245

    
246
		reflow();
247
	}
248

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

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

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

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

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

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

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

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

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

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

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

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

    
353
    public AbstractEntityCollectionElement<ENTITY> getEntityCollectionElement() {
354
        return entityCollectionElement;
355
    }
356

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

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

    
372

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

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

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

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

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

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

    
418
	/**
419
	 * <p>getTooltipString</p>
420
	 *
421
	 * @return String to display when hovering the add button
422
	 */
423
	protected abstract String getTooltipString();
424

    
425
	@Override
426
    public boolean isEnabled(){
427
		return isEnabled;
428
	}
429

    
430
	@Override
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)