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<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
		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
		Collection<ELEMENT> collection = getCollection(getEntity());
220

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

    
230
		this.setExpanded(forceExpansion);
231

    
232
		reflow();
233
	}
234

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

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

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

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

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

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

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

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

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

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

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

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

    
346
    public AbstractEntityCollectionElement<ENTITY> getEntityCollectionElement() {
347
        return entityCollectionElement;
348
    }
349

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

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

    
365

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

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

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

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

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

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

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