223d68d3a21530a85636fa7f04601c818d09423e
[taxeditor.git] / eu.etaxonomy.taxeditor.store / src / main / java / eu / etaxonomy / taxeditor / ui / selection / EntitySelectionElement.java
1 /**
2 *
3 */
4 package eu.etaxonomy.taxeditor.ui.selection;
5
6 import java.util.EnumSet;
7 import java.util.Observable;
8 import java.util.Observer;
9
10 import org.eclipse.core.runtime.IStatus;
11 import org.eclipse.core.runtime.NullProgressMonitor;
12 import org.eclipse.jface.wizard.WizardDialog;
13 import org.eclipse.swt.SWT;
14 import org.eclipse.swt.events.SelectionAdapter;
15 import org.eclipse.swt.events.SelectionEvent;
16 import org.eclipse.swt.events.SelectionListener;
17 import org.eclipse.swt.graphics.Color;
18 import org.eclipse.swt.widgets.Button;
19 import org.eclipse.swt.widgets.Composite;
20 import org.eclipse.swt.widgets.Label;
21 import org.eclipse.swt.widgets.Shell;
22 import org.eclipse.swt.widgets.Text;
23 import org.springframework.security.core.GrantedAuthority;
24
25 import eu.etaxonomy.cdm.api.conversation.ConversationHolder;
26 import eu.etaxonomy.cdm.api.conversation.IConversationEnabled;
27 import eu.etaxonomy.cdm.api.service.IAgentService;
28 import eu.etaxonomy.cdm.api.service.ICollectionService;
29 import eu.etaxonomy.cdm.api.service.INameService;
30 import eu.etaxonomy.cdm.api.service.IOccurrenceService;
31 import eu.etaxonomy.cdm.api.service.IReferenceService;
32 import eu.etaxonomy.cdm.api.service.IService;
33 import eu.etaxonomy.cdm.api.service.IUserService;
34 import eu.etaxonomy.cdm.api.service.molecular.IAmplificationService;
35 import eu.etaxonomy.cdm.api.service.molecular.IPrimerService;
36 import eu.etaxonomy.cdm.common.CdmUtils;
37 import eu.etaxonomy.cdm.model.agent.Institution;
38 import eu.etaxonomy.cdm.model.agent.Person;
39 import eu.etaxonomy.cdm.model.agent.Team;
40 import eu.etaxonomy.cdm.model.common.CdmBase;
41 import eu.etaxonomy.cdm.model.common.Group;
42 import eu.etaxonomy.cdm.model.common.ICdmBase;
43 import eu.etaxonomy.cdm.model.common.IIdentifiableEntity;
44 import eu.etaxonomy.cdm.model.common.User;
45 import eu.etaxonomy.cdm.model.molecular.Amplification;
46 import eu.etaxonomy.cdm.model.molecular.Primer;
47 import eu.etaxonomy.cdm.model.name.NonViralName;
48 import eu.etaxonomy.cdm.model.occurrence.Collection;
49 import eu.etaxonomy.cdm.model.occurrence.SpecimenOrObservationBase;
50 import eu.etaxonomy.cdm.model.reference.Reference;
51 import eu.etaxonomy.cdm.persistence.hibernate.CdmDataChangeMap;
52 import eu.etaxonomy.cdm.persistence.hibernate.permission.CRUD;
53 import eu.etaxonomy.taxeditor.model.AbstractUtility;
54 import eu.etaxonomy.taxeditor.model.ImageResources;
55 import eu.etaxonomy.taxeditor.model.MessagingUtils;
56 import eu.etaxonomy.taxeditor.preference.Resources;
57 import eu.etaxonomy.taxeditor.store.CdmStore;
58 import eu.etaxonomy.taxeditor.store.LoginManager;
59 import eu.etaxonomy.taxeditor.store.StoreUtil;
60 import eu.etaxonomy.taxeditor.ui.dialog.selection.SelectionDialogFactory;
61 import eu.etaxonomy.taxeditor.ui.element.AbstractCdmFormElement;
62 import eu.etaxonomy.taxeditor.ui.element.CdmFormFactory;
63 import eu.etaxonomy.taxeditor.ui.element.CdmPropertyChangeEvent;
64 import eu.etaxonomy.taxeditor.ui.element.ICdmFormElement;
65 import eu.etaxonomy.taxeditor.ui.element.IEnableableFormElement;
66 import eu.etaxonomy.taxeditor.ui.element.IEntityElement;
67 import eu.etaxonomy.taxeditor.ui.element.ILabeledElement;
68 import eu.etaxonomy.taxeditor.ui.element.ISelectableElement;
69 import eu.etaxonomy.taxeditor.ui.element.LayoutConstants;
70 import eu.etaxonomy.taxeditor.ui.element.SelectionArbitrator;
71 import eu.etaxonomy.taxeditor.ui.section.grantedAuthority.GrantedAuthorityLabelTextProvider;
72
73 /**
74 * <p>
75 * Abstract AbstractSelectionElement class.
76 * </p>
77 *
78 * @author n.hoffmann
79 * @created Nov 17, 2009
80 * @version 1.0
81 * @param <T>
82 */
83 public class EntitySelectionElement<T extends ICdmBase> extends
84 AbstractCdmFormElement implements SelectionListener, IEnableableFormElement, ISelectableElement, IEntityElement<T>, ILabeledElement, IConversationEnabled, Observer {
85
86 private static final EnumSet<CRUD> UPDATE = EnumSet.of(CRUD.UPDATE);
87 private static final EnumSet<CRUD> DELETE = EnumSet.of(CRUD.DELETE);
88 private static final EnumSet<CRUD> CREATE = EnumSet.of(CRUD.CREATE);
89
90 /**
91 * Bitmask for configuring functionality of selection element
92 */
93 public static final int NOTHING = 0; // 000
94 public static final int EDITABLE = 1 << 0; // 001
95 public static final int DELETABLE = 1 << 1; // 010
96 public static final int SELECTABLE = 1 << 2; // 100
97 public static final int ALL = EDITABLE | DELETABLE | SELECTABLE; // 111
98
99 protected T entity;
100
101 protected Label label;
102 protected Text text;
103 protected Button button_selection;
104
105 private SelectionArbitrator selectionArbitrator;
106
107 protected Button button_edit;
108
109 private final String labelString;
110
111 private Composite selectableComposite;
112
113 private Button button_remove;
114
115 private final boolean isEditable;
116
117 private final boolean isDeletable;
118
119 private final ConversationHolder conversation;
120 private Class<T> clazz;
121
122 /**
123 * <p>
124 * Constructor for AbstractSelectionElement.
125 * </p>
126 *
127 * @param formFactory
128 * a {@link eu.etaxonomy.taxeditor.ui.element.CdmFormFactory}
129 * object.
130 * @param conversation
131 * TODO
132 * @param parentElement
133 * a {@link eu.etaxonomy.taxeditor.ui.element.ICdmFormElement}
134 * object.
135 * @param labelString
136 * a {@link java.lang.String} object.
137 * @param entity
138 * a T object.
139 * @param isEditable
140 * a boolean.
141 * @param isSelectable
142 * a boolean.
143 * @param isDeletable
144 * a boolean.
145 * @param style
146 * a int.
147 * @param <T>
148 * a T object.
149 */
150 public EntitySelectionElement(CdmFormFactory formFactory,
151 ConversationHolder conversation, ICdmFormElement parentElement,
152 String labelString, T entity, int mode, int style) {
153 super(formFactory, parentElement);
154
155 this.isEditable = (mode & EDITABLE) == EDITABLE;
156 this.isDeletable = (mode & DELETABLE) == DELETABLE;
157 boolean isSelectable = (mode & SELECTABLE) == SELECTABLE;
158
159 this.labelString = (labelString == null || labelString.equals("")) ? "" : labelString + " : ";
160
161 this.conversation = conversation;
162
163 if (isSelectable && formFactory.getSelectionProvider() != null) {
164 selectionArbitrator = formFactory.createSelectionArbitrator(this);
165 }
166
167 createControls(getLayoutComposite(), SWT.NULL);
168
169 setEntity(entity);
170 }
171
172 public EntitySelectionElement(CdmFormFactory formFactory,
173 ConversationHolder conversation, ICdmFormElement parentElement, Class<T> clazz,
174 String labelString, T entity, int mode, int style) {
175 this(formFactory, conversation, parentElement, labelString, entity, mode, style);
176 this.clazz = clazz;
177 }
178
179 private void createControls(Composite parent, int style) {
180
181 label = formFactory.createLabel(getLayoutComposite(), labelString,
182 SWT.NULL);
183
184 addControl(label);
185
186 selectableComposite = formFactory.createComposite(getLayoutComposite());
187
188 int columns = 2;
189 if (isEditable) {
190 columns += 1;
191 }
192 if (isDeletable) {
193 columns += 1;
194 }
195
196 selectableComposite.setLayout(LayoutConstants.LAYOUT(columns, false));
197 selectableComposite.setLayoutData(LayoutConstants.FILL_HORIZONTALLY());
198
199 addControl(selectableComposite);
200
201 text = formFactory.createText(selectableComposite, null, SWT.WRAP);
202 text.setEditable(false);
203 addControl(text);
204
205 text.setLayoutData(LayoutConstants.FILL_HORIZONTALLY());
206 text.setBackground(StoreUtil
207 .getColor(Resources.COLOR_TEXT_DISABLED_BACKGROUND));
208
209 button_selection = formFactory.createButton(selectableComposite, null,
210 SWT.PUSH);
211 button_selection.setImage(ImageResources
212 .getImage(ImageResources.BROWSE_ICON));
213 button_selection.setToolTipText("Browse existing");
214
215 addControl(button_selection);
216 button_selection.addSelectionListener(this);
217
218 if (isEditable) {
219 button_edit = formFactory.createButton(selectableComposite, null,
220 SWT.PUSH);
221 button_edit.setImage(ImageResources
222 .getImage(ImageResources.EDIT_ICON));
223 button_edit.setToolTipText("Edit");
224 addControl(button_edit);
225 button_edit.addSelectionListener(new EditListener(this));
226 }
227
228 if (isDeletable) {
229 button_remove = formFactory.createButton(selectableComposite, null,
230 SWT.PUSH);
231 button_remove.setImage(ImageResources
232 .getImage(ImageResources.TRASH_ICON));
233 button_remove.setToolTipText("Remove");
234 addControl(button_remove);
235 button_remove.addSelectionListener(new DeleteListener(this));
236 }
237 }
238
239 @Override
240 public void widgetSelected(SelectionEvent e) {
241 T selection = SelectionDialogFactory.getSelectionFromDialog(clazz, getShell(), getConversationHolder(), getEntity(), getParentElement());
242 setSelectionInternal(selection);
243 }
244
245 /**
246 * Return the selected object
247 *
248 * @return a T object.
249 */
250 public T getSelection() {
251 return entity;
252 }
253
254 /*
255 * (non-Javadoc)
256 *
257 * @see
258 * eu.etaxonomy.taxeditor.forms.IEnableableFormElement#setEnabled(boolean)
259 */
260 /** {@inheritDoc} */
261 @Override
262 public void setEnabled(boolean enabled) {
263 button_selection.setEnabled(enabled);
264 button_remove.setEnabled(enabled);
265 if (isEditable) {
266 updateButtonStates();
267 }
268 }
269
270 /* (non-Javadoc)
271 * @see eu.etaxonomy.taxeditor.ui.element.IEnableableFormElement#isEnabled()
272 */
273 @Override
274 public boolean isEnabled() {
275 return button_selection.isEnabled();
276 }
277
278 /**
279 * <p>
280 * setSelectionInternal
281 * </p>
282 *
283 * @param selection
284 * a T object.
285 */
286 protected void setSelectionInternal(T selection) {
287 if (selection != null && !selection.equals(this.entity)) {
288 setEntity(selection);
289 firePropertyChangeEvent(new CdmPropertyChangeEvent(this, null));
290 }
291 }
292
293 /**
294 * <p>
295 * Setter for the field <code>entity</code>.
296 * </p>
297 *
298 * @param selection
299 * a T object.
300 */
301 public void setEntity(T selection) {
302 this.entity = selection;
303 updateElement();
304 }
305
306 /**
307 * Updates this elements view
308 */
309 protected void updateElement() {
310 String title = CdmUtils.Nz(getTitle());
311 text.setText(title); // title can be null
312 if (isEditable) {
313 updateButtonStates();
314 }
315 }
316
317 public void updateFromWizard() {
318 updateElement();
319 firePropertyChangeEvent(new CdmPropertyChangeEvent(this, null));
320 }
321
322 /**
323 * <p>
324 * getTitle
325 * </p>
326 *
327 * @return a {@link java.lang.String} object.
328 */
329 protected String getTitle() {
330 if (entity != null){
331 if(entity instanceof IIdentifiableEntity) {
332 return ((IIdentifiableEntity) entity).getTitleCache();
333 } else if(entity instanceof Group){
334 return ((Group) entity).getName();
335 } else if(entity instanceof GrantedAuthority){
336 return GrantedAuthorityLabelTextProvider.getText(((GrantedAuthority) entity));
337 } else if(entity instanceof User){
338 return ((User) entity).getUsername();
339 } else if (entity instanceof Primer){
340 return ((Primer) entity).getLabel();
341 } else if (entity instanceof Amplification){
342 return ((Amplification) entity).getLabelCache();
343 }
344
345 }
346 return "";
347 }
348
349 /** {@inheritDoc} */
350 @Override
351 public void setSelected(boolean selected) {
352 setBackground(selected ? SELECTED : getPersistentBackground());
353 }
354
355 /*
356 * (non-Javadoc)
357 *
358 * @see eu.etaxonomy.taxeditor.forms.IEntityElement#getEntity()
359 */
360 /**
361 * <p>
362 * Getter for the field <code>entity</code>.
363 * </p>
364 *
365 * @return a T object.
366 */
367 @Override
368 public T getEntity() {
369 return entity;
370 }
371
372 /*
373 * (non-Javadoc)
374 *
375 * @see eu.etaxonomy.taxeditor.forms.section.cdmdetail.ISelectableElement#
376 * getSelectionArbitrator()
377 */
378 /**
379 * <p>
380 * Getter for the field <code>selectionArbitrator</code>.
381 * </p>
382 *
383 * @return a {@link eu.etaxonomy.taxeditor.ui.element.SelectionArbitrator}
384 * object.
385 */
386 @Override
387 public SelectionArbitrator getSelectionArbitrator() {
388 return selectionArbitrator;
389 }
390
391 /**
392 * Convenient access to current shell
393 *
394 * @return a {@link org.eclipse.swt.widgets.Shell} object.
395 */
396 public Shell getShell() {
397 return getLayoutComposite().getShell();
398 }
399
400 /** {@inheritDoc} */
401 @Override
402 public void setIrrelevant(boolean irrelevant) {
403 String colorId = irrelevant ? Resources.COLOR_COMPOSITE_IRRELEVANT
404 : Resources.COLOR_TEXT_DISABLED_BACKGROUND;
405
406 Color color = StoreUtil.getColor(colorId);
407 text.setBackground(color);
408 }
409
410 private class DeleteListener extends SelectionAdapter {
411
412 private final EntitySelectionElement<T> selectionElement;
413
414 public DeleteListener(EntitySelectionElement<T> selectionElement) {
415 this.selectionElement = selectionElement;
416 }
417
418 @Override
419 public void widgetSelected(SelectionEvent e) {
420 setEntity(null);
421 firePropertyChangeEvent(new CdmPropertyChangeEvent(
422 selectionElement, null));
423 }
424 }
425
426 private class EditListener extends SelectionAdapter {
427
428 private static final String TRANSIENT_EDITING_WARNING_TEXT = "Warning: All changes for this element are directly reflected in the data base.\nThe \"Cancel\" button has no effect";
429 private static final String TRANSIENT_EDITING_WARNING_TITLE = "CDM element not yet saved.";
430 private final EntitySelectionElement<T> selectionElement;
431
432 public EditListener(EntitySelectionElement<T> selectionElement) {
433 this.selectionElement = selectionElement;
434 }
435
436 /** {@inheritDoc} */
437 @Override
438 public void widgetSelected(SelectionEvent e) {
439 T originalEntity = selectionElement.getEntity();
440 T clonedEntity = null;
441 IService<T> service = null;
442 if(originalEntity instanceof CdmBase){
443 //get corresponding service
444 if(entity instanceof Reference<?>){
445 service = (IService<T>) CdmStore.getService(IReferenceService.class);
446 }
447 else if (entity instanceof Team || entity instanceof Person || entity instanceof Institution) {
448 service = (IService<T>) CdmStore.getService(IAgentService.class);
449 }
450 else if (entity instanceof NonViralName) {
451 service = (IService<T>) CdmStore.getService(INameService.class);
452 }
453 else if (entity instanceof SpecimenOrObservationBase) {
454 service = (IService<T>) CdmStore.getService(IOccurrenceService.class);
455 }
456 else if (entity instanceof Collection) {
457 service = (IService<T>) CdmStore.getService(ICollectionService.class);
458 }
459 else if (entity instanceof User) {
460 service = (IService<T>) CdmStore.getService(IUserService.class);
461 }
462 else if (entity instanceof Primer) {
463 service = (IService<T>) CdmStore.getService(IPrimerService.class);
464 }
465 else if (entity instanceof Amplification) {
466 service = (IService<T>) CdmStore.getService(IAmplificationService.class);
467 }
468 //check if original already exists in data base. If not then do not clone and all changes will be persisted directly -> Warning to user.
469 if(service !=null && service.find(originalEntity.getUuid())==null && originalEntity.getId() != 0){
470 if(MessagingUtils.confirmDialog(TRANSIENT_EDITING_WARNING_TITLE, "["+originalEntity.getClass().getSimpleName()+"]"+originalEntity + " has to be saved before it can be edited. Save now?")){
471 service.save(originalEntity);
472 AbstractUtility.getActiveEditor().doSave(new NullProgressMonitor());
473 }
474 else{
475 //transient CDM elements should not be edited to avoid merge conflicts
476 // when the elements are cascaded
477 return;
478 }
479 }
480 else{
481 //FIXME temporarily disabled cloning re-opening bug #2645 (EditFromSelectionWizard persists data even when canceled)
482 // try {
483 // //clone original
484 // clonedEntity = (T) ((CdmBase) originalEntity).clone();
485 // } catch (CloneNotSupportedException e1) {
486 // MessagingUtils.warningDialog(TRANSIENT_EDITING_WARNING_TITLE, this, TRANSIENT_EDITING_WARNING_TEXT);
487 // }
488 }
489
490 }
491 if(clonedEntity!=null){
492 selectionElement.setEntity(clonedEntity);
493 }
494 WizardDialog dialog = new WizardDialog(selectionElement.getShell(),
495 new EditFromSelectionWizard(selectionElement));
496 if (dialog.open() == IStatus.OK) {
497 if(service!=null && clonedEntity!=null){//check if cloning happened
498 T editedClonedEntity = selectionElement.getEntity();
499 editedClonedEntity.setId(originalEntity.getId());
500 editedClonedEntity.setUuid(originalEntity.getUuid());
501
502 //merge clone and original
503 service.merge(editedClonedEntity);
504 originalEntity = service.load(originalEntity.getUuid());
505
506 }
507 selectionElement.setEntity(originalEntity);
508 selectionElement.updateFromWizard();
509 }
510 //be sure to reset to original in all cases
511 selectionElement.setEntity(originalEntity);
512 selectionElement.refresh();
513 }
514 }
515
516 // not used
517 /** {@inheritDoc} */
518 @Override
519 public void widgetDefaultSelected(SelectionEvent e) {
520 }
521
522 /**
523 * <p>
524 * getConversationHolder
525 * </p>
526 *
527 * @return a {@link eu.etaxonomy.cdm.api.conversation.ConversationHolder}
528 * object.
529 */
530 @Override
531 public ConversationHolder getConversationHolder() {
532 return conversation;
533 }
534
535 /** {@inheritDoc} */
536 @Override
537 public void setBackground(Color color) {
538 if(!label.isDisposed()){
539 label.setBackground(color);
540 }
541 }
542
543 /** {@inheritDoc} */
544 @Override
545 public void setLabel(String labelString) {
546 if (label != null) {
547 label.setText(labelString);
548 }
549 }
550
551 /**
552 * <p>
553 * Getter for the field <code>label</code>.
554 * </p>
555 *
556 * @return a {@link java.lang.String} object.
557 */
558 @Override
559 public String getLabel() {
560 if (label != null) {
561 return label.getText() + " : ";
562 }
563 return null;
564 }
565
566 /** {@inheritDoc} */
567 @Override
568 public void update(CdmDataChangeMap changeEvents) {
569 }
570
571 /* (non-Javadoc)
572 * @see eu.etaxonomy.taxeditor.ui.element.AbstractCdmFormElement#removeElements()
573 */
574 @Override
575 public void removeElements(){
576 super.removeElements();
577 LoginManager loginManager = CdmStore.getLoginManager();
578 loginManager.addObserver(this);
579 }
580
581 @Override
582 public void update(Observable o, Object arg) {
583 if(o instanceof LoginManager){
584 updateButtonStates();
585 }
586 }
587
588 private void updateButtonStates() {
589 if(button_edit != null && !button_selection.isDisposed()){
590 button_edit.setEnabled(isEditable && button_selection.isEnabled() && getEntity() != null && CdmStore.currentAuthentiationHasPermission((CdmBase) getEntity(), UPDATE));
591 }
592 }
593 }