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

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

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

    
63
    protected Composite container;
64

    
65
	private Label label_empty;
66

    
67
	private String title;
68

    
69
    private AbstractEntityCollectionElement<ENTITY> entityCollectionElement;
70

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

    
77
		addExpansionListener(this);
78

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

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

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

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

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

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

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

    
143
		addAction(toolBarManager);
144

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

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

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

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

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

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

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

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

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

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

    
235
		this.setExpanded(forceExpansion);
236

    
237
		reflow();
238
	}
239

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
370

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

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

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

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

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

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

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