automated build configuration is on its way
[taxeditor.git] / 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
8 import org.apache.commons.collections.CollectionUtils;
9 import org.eclipse.jface.action.Action;
10 import org.eclipse.jface.action.ToolBarManager;
11 import org.eclipse.jface.resource.ImageDescriptor;
12 import org.eclipse.swt.SWT;
13 import org.eclipse.swt.events.SelectionAdapter;
14 import org.eclipse.swt.events.SelectionEvent;
15 import org.eclipse.swt.events.SelectionListener;
16 import org.eclipse.swt.graphics.Color;
17 import org.eclipse.swt.graphics.ImageData;
18 import org.eclipse.swt.widgets.Composite;
19 import org.eclipse.swt.widgets.Control;
20 import org.eclipse.swt.widgets.Label;
21 import org.eclipse.ui.forms.events.ExpansionEvent;
22 import org.eclipse.ui.forms.events.IExpansionListener;
23 import org.eclipse.ui.forms.widgets.Section;
24
25 import eu.etaxonomy.cdm.api.conversation.ConversationHolder;
26 import eu.etaxonomy.cdm.common.CdmUtils;
27 import eu.etaxonomy.cdm.model.common.IVersionableEntity;
28 import eu.etaxonomy.taxeditor.model.ImageResources;
29 import eu.etaxonomy.taxeditor.preference.IPreferenceKeys;
30 import eu.etaxonomy.taxeditor.preference.PreferencesUtil;
31 import eu.etaxonomy.taxeditor.preference.Resources;
32 import eu.etaxonomy.taxeditor.store.StoreUtil;
33 import eu.etaxonomy.taxeditor.ui.forms.AbstractFormSection;
34 import eu.etaxonomy.taxeditor.ui.forms.CdmFormFactory;
35 import eu.etaxonomy.taxeditor.ui.forms.CdmPropertyChangeEvent;
36 import eu.etaxonomy.taxeditor.ui.forms.ICdmFormElement;
37
38 /**
39 * <p>Abstract AbstractEntityCollectionSection class.</p>
40 *
41 * @author n.hoffmann
42 * @version $Id: $
43 */
44 public abstract class AbstractEntityCollectionSection<ENTITY, ELEMENT> extends AbstractFormSection<ENTITY> implements IExpansionListener{
45
46 protected Composite container;
47
48 private Label label_empty;
49
50 private String title;
51
52 /**
53 * <p>Constructor for AbstractEntityCollectionSection.</p>
54 *
55 * @param conversation
56 * @param parentElement a {@link eu.etaxonomy.taxeditor.ui.forms.ICdmFormElement} object.
57 * @param style a int.
58 * @param formFactory a {@link eu.etaxonomy.taxeditor.ui.forms.CdmFormFactory} object.
59 * @param title a {@link java.lang.String} object.
60 * @param <ENTITY> a ENTITY object.
61 * @param <ELEMENT> a ELEMENT object.
62 */
63 public AbstractEntityCollectionSection(CdmFormFactory formFactory, ConversationHolder conversation, ICdmFormElement parentElement, String title, int style) {
64 super(formFactory, conversation, parentElement, Section.CLIENT_INDENT | style);
65 this.title = title;
66 this.setText(getTitleString());
67 setTextClient(createToolbar());
68
69 addExpansionListener(this);
70 }
71
72 private Control createToolbar() {
73 ToolBarManager toolBarManager = new ToolBarManager(SWT.FLAT);
74
75 Action addAction = new Action("add", Action.AS_PUSH_BUTTON){
76 /* (non-Javadoc)
77 * @see org.eclipse.jface.action.Action#run()
78 */
79 @Override
80 public void run() {
81 ELEMENT element = createNewElement();
82 if(element != null){
83 addElement(element);
84 if(! getSection().isExpanded())
85 getSection().setExpanded(true);
86 internalUpdateSection(true);
87 }
88 }
89 };
90 addAction.setImageDescriptor(new ImageDescriptor() {
91
92 @Override
93 public ImageData getImageData() {
94 return ImageResources.getImage(ImageResources.ADD_ICON).getImageData();
95 }
96 });
97 addAction.setToolTipText(getTooltipString());
98
99 toolBarManager.add(addAction);
100
101 return toolBarManager.createControl(this);
102 }
103
104 /**
105 * <p>setEntity</p>
106 *
107 * @param entity a ENTITY object.
108 */
109 public void setEntity(ENTITY entity) {
110 if(entity != null && hasCollectionChanged(entity)){
111 super.setEntity(entity);
112 internalUpdateSection(false);
113 }
114 setSectionTitle();
115 layout();
116 };
117
118 /**
119 * Sets the title for the section. Adds a "+" sign if the collection is not empty for this section.
120 * Override in subclasses if you want to have a different behaviour.
121 */
122 protected void setSectionTitle() {
123 if(getCollection(getEntity()) != null && getCollection(getEntity()).size() > 0){
124 this.setText(getTitleString() + " +");
125 }else{
126 this.setText(getTitleString());
127 }
128 }
129
130 /**
131 * Removes all content from the container
132 */
133 private void destroyDynamicContent(){
134 if(label_empty != null){
135 label_empty.dispose();
136 label_empty = null;
137 }
138 removeElements();
139 }
140
141 /**
142 * Call this method after dynamically changing the client area.
143 * If the options changed is set to true, will also fire a state changed
144 * event to inform the user of unsaved changes.
145 *
146 * @param changed a boolean.
147 */
148 protected void internalUpdateSection(boolean changed){
149 destroyDynamicContent();
150 if(isExpanded() || expandSectionWhenContentAvailable())
151 renderContent(isExpanded());
152 if(changed)
153 firePropertyChangeEvent(new CdmPropertyChangeEvent(this, null));
154 }
155
156 /**
157 * Whether the entities specific collection changed
158 *
159 * @param newEntity
160 * @return
161 */
162 private boolean hasCollectionChanged(ENTITY newEntity){
163
164 // return true on null
165 if(getEntity() == null || newEntity == null) return true;
166
167 // if the entities differ the collection has changed
168 if(! getEntity().equals(newEntity)) return true;
169
170 Collection<ELEMENT> oldCollection = getCollection(getEntity());
171 Collection<ELEMENT> newCollection = getCollection(newEntity);
172
173 // return true on null
174 if(oldCollection == null || newCollection == null) return true;
175
176 // if the collections are object equal, check if the content is equal, too
177 if(oldCollection.equals(newCollection)){
178
179 boolean equal = CollectionUtils.isEqualCollection(oldCollection, newCollection);
180 // return true when collections are not equal
181 return equal ? false : true;
182 }
183 return true;
184 }
185
186 /**
187 * Create the elements to be shown in this seciton client area
188 */
189 private void renderContent(boolean forceExpansion)
190 {
191 Collection<ELEMENT> elements = getCollection(getEntity());
192
193 if(elements == null || elements.size() == 0){
194 createEmptyContent();
195 }else{
196 createDynamicContents(elements);
197 forceExpansion = true;
198 }
199
200 this.setExpanded(forceExpansion);
201
202 reflow();
203 }
204
205 /**
206 * <p>createEmptyContent</p>
207 */
208 protected void createEmptyContent(){
209 label_empty = formFactory.createLabel(getLayoutComposite(), getEmptyString());
210 }
211
212 /**
213 * Creates the widgets for the collection
214 *
215 * @param elements a {@link java.util.Collection} object.
216 */
217 protected void createDynamicContents(Collection<ELEMENT> elements)
218 {
219 int i = 0;
220 for(final ELEMENT element : elements){
221 SelectionAdapter removeListener = new SelectionAdapter(){
222 @Override
223 public void widgetSelected(SelectionEvent e) {
224 removeElement(element);
225 internalUpdateSection(true);
226 }
227 };
228 boolean modulo = i++%2 == 0;
229 String colorResource = modulo ? Resources.COLOR_LIST_EVEN : Resources.COLOR_LIST_ODD;
230 createElementComposite(element, removeListener, StoreUtil.getColor(colorResource));
231 }
232 }
233
234 /**
235 * Create the specific widget for the element
236 *
237 * @param element a ELEMENT object.
238 * @param removeListener a {@link org.eclipse.swt.events.SelectionListener} object.
239 * @param backgroundColor a {@link org.eclipse.swt.graphics.Color} object.
240 */
241 protected void createElementComposite(ELEMENT element, SelectionListener removeListener, Color backgroundColor){
242 AbstractEntityCollectionElement formElement = formFactory.createEntityCollectionElement(this, element, removeListener, backgroundColor, SWT.NULL);
243 }
244
245 /* (non-Javadoc)
246 * @see eu.etaxonomy.taxeditor.forms.section.AbstractEditorFormSection#setBackground(org.eclipse.swt.graphics.Color)
247 */
248 /** {@inheritDoc} */
249 @Override
250 public void setBackground(Color color) {
251 if(label_empty != null && !label_empty.isDisposed()){
252 label_empty.setBackground(color);
253 }
254 super.setBackground(color);
255 }
256
257 /**
258 * <p>getTitleString</p>
259 *
260 * @return a {@link java.lang.String} object.
261 */
262 public String getTitleString() {
263 return CdmUtils.Nz(title);
264 }
265
266 /**
267 * <p>setTitleString</p>
268 *
269 * @param title a {@link java.lang.String} object.
270 */
271 public void setTitleString(String title){
272 this.title = title;
273 }
274
275 /** {@inheritDoc} */
276 public void expansionStateChanging(ExpansionEvent e) {
277 // logger.warn("Expansion State Changing");
278 }
279
280 /** {@inheritDoc} */
281 public void expansionStateChanged(ExpansionEvent e) {
282 if(isExpanded()){
283 renderContent(isExpanded());
284 }else{
285 destroyDynamicContent();
286 }
287 }
288
289 private boolean expandSectionWhenContentAvailable(){
290 return PreferencesUtil.getPreferenceStore().getBoolean(IPreferenceKeys.SHOULD_EXPAND_SECTION_WHEN_DATA_AVAILABLE);
291 }
292
293 /**
294 * Get the specific collection of this entity
295 *
296 * @param entity a ENTITY object.
297 * @return a {@link java.util.Collection} object.
298 */
299 public abstract Collection<ELEMENT> getCollection(ENTITY entity);
300
301 /**
302 * Create a new Element for this collection
303 *
304 * @return a ELEMENT object.
305 */
306 public abstract ELEMENT createNewElement();
307
308 /**
309 * Add an element to the entities collection
310 *
311 * @param element a ELEMENT object.
312 */
313 public abstract void addElement(ELEMENT element);
314
315 /**
316 * Remove an element from the entities collection
317 *
318 * @param element a ELEMENT object.
319 */
320 public abstract void removeElement(ELEMENT element);
321
322 /**
323 * String to display when the collection is empty
324 *
325 * @return a {@link java.lang.String} object.
326 */
327 public abstract String getEmptyString();
328
329 /**
330 * <p>getTooltipString</p>
331 *
332 * @return String to display when hovering the add button
333 */
334 protected abstract String getTooltipString();
335 }