92cd0bf2d94cfe0eaa54e1bc53b206775edf8266
[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 true, 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 destroyDynamicContent();
192 if(isExpanded() || expandSectionWhenContentAvailable()) {
193 renderContent(isExpanded());
194 }
195 if(changed) {
196 firePropertyChangeEvent(this);
197 }
198 }
199
200 /**
201 * Create the elements to be shown in this section client area
202 */
203 private void renderContent(boolean forceExpansion)
204 {
205 Collection<ELEMENT> elements = getCollection(getEntity());
206
207 if(elements == null || elements.isEmpty()){
208 createEmptyContent();
209 }else{
210 createDynamicContents(elements);
211 forceExpansion = true;
212 }
213
214 this.setExpanded(forceExpansion);
215
216 reflow();
217 }
218
219 /**
220 * <p>createEmptyContent</p>
221 */
222 protected void createEmptyContent(){
223 label_empty = formFactory.createLabel(getLayoutComposite(), getEmptyString());
224 }
225
226 /**
227 * Creates the widgets for the collection
228 *
229 * @param elements a {@link java.util.Collection} object.
230 */
231 protected void createDynamicContents(Collection<ELEMENT> elements)
232 {
233 int i = 0;
234 for(final ELEMENT element : elements){
235 SelectionAdapter removeListener = new SelectionAdapter(){
236 @Override
237 public void widgetSelected(SelectionEvent e) {
238 removeElement(element);
239 internalUpdateSection(true);
240 }
241 };
242 boolean modulo = i++%2 == 0;
243 String colorResource = modulo ? Resources.COLOR_LIST_EVEN : Resources.COLOR_LIST_ODD;
244 createElementComposite(element, removeListener, AbstractUtility.getColor(colorResource));
245 }
246 }
247
248 /**
249 * Create the specific widget for the element
250 *
251 * @param element a ELEMENT object.
252 * @param removeListener a {@link org.eclipse.swt.events.SelectionListener} object.
253 * @param backgroundColor a {@link org.eclipse.swt.graphics.Color} object.
254 */
255 protected void createElementComposite(ELEMENT element, SelectionListener removeListener, Color backgroundColor){
256 formFactory.createEntityCollectionElement(this, element, removeListener, backgroundColor, SWT.NULL);
257 }
258
259 /* (non-Javadoc)
260 * @see eu.etaxonomy.taxeditor.forms.section.AbstractEditorFormSection#setBackground(org.eclipse.swt.graphics.Color)
261 */
262 /** {@inheritDoc} */
263 @Override
264 public void setBackground(Color color) {
265 if(label_empty != null && !label_empty.isDisposed()){
266 label_empty.setBackground(color);
267 }
268 super.setBackground(color);
269 }
270
271 /**
272 * <p>getTitleString</p>
273 *
274 * @return a {@link java.lang.String} object.
275 */
276 public String getTitleString() {
277 return CdmUtils.Nz(title);
278 }
279
280 /**
281 * <p>setTitleString</p>
282 *
283 * @param title a {@link java.lang.String} object.
284 */
285 public void setTitleString(String title){
286 this.title = title;
287 setSectionTitle();
288 layout();
289 }
290
291 /** {@inheritDoc} */
292 @Override
293 public void expansionStateChanging(ExpansionEvent e) {
294 // logger.warn("Expansion State Changing");
295 }
296
297 /** {@inheritDoc} */
298 @Override
299 public void expansionStateChanged(ExpansionEvent e) {
300 if(isExpanded()){
301 renderContent(isExpanded());
302 }else{
303 destroyDynamicContent();
304 }
305 }
306
307 private boolean expandSectionWhenContentAvailable(){
308 return PreferencesUtil.getPreferenceStore().getBoolean(IPreferenceKeys.SHOULD_EXPAND_SECTION_WHEN_DATA_AVAILABLE);
309 }
310
311 /**
312 * Remove an element from the entities collection and update the section
313 *
314 * @param element a ELEMENT object.
315 */
316 public void removeElementAndUpdate(ELEMENT element) {
317 removeElement(element);
318 internalUpdateSection(true);
319 }
320
321 /* (non-Javadoc)
322 * @see java.util.Observer#update(java.util.Observable, java.lang.Object)
323 */
324 @Override
325 public void update(Observable o, Object arg){
326 if(o instanceof LoginManager){
327 updateToolbar();
328 }
329 }
330
331 private void updateToolbar() {
332 if(getEntity() != null && CdmStore.currentAuthentiationHasPermission(StoreUtil.getCdmEntity(getEntity()), UPDATE)){
333 showToolbar();
334 } else {
335 removeToolbar();
336 }
337 }
338
339 /**
340 * Get the specific collection of this entity
341 *
342 * @param entity a ENTITY object.
343 * @return a {@link java.util.Collection} object.
344 */
345 public abstract Collection<ELEMENT> getCollection(ENTITY entity);
346
347 /**
348 * Create a new Element for this collection
349 *
350 * @return a ELEMENT object.
351 */
352 public abstract ELEMENT createNewElement();
353
354 /**
355 * Add an element to the entities collection
356 *
357 * @param element a ELEMENT object.
358 */
359 public abstract void addElement(ELEMENT element);
360
361 /**
362 * Remove an element from the entities collection
363 *
364 * @param element a ELEMENT object.
365 */
366 public abstract void removeElement(ELEMENT element);
367
368 /**
369 * String to display when the collection is empty
370 *
371 * @return a {@link java.lang.String} object.
372 */
373 public abstract String getEmptyString();
374
375 /**
376 * <p>getTooltipString</p>
377 *
378 * @return String to display when hovering the add button
379 */
380 protected abstract String getTooltipString();
381 }