ref #6913 Remove workbench and selection handling from edit/new wizards
[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 private static final EnumSet<CRUD> UPDATE = EnumSet.of(CRUD.UPDATE);
59
60 protected Composite container;
61
62 private Label label_empty;
63
64 private String title;
65
66 private AbstractEntityCollectionElement entityCollectionElement;
67
68 public AbstractEntityCollectionSection(CdmFormFactory formFactory, ConversationHolder conversation, ICdmFormElement parentElement, String title, int style) {
69 super(formFactory, parentElement, ExpandableComposite.CLIENT_INDENT | style);
70 this.title = title;
71 this.setText(getTitleString());
72 updateToolbar();
73
74 addExpansionListener(this);
75
76 CdmStore.getLoginManager().addObserver(this);
77 addDisposeListener(new DisposeListener() {
78 @Override
79 public void widgetDisposed(DisposeEvent e) {
80 CdmStore.getLoginManager().deleteObserver(AbstractEntityCollectionSection.this);
81 }
82 });
83 }
84
85 protected Control createToolbar() {
86 ToolBarManager toolBarManager = new ToolBarManager(SWT.FLAT);
87
88 Action addAction = new Action("Add", IAction.AS_PUSH_BUTTON){
89 @Override
90 public void run() {
91 ELEMENT element = createNewElement();
92 if(element != null){
93 addElement(element);
94 if(! getSection().isExpanded()) {
95 getSection().setExpanded(true);
96 }
97 internalUpdateSection(true);
98 }
99 }
100 };
101 addAction.setImageDescriptor(new ImageDescriptor() {
102
103 @Override
104 public ImageData getImageData() {
105 return ImageResources.getImage(ImageResources.ADD_ICON).getImageData();
106 }
107 });
108 addAction.setToolTipText(getTooltipString());
109
110 Action browseAction = null;
111 if(allowAddExisting()){
112 browseAction = new Action("Browse", IAction.AS_PUSH_BUTTON){
113 @Override
114 public void run() {
115 ELEMENT element = addExisting();
116 if(element != null){
117 addElement(element);
118 if(! getSection().isExpanded()) {
119 getSection().setExpanded(true);
120 }
121 internalUpdateSection(true);
122 }
123 }
124 };
125 browseAction.setImageDescriptor(new ImageDescriptor() {
126
127 @Override
128 public ImageData getImageData() {
129 return ImageResources.getImage(ImageResources.BROWSE_ICON).getImageData();
130 }
131 });
132 browseAction.setToolTipText("Browse");
133 }
134
135 toolBarManager.add(addAction);
136 if(browseAction!=null){
137 toolBarManager.add(browseAction);
138 }
139
140 return toolBarManager.createControl(this);
141 }
142
143 /**
144 * using this method is discouraged, use updateToolBar() instead
145 */
146 public void showToolbar(){
147 setTextClient(createToolbar());
148 }
149
150 /**
151 * using this method is discouraged, use updateToolBar() instead
152 */
153 public void removeToolbar(){
154 setTextClient(null);
155 }
156
157 @Override
158 public void setEntity(ENTITY entity) {
159 if(entity != null){
160 super.setEntity(entity);
161 internalUpdateSection(false);
162 }
163 setSectionTitle();
164 updateToolbar();
165 layout();
166 }
167
168 /**
169 * Sets the title for the section. Adds a "+" sign if the collection is not empty for this section.
170 * Override in subclasses if you want to have a different behaviour.
171 */
172 protected void setSectionTitle() {
173 Collection<ELEMENT> collection = getCollection(getEntity());
174 if(collection != null && collection.size() > 0){
175 this.setText(getTitleString() + " +");
176 }else{
177 this.setText(getTitleString());
178 }
179 }
180
181 /**
182 * Removes all content from the container
183 */
184 private void destroyDynamicContent(){
185 if(label_empty != null){
186 label_empty.dispose();
187 label_empty = null;
188 }
189 removeElements();
190 }
191
192 /**
193 * Call this method after dynamically changing the client area.
194 * If the options changed is set to <code>true</code>, will also fire a state changed
195 * event to inform the user of unsaved changes.
196 *
197 * @param changed a boolean.
198 */
199 protected void internalUpdateSection(boolean changed){
200 setSectionTitle();
201 destroyDynamicContent();
202 if(isExpanded() || expandSectionWhenContentAvailable()) {
203 renderContent(isExpanded());
204 }
205 if(changed) {
206 firePropertyChangeEvent(this);
207 }
208 }
209
210 /**
211 * Create the elements to be shown in this section client area
212 */
213 private void renderContent(boolean forceExpansion)
214 {
215 Collection<ELEMENT> elements = getCollection(getEntity());
216
217 if(elements == null || elements.isEmpty()){
218 createEmptyContent();
219 }else{
220 createDynamicContents(elements);
221 forceExpansion = true;
222 }
223
224 this.setExpanded(forceExpansion);
225
226 reflow();
227 }
228
229 protected void createEmptyContent(){
230 label_empty = formFactory.createLabel(getLayoutComposite(), getEmptyString());
231 }
232
233 /**
234 * Creates the widgets for the collection
235 *
236 * @param elements a {@link java.util.Collection} object.
237 */
238 protected void createDynamicContents(Collection<ELEMENT> elements)
239 {
240 int i = 0;
241 for(final ELEMENT element : elements){
242 SelectionAdapter removeListener = new SelectionAdapter(){
243 @Override
244 public void widgetSelected(SelectionEvent e) {
245 removeElement(element);
246 internalUpdateSection(true);
247 }
248 };
249 boolean modulo = i++%2 == 0;
250 String colorResource = modulo ? Resources.COLOR_LIST_EVEN : Resources.COLOR_LIST_ODD;
251 createElementComposite(element, removeListener, AbstractUtility.getColor(colorResource));
252 }
253 }
254
255 /**
256 * Create the specific widget for the element
257 *
258 * @param element a ELEMENT object.
259 * @param removeListener a {@link org.eclipse.swt.events.SelectionListener} object.
260 * @param backgroundColor a {@link org.eclipse.swt.graphics.Color} object.
261 */
262 protected void createElementComposite(ELEMENT element, SelectionListener removeListener, Color backgroundColor){
263 entityCollectionElement = formFactory.createEntityCollectionElement(this, element, removeListener, backgroundColor, SWT.NULL);
264 }
265
266 /** {@inheritDoc} */
267 @Override
268 public void setBackground(Color color) {
269 if(label_empty != null && !label_empty.isDisposed()){
270 label_empty.setBackground(color);
271 }
272 super.setBackground(color);
273 }
274
275 /**
276 * <p>getTitleString</p>
277 *
278 * @return a {@link java.lang.String} object.
279 */
280 public String getTitleString() {
281 return CdmUtils.Nz(title);
282 }
283
284 /**
285 * <p>setTitleString</p>
286 *
287 * @param title a {@link java.lang.String} object.
288 */
289 public void setTitleString(String title){
290 this.title = title;
291 setSectionTitle();
292 layout();
293 }
294
295 /** {@inheritDoc} */
296 @Override
297 public void expansionStateChanging(ExpansionEvent e) {
298 // logger.warn("Expansion State Changing");
299 }
300
301 /** {@inheritDoc} */
302 @Override
303 public void expansionStateChanged(ExpansionEvent e) {
304 if(isExpanded()){
305 renderContent(isExpanded());
306 }else{
307 destroyDynamicContent();
308 }
309 }
310
311 private boolean expandSectionWhenContentAvailable(){
312 return PreferencesUtil.getPreferenceStore().getBoolean(IPreferenceKeys.SHOULD_EXPAND_SECTION_WHEN_DATA_AVAILABLE);
313 }
314
315 /**
316 * Remove an element from the entities collection and update the section
317 *
318 * @param element a ELEMENT object.
319 */
320 public void removeElementAndUpdate(ELEMENT element) {
321 removeElement(element);
322 internalUpdateSection(true);
323 }
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 public AbstractEntityCollectionElement getEntityCollectionElement() {
341 return entityCollectionElement;
342 }
343
344
345 /**
346 * Get the specific collection of this entity
347 *
348 * @param entity a ENTITY object.
349 * @return a {@link java.util.Collection} object.
350 */
351 public abstract Collection<ELEMENT> getCollection(ENTITY entity);
352
353 /**
354 * Create a new Element for this collection
355 *
356 * @return a ELEMENT object.
357 */
358 public abstract ELEMENT createNewElement();
359
360 /**
361 * Add an element to the entities collection
362 *
363 * @param element a ELEMENT object.
364 */
365 public abstract void addElement(ELEMENT element);
366
367 /**
368 * Add an existing element to the entities collection.
369 * @return the existing element
370 */
371 public abstract ELEMENT addExisting();
372
373 /**
374 * If <code>true</code> the section will also display
375 * a browse icon to choose from existing elements.
376 * <br>
377 * <b>Note:</b> when returning true you have to make sure
378 * to implement the {@link #addExisting()} method
379 * @return true if existing entities can be added;
380 * false otherwise
381 */
382 public abstract boolean allowAddExisting();
383
384 /**
385 * Remove an element from the entities collection
386 *
387 * @param element a ELEMENT object.
388 */
389 public abstract void removeElement(ELEMENT element);
390
391 /**
392 * String to display when the collection is empty
393 *
394 * @return a {@link java.lang.String} object.
395 */
396 public abstract String getEmptyString();
397
398 /**
399 * <p>getTooltipString</p>
400 *
401 * @return String to display when hovering the add button
402 */
403 protected abstract String getTooltipString();
404 }