Project

General

Profile

Download (11.5 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.persistence.hibernate.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 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
		return toolBarManager.createControl(this);
145
	}
146

    
147
	/**
148
	 * using this method is discouraged, use updateToolBar() instead
149
	 */
150
	public void showToolbar(){
151
		setTextClient(createToolbar());
152
	}
153

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

    
161
	@Override
162
	public void setEntity(ENTITY entity) {
163
		if(entity != null){
164
			super.setEntity(entity);
165
			internalUpdateSection(false);
166
		}
167
		setSectionTitle();
168
		updateToolbar();
169
		layout();
170
	}
171

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

    
185
	/**
186
	 * Removes all content from the container
187
	 */
188
	private void destroyDynamicContent(){
189
		if(label_empty != null){
190
			label_empty.dispose();
191
			label_empty = null;
192
		}
193
		removeElements();
194
	}
195

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

    
214
	/**
215
	 * Create the elements to be shown in this section client area
216
	 */
217
	private void renderContent(boolean forceExpansion)
218
	{
219
		List<ELEMENT> elements = new ArrayList<>(getCollection(getEntity()));
220
		Collections.sort(elements, getComparator());
221

    
222
		if(elements == null || elements.isEmpty()){
223
			createEmptyContent();
224
		}else{
225
			createDynamicContents(elements);
226
			forceExpansion = true;
227
		}
228

    
229
		this.setExpanded(forceExpansion);
230

    
231
		reflow();
232
	}
233

    
234
	protected void createEmptyContent(){
235
		label_empty = formFactory.createLabel(getLayoutComposite(), getEmptyString());
236
	}
237

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

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

    
271
	/** {@inheritDoc} */
272
	@Override
273
	public void setBackground(Color color) {
274
		if(label_empty != null && !label_empty.isDisposed()){
275
			label_empty.setBackground(color);
276
		}
277
		super.setBackground(color);
278
	}
279

    
280
	/**
281
	 * <p>getTitleString</p>
282
	 *
283
	 * @return a {@link java.lang.String} object.
284
	 */
285
	public String getTitleString() {
286
		return CdmUtils.Nz(title);
287
	}
288

    
289
	/**
290
	 * <p>setTitleString</p>
291
	 *
292
	 * @param title a {@link java.lang.String} object.
293
	 */
294
	public void setTitleString(String title){
295
		this.title = title;
296
		setSectionTitle();
297
		layout();
298
	}
299

    
300
	/** {@inheritDoc} */
301
	@Override
302
    public void expansionStateChanging(ExpansionEvent e) {
303
//		logger.warn("Expansion State Changing");
304
	}
305

    
306
	/** {@inheritDoc} */
307
	@Override
308
    public void expansionStateChanged(ExpansionEvent e) {
309
		if(isExpanded()){
310
			renderContent(isExpanded());
311
		}else{
312
			destroyDynamicContent();
313
		}
314
	}
315

    
316
	private boolean expandSectionWhenContentAvailable(){
317
		return PreferencesUtil.getPreferenceStore().getBoolean(IPreferenceKeys.SHOULD_EXPAND_SECTION_WHEN_DATA_AVAILABLE);
318
	}
319

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

    
330
	@Override
331
    public void update(Observable o, Object arg){
332
	    if(o instanceof LoginManager){
333
	        updateToolbar();
334
	    }
335
	}
336

    
337
    private void updateToolbar() {
338
        if(getEntity() != null && CdmStore.currentAuthentiationHasPermission(StoreUtil.getCdmEntity(getEntity()), UPDATE)){
339
            showToolbar();
340
        } else {
341
            removeToolbar();
342
        }
343
    }
344

    
345
    public AbstractEntityCollectionElement getEntityCollectionElement() {
346
        return entityCollectionElement;
347
    }
348

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

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

    
364

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

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

    
379
	/**
380
	 * Add an existing element to the entities collection.
381
	 * @return the existing element
382
	 */
383
	public abstract ELEMENT addExisting();
384

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

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

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

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