Project

General

Profile

Download (11.6 KB) Statistics
| Branch: | Tag: | Revision:
1
/**
2
 *
3
 */
4
package eu.etaxonomy.taxeditor.ui.section;
5

    
6
import java.util.ArrayList;
7
import java.util.Collection;
8
import java.util.Collections;
9
import java.util.Comparator;
10
import java.util.EnumSet;
11
import java.util.List;
12
import java.util.Observable;
13
import java.util.Observer;
14

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

    
34
import eu.etaxonomy.cdm.api.conversation.ConversationHolder;
35
import eu.etaxonomy.cdm.common.CdmUtils;
36
import eu.etaxonomy.cdm.model.permission.CRUD;
37
import eu.etaxonomy.taxeditor.model.AbstractUtility;
38
import eu.etaxonomy.taxeditor.model.ImageResources;
39
import eu.etaxonomy.taxeditor.preference.IPreferenceKeys;
40
import eu.etaxonomy.taxeditor.preference.PreferencesUtil;
41
import eu.etaxonomy.taxeditor.preference.Resources;
42
import eu.etaxonomy.taxeditor.store.CdmStore;
43
import eu.etaxonomy.taxeditor.store.LoginManager;
44
import eu.etaxonomy.taxeditor.store.StoreUtil;
45
import eu.etaxonomy.taxeditor.ui.element.AbstractFormSection;
46
import eu.etaxonomy.taxeditor.ui.element.CdmFormFactory;
47
import eu.etaxonomy.taxeditor.ui.element.ICdmFormElement;
48

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

    
60
    private static final EnumSet<CRUD> UPDATE = EnumSet.of(CRUD.UPDATE);
61

    
62
    protected Composite container;
63

    
64
	private Label label_empty;
65

    
66
	private String title;
67

    
68
    private AbstractEntityCollectionElement<ENTITY> entityCollectionElement;
69

    
70
	public AbstractEntityCollectionSection(CdmFormFactory formFactory, ConversationHolder conversation, ICdmFormElement parentElement, String title, int style) {
71
		super(formFactory, parentElement, ExpandableComposite.CLIENT_INDENT | style);
72
		this.title = title;
73
		this.setText(getTitleString());
74
		updateToolbar();
75

    
76
		addExpansionListener(this);
77

    
78
		CdmStore.getLoginManager().addObserver(this);
79
		addDisposeListener(new DisposeListener() {
80
            @Override
81
            public void widgetDisposed(DisposeEvent e) {
82
                CdmStore.getLoginManager().deleteObserver(AbstractEntityCollectionSection.this);
83
            }
84
        });
85
	}
86

    
87
	protected Control createToolbar() {
88
		ToolBarManager toolBarManager = new ToolBarManager(SWT.FLAT);
89

    
90
		Action addAction = new Action("Add", IAction.AS_PUSH_BUTTON){
91
			@Override
92
			public void run() {
93
			    ELEMENT element = createNewElement();
94
			    if(element != null){
95
			        addElement(element);
96
			        if(! getSection().isExpanded()) {
97
			            getSection().setExpanded(true);
98
			        }
99
			        internalUpdateSection(true);
100
			    }
101
			}
102
		};
103
		addAction.setImageDescriptor(new ImageDescriptor() {
104

    
105
			@Override
106
			public ImageData getImageData() {
107
				return ImageResources.getImage(ImageResources.ADD_ICON).getImageData();
108
			}
109
		});
110
		addAction.setToolTipText(getTooltipString());
111

    
112
		Action browseAction = null;
113
		if(allowAddExisting()){
114
		    browseAction = new Action("Browse", IAction.AS_PUSH_BUTTON){
115
		        @Override
116
		        public void run() {
117
		            ELEMENT element = addExisting();
118
		            if(element != null){
119
		                addElement(element);
120
		                if(! getSection().isExpanded()) {
121
		                    getSection().setExpanded(true);
122
		                }
123
		                internalUpdateSection(true);
124
		            }
125
		        }
126
		    };
127
		    browseAction.setImageDescriptor(new ImageDescriptor() {
128

    
129
		        @Override
130
		        public ImageData getImageData() {
131
		            return ImageResources.getImage(ImageResources.BROWSE_ICON).getImageData();
132
		        }
133
		    });
134
		    browseAction.setToolTipText("Browse");
135
		}
136

    
137
		toolBarManager.add(addAction);
138
		if(browseAction!=null){
139
		    toolBarManager.add(browseAction);
140
		}
141

    
142
		addAction(toolBarManager);
143

    
144
		return toolBarManager.createControl(this);
145
	}
146

    
147
    protected void addAction(ToolBarManager toolBarManager) {
148
        // default implementation empty
149
    }
150

    
151
    /**
152
	 * using this method is discouraged, use updateToolBar() instead
153
	 */
154
	public void showToolbar(){
155
		setTextClient(createToolbar());
156
	}
157

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

    
165
	@Override
166
	public void setEntity(ENTITY entity) {
167
		if(entity != null){
168
			super.setEntity(entity);
169
			internalUpdateSection(false);
170
		}
171
		setSectionTitle();
172
		updateToolbar();
173
		layout();
174
	}
175

    
176
	/**
177
	 * Sets the title for the section. Adds a "+" sign if the collection is not empty for this section.
178
	 * Override in subclasses if you want to have a different behaviour.
179
	 */
180
	protected void setSectionTitle() {
181
		Collection<ELEMENT> collection = getCollection(getEntity());
182
		if(collection != null && collection.size() > 0){
183
			this.setText(getTitleString() + " +");
184
		}else{
185
			this.setText(getTitleString());
186
		}
187
	}
188

    
189
	/**
190
	 * Removes all content from the container
191
	 */
192
	private void destroyDynamicContent(){
193
		if(label_empty != null){
194
			label_empty.dispose();
195
			label_empty = null;
196
		}
197
		removeElements();
198
	}
199

    
200
	/**
201
	 * Call this method after dynamically changing the client area.
202
	 * If the options changed is set to <code>true</code>, will also fire a state changed
203
	 * event to inform the user of unsaved changes.
204
	 *
205
	 * @param changed a boolean.
206
	 */
207
	protected void internalUpdateSection(boolean changed){
208
	    setSectionTitle();
209
		destroyDynamicContent();
210
		if(isExpanded() || expandSectionWhenContentAvailable()) {
211
            renderContent(isExpanded());
212
        }
213
		if(changed) {
214
            firePropertyChangeEvent(this);
215
        }
216
	}
217

    
218
	/**
219
	 * Create the elements to be shown in this section client area
220
	 */
221
	private void renderContent(boolean forceExpansion)
222
	{
223
		Collection<ELEMENT> collection = getCollection(getEntity());
224

    
225
		if(collection == null || collection.isEmpty()){
226
			createEmptyContent();
227
		}else{
228
		    List<ELEMENT> elements = new ArrayList<>(collection);
229
		    Collections.sort(elements, getComparator());
230
			createDynamicContents(elements);
231
			forceExpansion = true;
232
		}
233

    
234
		this.setExpanded(forceExpansion);
235

    
236
		reflow();
237
	}
238

    
239
	protected void createEmptyContent(){
240
		label_empty = formFactory.createLabel(getLayoutComposite(), getEmptyString());
241
	}
242

    
243
	/**
244
	 * Creates the widgets for the collection
245
	 *
246
	 * @param elements a {@link java.util.Collection} object.
247
	 */
248
	protected void createDynamicContents(Collection<ELEMENT> elements)
249
	{
250
		int i = 0;
251
		for(final ELEMENT element : elements){
252
			SelectionAdapter removeListener = new SelectionAdapter(){
253
				@Override
254
				public void widgetSelected(SelectionEvent e) {
255
					removeElement(element);
256
					internalUpdateSection(true);
257
				}
258
			};
259
			boolean modulo = i++%2 == 0;
260
			String colorResource = modulo ? Resources.COLOR_LIST_EVEN : Resources.COLOR_LIST_ODD;
261
			createElementComposite(element, removeListener, AbstractUtility.getColor(colorResource));
262
		}
263
	}
264

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

    
276
	/** {@inheritDoc} */
277
	@Override
278
	public void setBackground(Color color) {
279
		if(label_empty != null && !label_empty.isDisposed()){
280
			label_empty.setBackground(color);
281
		}
282
		super.setBackground(color);
283
	}
284

    
285
	/**
286
	 * <p>getTitleString</p>
287
	 *
288
	 * @return a {@link java.lang.String} object.
289
	 */
290
	public String getTitleString() {
291
		return CdmUtils.Nz(title);
292
	}
293

    
294
	/**
295
	 * <p>setTitleString</p>
296
	 *
297
	 * @param title a {@link java.lang.String} object.
298
	 */
299
	public void setTitleString(String title){
300
		this.title = title;
301
		setSectionTitle();
302
		layout();
303
	}
304

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

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

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

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

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

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

    
350
    public AbstractEntityCollectionElement<ENTITY> getEntityCollectionElement() {
351
        return entityCollectionElement;
352
    }
353

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

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

    
369

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

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

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

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

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

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

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