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
    private Collection<ELEMENT> collection;
73

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

    
80
		addExpansionListener(this);
81

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

    
91
	protected Control createToolbar() {
92
		ToolBarManager toolBarManager = new ToolBarManager(SWT.FLAT);
93

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

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

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

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

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

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

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

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

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

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

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

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

    
216
	/**
217
	 * Create the elements to be shown in this section client area
218
	 */
219
	private void renderContent(boolean forceExpansion)
220
	{
221

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

    
231
		this.setExpanded(forceExpansion);
232

    
233
		reflow();
234
	}
235

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
366

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

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

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

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

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

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

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