Project

General

Profile

Download (11.7 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

    
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 {
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
	public AbstractEntityCollectionSection(CdmFormFactory formFactory, ConversationHolder conversation, ICdmFormElement parentElement, String title, int style) {
79
		super(formFactory, parentElement, ExpandableComposite.CLIENT_INDENT | style);
80
		this.title = title;
81
		this.setText(getTitleString());
82
		updateToolbar();
83

    
84
		addExpansionListener(this);
85

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

    
95
	protected Control createToolbar() {
96
		ToolBarManager toolBarManager = new ToolBarManager(SWT.FLAT);
97

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

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

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

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

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

    
150
		addAction(toolBarManager);
151

    
152
		return toolBarManager.createControl(this);
153
	}
154

    
155
    protected void addAction(ToolBarManager toolBarManager) {
156
        // default implementation empty
157
    }
158

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

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

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

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

    
197
	/**
198
	 * Removes all content from the container
199
	 */
200
	private void destroyDynamicContent(){
201
		if(label_empty != null){
202
			label_empty.dispose();
203
			label_empty = null;
204
		}
205
		removeElements();
206
	}
207

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

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

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

    
241
		this.setExpanded(forceExpansion);
242

    
243
		reflow();
244
	}
245

    
246
	protected void createEmptyContent(){
247
		label_empty = formFactory.createLabel(getLayoutComposite(), getEmptyString());
248
	}
249

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

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

    
281
	@Override
282
	public void setBackground(Color color) {
283
		if(label_empty != null && !label_empty.isDisposed()){
284
			label_empty.setBackground(color);
285
		}
286
		super.setBackground(color);
287
	}
288

    
289
	/**
290
	 * getTitleString
291
	 */
292
	public String getTitleString() {
293
		return CdmUtils.Nz(title);
294
	}
295

    
296
	/**
297
	 * setTitleString
298
	 */
299
	public void setTitleString(String title){
300
		this.title = title;
301
		setSectionTitle();
302
		layout();
303
	}
304

    
305
	@Override
306
    public void expansionStateChanging(ExpansionEvent e) {
307
//		logger.warn("Expansion State Changing");
308
	}
309

    
310
	@Override
311
    public void expansionStateChanged(ExpansionEvent e) {
312
		if(isExpanded()){
313
			renderContent(isExpanded());
314
		}else{
315
			destroyDynamicContent();
316
		}
317
	}
318

    
319
	private boolean expandSectionWhenContentAvailable(){
320
		return PreferencesUtil.getBooleanValue(IPreferenceKeys.SHOULD_EXPAND_SECTION_WHEN_DATA_AVAILABLE, true);
321
	}
322

    
323
	/**
324
	 * Remove an element from the entities collection and update the section
325
	 *
326
	 * @param element a ELEMENT object.
327
	 */
328
	public void removeElementAndUpdate(ELEMENT element) {
329
		removeElement(element);
330
		internalUpdateSection(true);
331
	}
332

    
333
	@Override
334
    public void update(Observable o, Object arg){
335
	    if(o instanceof LoginManager){
336
	        updateToolbar();
337
	    }
338
	}
339

    
340
    protected void updateToolbar() {
341
        if( !(getEntity() instanceof CdmBase) || (getEntity() != null && CdmStore.currentAuthentiationHasPermission(StoreUtil.getCdmEntity(getEntity()), UPDATE)) ){
342
            showToolbar();
343
        } else {
344
            removeToolbar();
345
        }
346
    }
347

    
348
    public AbstractEntityCollectionElement<ENTITY> getEntityCollectionElement() {
349
        return entityCollectionElement;
350
    }
351

    
352
    /**
353
     * Returns the {@link Comparator} specific for the ELEMENTs
354
     * which is used to sort the elements
355
     * @return the comparator for ELEMENT
356
     */
357
    public abstract Comparator<ELEMENT> getComparator();
358

    
359
	/**
360
	 * Get the specific collection of this entity
361
	 *
362
	 * @param entity a ENTITY object.
363
	 * @return a {@link java.util.Collection} object.
364
	 */
365
	public abstract Collection<ELEMENT> getCollection(ENTITY entity);
366

    
367

    
368
	/**
369
	 * Create a new Element for this collection
370
	 *
371
	 * @return a ELEMENT object.
372
	 */
373
	public abstract ELEMENT createNewElement();
374

    
375
	/**
376
	 * Add an element to the entities collection
377
	 *
378
	 * @param element a ELEMENT object.
379
	 */
380
	public abstract void addElement(ELEMENT element);
381

    
382
	/**
383
	 * Add an existing element to the entities collection.
384
	 * @return the existing element
385
	 */
386
	public abstract ELEMENT addExisting();
387

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

    
399
	/**
400
	 * Remove an element from the entities collection
401
	 *
402
	 * @param element a ELEMENT object.
403
	 */
404
	public abstract void removeElement(ELEMENT element);
405

    
406
	/**
407
	 * String to display when the collection is empty
408
	 *
409
	 * @return a {@link java.lang.String} object.
410
	 */
411
	public abstract String getEmptyString();
412

    
413
	/**
414
	 * <p>getTooltipString</p>
415
	 *
416
	 * @return String to display when hovering the add button
417
	 */
418
	protected abstract String getTooltipString();
419
}
(4-4/9)