d349a64eed00b0506616e692277a58aa18a9e4ac
[taxeditor.git] / eu.etaxonomy.taxeditor.store / src / main / java / eu / etaxonomy / taxeditor / ui / section / AbstractEntityCollectionSection.java
1 /**
2 *
3 */
4 package eu.etaxonomy.taxeditor.ui.section;
5
6 import java.util.Collection;
7 import java.util.EnumSet;
8 import java.util.Observable;
9 import java.util.Observer;
10
11 import org.eclipse.jface.action.Action;
12 import org.eclipse.jface.action.IAction;
13 import org.eclipse.jface.action.ToolBarManager;
14 import org.eclipse.jface.resource.ImageDescriptor;
15 import org.eclipse.swt.SWT;
16 import org.eclipse.swt.events.DisposeEvent;
17 import org.eclipse.swt.events.DisposeListener;
18 import org.eclipse.swt.events.SelectionAdapter;
19 import org.eclipse.swt.events.SelectionEvent;
20 import org.eclipse.swt.events.SelectionListener;
21 import org.eclipse.swt.graphics.Color;
22 import org.eclipse.swt.graphics.ImageData;
23 import org.eclipse.swt.widgets.Composite;
24 import org.eclipse.swt.widgets.Control;
25 import org.eclipse.swt.widgets.Label;
26 import org.eclipse.ui.forms.events.ExpansionEvent;
27 import org.eclipse.ui.forms.events.IExpansionListener;
28 import org.eclipse.ui.forms.widgets.ExpandableComposite;
29
30 import eu.etaxonomy.cdm.api.conversation.ConversationHolder;
31 import eu.etaxonomy.cdm.common.CdmUtils;
32 import eu.etaxonomy.cdm.persistence.hibernate.permission.CRUD;
33 import eu.etaxonomy.taxeditor.model.AbstractUtility;
34 import eu.etaxonomy.taxeditor.model.ImageResources;
35 import eu.etaxonomy.taxeditor.preference.IPreferenceKeys;
36 import eu.etaxonomy.taxeditor.preference.PreferencesUtil;
37 import eu.etaxonomy.taxeditor.preference.Resources;
38 import eu.etaxonomy.taxeditor.store.CdmStore;
39 import eu.etaxonomy.taxeditor.store.LoginManager;
40 import eu.etaxonomy.taxeditor.store.StoreUtil;
41 import eu.etaxonomy.taxeditor.ui.element.AbstractFormSection;
42 import eu.etaxonomy.taxeditor.ui.element.CdmFormFactory;
43 import eu.etaxonomy.taxeditor.ui.element.ICdmFormElement;
44
45 /**
46 * This class visualizes an CDM entity of type ENTITY and additionally provides the functionality to add
47 * other elements of type ELEMENT to them.
48 *
49 * @param <ENTITY> A CDM entity which should be visualized by this section.
50 * @param <ELEMENT> An element that can be added (multiple times) to this entity.
51 *
52 * @author n.hoffmann
53 * @version $Id: $
54 */
55
56 public abstract class AbstractEntityCollectionSection<ENTITY, ELEMENT> extends AbstractFormSection<ENTITY> implements IExpansionListener, Observer {
57
58 /**
59 *
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 /**
70 * <p>Constructor for AbstractEntityCollectionSection.</p>
71 *
72 * @param conversation
73 * @param parentElement a {@link eu.etaxonomy.taxeditor.ui.element.ICdmFormElement} object.
74 * @param style a int.
75 * @param formFactory a {@link eu.etaxonomy.taxeditor.ui.element.CdmFormFactory} object.
76 * @param title a {@link java.lang.String} object.
77 * @param <ENTITY> a ENTITY object.
78 * @param <ELEMENT> a ELEMENT object.
79 */
80 public AbstractEntityCollectionSection(CdmFormFactory formFactory, ConversationHolder conversation, ICdmFormElement parentElement, String title, int style) {
81 super(formFactory, parentElement, ExpandableComposite.CLIENT_INDENT | style);
82 this.title = title;
83 this.setText(getTitleString());
84 updateToolbar();
85
86 addExpansionListener(this);
87
88 CdmStore.getLoginManager().addObserver(this);
89 addDisposeListener(new DisposeListener() {
90 @Override
91 public void widgetDisposed(DisposeEvent e) {
92 CdmStore.getLoginManager().deleteObserver(AbstractEntityCollectionSection.this);
93 }
94 });
95 }
96
97 protected Control createToolbar() {
98 ToolBarManager toolBarManager = new ToolBarManager(SWT.FLAT);
99
100 Action addAction = new Action("add", IAction.AS_PUSH_BUTTON){
101 /* (non-Javadoc)
102 * @see org.eclipse.jface.action.Action#run()
103 */
104 @Override
105 public void run() {
106 ELEMENT element = createNewElement();
107 if(element != null){
108 addElement(element);
109 if(! getSection().isExpanded()) {
110 getSection().setExpanded(true);
111 }
112 internalUpdateSection(true);
113 }
114 }
115 };
116 addAction.setImageDescriptor(new ImageDescriptor() {
117
118 @Override
119 public ImageData getImageData() {
120 return ImageResources.getImage(ImageResources.ADD_ICON).getImageData();
121 }
122 });
123 addAction.setToolTipText(getTooltipString());
124
125 toolBarManager.add(addAction);
126
127 return toolBarManager.createControl(this);
128 }
129
130 /**
131 * using this method is discouraged, use updateToolBar() instead
132 */
133 public void showToolbar(){
134 setTextClient(createToolbar());
135 }
136
137 /**
138 * using this method is discouraged, use updateToolBar() instead
139 */
140 public void removeToolbar(){
141 setTextClient(null);
142 }
143
144 /**
145 * <p>setEntity</p>
146 *
147 * @param entity a ENTITY object.
148 */
149 @Override
150 public void setEntity(ENTITY entity) {
151 if(entity != null){
152 super.setEntity(entity);
153 internalUpdateSection(false);
154 }
155 setSectionTitle();
156 updateToolbar();
157 layout();
158 }
159
160 /**
161 * Sets the title for the section. Adds a "+" sign if the collection is not empty for this section.
162 * Override in subclasses if you want to have a different behaviour.
163 */
164 protected void setSectionTitle() {
165 if(getCollection(getEntity()) != null && getCollection(getEntity()).size() > 0){
166 this.setText(getTitleString() + " +");
167 }else{
168 this.setText(getTitleString());
169 }
170 }
171
172 /**
173 * Removes all content from the container
174 */
175 private void destroyDynamicContent(){
176 if(label_empty != null){
177 label_empty.dispose();
178 label_empty = null;
179 }
180 removeElements();
181 }
182
183 /**
184 * Call this method after dynamically changing the client area.
185 * If the options changed is set to <code>true</code>, will also fire a state changed
186 * event to inform the user of unsaved changes.
187 *
188 * @param changed a boolean.
189 */
190 protected void internalUpdateSection(boolean changed){
191 setSectionTitle();
192 destroyDynamicContent();
193 if(isExpanded() || expandSectionWhenContentAvailable()) {
194 renderContent(isExpanded());
195 }
196 if(changed) {
197 firePropertyChangeEvent(this);
198 }
199 }
200
201 /**
202 * Create the elements to be shown in this section client area
203 */
204 private void renderContent(boolean forceExpansion)
205 {
206 Collection<ELEMENT> elements = getCollection(getEntity());
207
208 if(elements == null || elements.isEmpty()){
209 createEmptyContent();
210 }else{
211 createDynamicContents(elements);
212 forceExpansion = true;
213 }
214
215 this.setExpanded(forceExpansion);
216
217 reflow();
218 }
219
220 /**
221 * <p>createEmptyContent</p>
222 */
223 protected void createEmptyContent(){
224 label_empty = formFactory.createLabel(getLayoutComposite(), getEmptyString());
225 }
226
227 /**
228 * Creates the widgets for the collection
229 *
230 * @param elements a {@link java.util.Collection} object.
231 */
232 protected void createDynamicContents(Collection<ELEMENT> elements)
233 {
234 int i = 0;
235 for(final ELEMENT element : elements){
236 SelectionAdapter removeListener = new SelectionAdapter(){
237 @Override
238 public void widgetSelected(SelectionEvent e) {
239 removeElement(element);
240 internalUpdateSection(true);
241 }
242 };
243 boolean modulo = i++%2 == 0;
244 String colorResource = modulo ? Resources.COLOR_LIST_EVEN : Resources.COLOR_LIST_ODD;
245 createElementComposite(element, removeListener, AbstractUtility.getColor(colorResource));
246 }
247 }
248
249 /**
250 * Create the specific widget for the element
251 *
252 * @param element a ELEMENT object.
253 * @param removeListener a {@link org.eclipse.swt.events.SelectionListener} object.
254 * @param backgroundColor a {@link org.eclipse.swt.graphics.Color} object.
255 */
256 protected void createElementComposite(ELEMENT element, SelectionListener removeListener, Color backgroundColor){
257 formFactory.createEntityCollectionElement(this, element, removeListener, backgroundColor, SWT.NULL);
258 }
259
260 /* (non-Javadoc)
261 * @see eu.etaxonomy.taxeditor.forms.section.AbstractEditorFormSection#setBackground(org.eclipse.swt.graphics.Color)
262 */
263 /** {@inheritDoc} */
264 @Override
265 public void setBackground(Color color) {
266 if(label_empty != null && !label_empty.isDisposed()){
267 label_empty.setBackground(color);
268 }
269 super.setBackground(color);
270 }
271
272 /**
273 * <p>getTitleString</p>
274 *
275 * @return a {@link java.lang.String} object.
276 */
277 public String getTitleString() {
278 return CdmUtils.Nz(title);
279 }
280
281 /**
282 * <p>setTitleString</p>
283 *
284 * @param title a {@link java.lang.String} object.
285 */
286 public void setTitleString(String title){
287 this.title = title;
288 setSectionTitle();
289 layout();
290 }
291
292 /** {@inheritDoc} */
293 @Override
294 public void expansionStateChanging(ExpansionEvent e) {
295 // logger.warn("Expansion State Changing");
296 }
297
298 /** {@inheritDoc} */
299 @Override
300 public void expansionStateChanged(ExpansionEvent e) {
301 if(isExpanded()){
302 renderContent(isExpanded());
303 }else{
304 destroyDynamicContent();
305 }
306 }
307
308 private boolean expandSectionWhenContentAvailable(){
309 return PreferencesUtil.getPreferenceStore().getBoolean(IPreferenceKeys.SHOULD_EXPAND_SECTION_WHEN_DATA_AVAILABLE);
310 }
311
312 /**
313 * Remove an element from the entities collection and update the section
314 *
315 * @param element a ELEMENT object.
316 */
317 public void removeElementAndUpdate(ELEMENT element) {
318 removeElement(element);
319 internalUpdateSection(true);
320 }
321
322 /* (non-Javadoc)
323 * @see java.util.Observer#update(java.util.Observable, java.lang.Object)
324 */
325 @Override
326 public void update(Observable o, Object arg){
327 if(o instanceof LoginManager){
328 updateToolbar();
329 }
330 }
331
332 private void updateToolbar() {
333 if(getEntity() != null && CdmStore.currentAuthentiationHasPermission(StoreUtil.getCdmEntity(getEntity()), UPDATE)){
334 showToolbar();
335 } else {
336 removeToolbar();
337 }
338 }
339
340 /**
341 * Get the specific collection of this entity
342 *
343 * @param entity a ENTITY object.
344 * @return a {@link java.util.Collection} object.
345 */
346 public abstract Collection<ELEMENT> getCollection(ENTITY entity);
347
348 /**
349 * Create a new Element for this collection
350 *
351 * @return a ELEMENT object.
352 */
353 public abstract ELEMENT createNewElement();
354
355 /**
356 * Add an element to the entities collection
357 *
358 * @param element a ELEMENT object.
359 */
360 public abstract void addElement(ELEMENT element);
361
362 /**
363 * Remove an element from the entities collection
364 *
365 * @param element a ELEMENT object.
366 */
367 public abstract void removeElement(ELEMENT element);
368
369 /**
370 * String to display when the collection is empty
371 *
372 * @return a {@link java.lang.String} object.
373 */
374 public abstract String getEmptyString();
375
376 /**
377 * <p>getTooltipString</p>
378 *
379 * @return String to display when hovering the add button
380 */
381 protected abstract String getTooltipString();
382 }