Project

General

Profile

Download (11.7 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
 * @version $Id: $
58
 */
59

    
60
public abstract class AbstractEntityCollectionSection<ENTITY, ELEMENT> extends AbstractFormSection<ENTITY> implements IExpansionListener, Observer {
61

    
62
    private static final EnumSet<CRUD> UPDATE = EnumSet.of(CRUD.UPDATE);
63

    
64
    protected Composite container;
65

    
66
	private Label label_empty;
67

    
68
	private String title;
69

    
70
    private AbstractEntityCollectionElement<ENTITY> entityCollectionElement;
71

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

    
78
		addExpansionListener(this);
79

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

    
89
	protected Control createToolbar() {
90
		ToolBarManager toolBarManager = new ToolBarManager(SWT.FLAT);
91

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

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

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

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

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

    
144
		addAction(toolBarManager);
145

    
146
		return toolBarManager.createControl(this);
147
	}
148

    
149
    protected void addAction(ToolBarManager toolBarManager) {
150
        // default implementation empty
151
    }
152

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

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

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

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

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

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

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

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

    
236
		this.setExpanded(forceExpansion);
237

    
238
		reflow();
239
	}
240

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

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

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

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

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

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

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

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

    
323
	private boolean expandSectionWhenContentAvailable(){
324
		return PreferencesUtil.getBooleanValue(IPreferenceKeys.SHOULD_EXPAND_SECTION_WHEN_DATA_AVAILABLE);
325
	}
326

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

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

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

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

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

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

    
371

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

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

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

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

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

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

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