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