Merge branch 'develop' into taxonDescription
[taxeditor.git] / eu.etaxonomy.taxeditor.store / src / main / java / eu / etaxonomy / taxeditor / ui / dialog / selection / AbstractFilteredCdmResourceSelectionDialog.java
1 /**
2 * Copyright (C) 2007 EDIT
3 * European Distributed Institute of Taxonomy
4 * http://www.e-taxonomy.eu
5 *
6 * The contents of this file are subject to the Mozilla Public License Version 1.1
7 * See LICENSE.TXT at the top of this package for the full license terms.
8 */
9
10 package eu.etaxonomy.taxeditor.ui.dialog.selection;
11
12 import java.text.Collator;
13 import java.util.ArrayList;
14 import java.util.Collections;
15 import java.util.Comparator;
16 import java.util.HashSet;
17 import java.util.Iterator;
18 import java.util.List;
19 import java.util.Set;
20 import java.util.UUID;
21
22 import org.apache.commons.lang.StringUtils;
23 import org.eclipse.core.runtime.IProgressMonitor;
24 import org.eclipse.core.runtime.IStatus;
25 import org.eclipse.jface.dialogs.IDialogConstants;
26 import org.eclipse.jface.dialogs.IDialogSettings;
27 import org.eclipse.jface.viewers.ILabelProvider;
28 import org.eclipse.jface.viewers.LabelProvider;
29 import org.eclipse.jface.viewers.StructuredSelection;
30 import org.eclipse.jface.window.Window;
31 import org.eclipse.jface.wizard.WizardDialog;
32 import org.eclipse.swt.SWT;
33 import org.eclipse.swt.events.SelectionAdapter;
34 import org.eclipse.swt.events.SelectionEvent;
35 import org.eclipse.swt.events.SelectionListener;
36 import org.eclipse.swt.graphics.Cursor;
37 import org.eclipse.swt.layout.GridData;
38 import org.eclipse.swt.layout.GridLayout;
39 import org.eclipse.swt.widgets.Button;
40 import org.eclipse.swt.widgets.Composite;
41 import org.eclipse.swt.widgets.Control;
42 import org.eclipse.swt.widgets.Shell;
43 import org.eclipse.swt.widgets.Text;
44
45 import eu.etaxonomy.cdm.api.service.dto.EntityDTOBase;
46 import eu.etaxonomy.cdm.api.service.dto.IdentifiedEntityDTO;
47 import eu.etaxonomy.cdm.model.common.CdmBase;
48 import eu.etaxonomy.cdm.model.common.ICdmBase;
49 import eu.etaxonomy.cdm.model.common.IIdentifiableEntity;
50 import eu.etaxonomy.cdm.persistence.dto.UuidAndTitleCache;
51 import eu.etaxonomy.taxeditor.l10n.Messages;
52 import eu.etaxonomy.taxeditor.model.MessagingUtils;
53 import eu.etaxonomy.taxeditor.newWizard.AbstractNewEntityWizard;
54 import eu.etaxonomy.taxeditor.preference.IPreferenceKeys;
55 import eu.etaxonomy.taxeditor.preference.PreferencesUtil;
56 import eu.etaxonomy.taxeditor.store.internal.TaxeditorStorePlugin;
57
58 /**
59 * <p>Abstract AbstractFilteredCdmResourceSelectionDialog class.</p>
60 *
61 * @author n.hoffmann
62 * @created 04.06.2009
63 * @version 1.0
64 */
65 public abstract class AbstractFilteredCdmResourceSelectionDialog<T extends ICdmBase> extends
66 SearchDialog {//implements IConversationEnabled {
67
68 // private final ConversationHolder conversation = null;
69
70 protected List<UuidAndTitleCache<T>> model;
71 private final Set<T> transientCdmObjects = new HashSet<T>();
72 private final String settings;
73 protected final int limitOfInitialElements = 100;
74
75 private T selectedObject;
76
77 protected Set<UUID> cdmBaseToBeFiltered;
78
79
80 /**
81 * <p>Constructor for AbstractFilteredCdmResourceSelectionDialog.</p>
82 *
83 * @param shell a {@link org.eclipse.swt.widgets.Shell} object.
84 * @param conversation
85 * @param title a {@link java.lang.String} object.
86 * @param multi a boolean.
87 * @param settings a {@link java.lang.String} object.
88 * @param cdmObject a T object.
89 * @param <T> a T object.
90 */
91 protected AbstractFilteredCdmResourceSelectionDialog(Shell shell, //ConversationHolder conversation,
92 String title, boolean multi, String settings, T cdmObject) {
93 super(shell, title);
94 setShellStyle(SWT.DIALOG_TRIM);
95 setMessage(Messages.SearchDialog_patternLabel);
96 this.settings = settings;
97 if (cdmObject != null){
98 this.cdmBaseToBeFiltered = new HashSet<>();
99 this.cdmBaseToBeFiltered.add(cdmObject.getUuid());
100 }
101 Cursor cursor = shell.getCursor();
102 shell.setCursor(shell.getDisplay().getSystemCursor(SWT.CURSOR_WAIT));
103 init();
104 shell.setCursor(cursor);
105 setListLabelProvider(createListLabelProvider());
106
107 }
108
109 /**
110 * By default, we are returning the standard list label provider
111 *
112 * Override in subclasses if you want different behavior
113 *
114 * @return
115 */
116 protected ILabelProvider createDetailsLabelProvider() {
117 return createListLabelProvider();
118 }
119
120 /**
121 *
122 * @return
123 */
124 protected ILabelProvider createListLabelProvider() {
125 return new FilteredCdmResourceLabelProvider();
126 }
127
128 /**
129 * Override in subclasses.
130 * Will run before initModel()
131 */
132 protected void init() {
133
134 }
135
136 /**
137 * <p>getSelectionFromDialog</p>
138 *
139 * @param dialog a {@link eu.etaxonomy.taxeditor.ui.dialog.selection.AbstractFilteredCdmResourceSelectionDialog} object.
140 * @param <TYPE> a TYPE object.
141 * @return a TYPE object.
142 */
143 protected static <TYPE extends CdmBase> TYPE getSelectionFromDialog(AbstractFilteredCdmResourceSelectionDialog<TYPE> dialog) {
144 UuidAndTitleCache result = getUuidAndTitleCacheSelectionFromDialog(dialog);
145 if (result != null){
146 return dialog.getCdmObjectByUuid(result.getUuid());
147 } else {
148 return null;
149 }
150 }
151
152 /**
153 * <p>getSelectionFromDialog</p>
154 *
155 * @param dialog a {@link eu.etaxonomy.taxeditor.ui.dialog.selection.AbstractFilteredCdmResourceSelectionDialog} object.
156 * @param <TYPE> a TYPE object.
157 * @return a TYPE object.
158 */
159 protected static UuidAndTitleCache getUuidAndTitleCacheSelectionFromDialog(AbstractFilteredCdmResourceSelectionDialog dialog) {
160 if (dialog == null){
161 return null;
162 }
163 int result = dialog.open();
164
165 if (result == Window.CANCEL) {
166 return null;
167 }
168
169 UuidAndTitleCache uuid = dialog.getSelectedUuidAndTitleCache();
170
171 return uuid;
172 }
173
174 /**
175 * Check if object was created during the life of this dialog. If not,
176 * retrieve it from the CdmStore.
177 *
178 * @param cdmUuid a {@link java.util.UUID} object.
179 * @return a T object.
180 */
181 protected T getCdmObjectByUuid(UUID cdmUuid) {
182 for (T cdmObject : transientCdmObjects) {
183 if (cdmObject.getUuid().equals(cdmUuid)) {
184 return cdmObject;
185 }
186 }
187 return getPersistentObject(cdmUuid);
188 }
189
190 /**
191 * <p>getPersistentObject</p>
192 *
193 * @param uuid a {@link java.util.UUID} object.
194 * @return a T object.
195 */
196 abstract protected T getPersistentObject(UUID uuid);
197
198
199 /**
200 * <p>isObjectTransient</p>
201 *
202 * @param cdmObject a T object.
203 * @return a boolean.
204 */
205 protected boolean isObjectTransient(T cdmObject) {
206 return (getPersistentObject(cdmObject.getUuid()) == null);
207 }
208
209 /**
210 * <p>getTitle</p>
211 *
212 * @param cdmObject a T object.
213 * @return a {@link java.lang.String} object.
214 */
215 protected String getTitle(T cdmObject) {
216 if(cdmObject == null){
217 return "";
218 }
219
220 if (cdmObject instanceof IIdentifiableEntity) {
221 return ((IIdentifiableEntity) cdmObject).getTitleCache();
222 }
223
224 throw new IllegalArgumentException("Generic method only" +
225 " supports cdmObject of type IIdentifiableEntity." +
226 " Please implement specific method in subclass.");
227 }
228
229
230
231 /**
232 * Set the filter input to the Agent's title cache
233 *
234 * @param cdmObject a T object.
235 */
236 protected void setPattern(T cdmObject) {
237 String pattern = getTitle(cdmObject);
238 getSearchField().setText(pattern);
239 }
240
241
242
243 /* (non-Javadoc)
244 * @see org.eclipse.ui.dialogs.FilteredItemsSelectionDialog#fillContentProvider(org.eclipse.ui.dialogs.FilteredItemsSelectionDialog.AbstractContentProvider, org.eclipse.ui.dialogs.FilteredItemsSelectionDialog.ItemsFilter, org.eclipse.core.runtime.IProgressMonitor)
245 */
246 /** {@inheritDoc} */
247
248 @Override
249 protected void fillContentProvider(IProgressMonitor progressMonitor)
250 {
251 try {
252 if (model == null){
253 model = new ArrayList<UuidAndTitleCache<T>>();
254 }
255 if(model != null){
256 if (progressMonitor != null){
257 progressMonitor.beginTask("Looking for entities", model.size());
258 }
259 sort();
260
261 contentProvider.reset();
262 Iterator<UuidAndTitleCache<T>> iterator = model.iterator();
263 UuidAndTitleCache<T> element;
264 while(iterator.hasNext()){
265 element = iterator.next();
266
267 if (cdmBaseToBeFiltered == null || !cdmBaseToBeFiltered.contains(element.getUuid())){
268 contentProvider.add(element);
269 }
270 if (progressMonitor != null){
271 if (progressMonitor.isCanceled()) {
272 return;
273 }
274 progressMonitor.worked(1);
275 }
276 }
277 this.refresh();
278 }else{
279
280 MessagingUtils.warn(getClass(), "Model for Filtered Selection is null:" + this.getClass().getSimpleName());
281 }
282 }
283 finally {
284 if (progressMonitor != null) {
285 progressMonitor.done();
286 }
287 }
288 }
289
290
291 protected void sort() {
292 Collections.sort(model, getItemsComparator());
293 }
294
295 /* (non-Javadoc)
296 * @see org.eclipse.ui.dialogs.FilteredItemsSelectionDialog#getDialogSettings()
297 */
298 /** {@inheritDoc} */
299
300 protected IDialogSettings getDialogSettings() {
301 IDialogSettings settings = TaxeditorStorePlugin.getDefault().getDialogSettings().getSection(getSettings());
302
303 if (settings == null) {
304 settings = TaxeditorStorePlugin.getDefault().getDialogSettings().addNewSection(getSettings());
305 }
306 return settings;
307 }
308
309 /* (non-Javadoc)
310 * @see org.eclipse.ui.dialogs.FilteredItemsSelectionDialog#getElementName(java.lang.Object)
311 */
312 /** {@inheritDoc} */
313
314 public String getElementName(Object item) {
315 return ((UuidAndTitleCache) item).getTitleCache();
316 }
317
318 /* (non-Javadoc)
319 * @see org.eclipse.ui.dialogs.FilteredItemsSelectionDialog#getItemsComparator()
320 */
321 /** {@inheritDoc} */
322
323 @Override
324 protected Comparator getItemsComparator() {
325 return new Comparator<UuidAndTitleCache>() {
326 @Override
327 public int compare(UuidAndTitleCache entity1,
328 UuidAndTitleCache entity2) {
329 Collator collator = Collator.getInstance();
330 if (entity1 == entity2){
331 return 0;
332 }
333
334 if (entity1 == null && entity2 != null){
335 return -1;
336 }
337 if (entity2 == null && entity1 != null){
338 return 1;
339 }
340 if (entity1.getUuid().equals(entity2.getUuid())){
341 return 0;
342 }
343 if (entity1.getTitleCache() == null && entity2.getTitleCache() != null){
344 return -1;
345 }
346 if (entity2.getTitleCache() == null){
347 return 1;
348 }
349 int result = collator.compare(entity1.getTitleCache(), entity2.getTitleCache());
350 if (result == 0){
351 result = entity1.getUuid().compareTo(entity2.getUuid());
352 }
353 return result;
354 }
355 };
356 }
357
358
359 /**
360 * <p>getSelectedUuidAndTitleCache</p>
361 *
362 * @return a {@link eu.etaxonomy.cdm.model.common.UuidAndTitleCache} object.
363 */
364 protected UuidAndTitleCache getSelectedUuidAndTitleCache() {
365 Object result = getResult();
366 if (result instanceof UuidAndTitleCache){
367 return (UuidAndTitleCache) result;
368 }
369 return null;
370 }
371
372 /**
373 * @return
374 */
375 private Object getResult() {
376 StructuredSelection selection = getCurrentSelection();
377 if (selection == null){
378 return null;
379 }
380 return selection.getFirstElement();
381 }
382
383 /**
384 * <p>Getter for the field <code>settings</code>.</p>
385 *
386 * @return a {@link java.lang.String} object.
387 */
388 public String getSettings() {
389 if(settings == null){
390 throw new IllegalStateException("No SETTINGS set.");
391 }
392 return settings;
393 }
394
395
396
397 /**
398 * <p>getNewWizardLinkText</p>
399 *
400 * @return a {@link java.lang.String} object.
401 */
402 protected abstract String[] getNewWizardText();
403
404 /**
405 * <p>getNewEntityWizard</p>
406 * @param parameter
407 * @return a {@link eu.etaxonomy.taxeditor.newWizard.AbstractNewEntityWizard} object.
408 */
409 protected abstract AbstractNewEntityWizard getNewEntityWizard(String parameter);
410
411 public class FilteredCdmResourceLabelProvider extends LabelProvider {
412 @Override
413 public String getText(Object element) {
414 if (element == null) {
415 return null;
416 }
417 UuidAndTitleCache uuidAndTitleCache = (UuidAndTitleCache) element;
418 String titleCache = uuidAndTitleCache.getTitleCache();
419 if(PreferencesUtil.getPreferenceStore().getBoolean(IPreferenceKeys.SHOW_ID_IN_ENTITY_SELECTION_DIAOLOG)){
420 titleCache += " ["+uuidAndTitleCache.getId()+"]";
421 }
422 if (element instanceof EntityDTOBase){
423 titleCache += "(" + ((IdentifiedEntityDTO)element).getIdentifier().getTypeLabel() +": " + ((IdentifiedEntityDTO)element).getIdentifier().getIdentifier() + ")";
424 }
425
426 return titleCache;
427 }
428 };
429
430 /* (non-Javadoc)
431 * @see org.eclipse.ui.dialogs.FilteredItemsSelectionDialog#createExtendedContentArea(org.eclipse.swt.widgets.Composite)
432 */
433 /** {@inheritDoc} */
434
435 // @Override
436 // protected Control createExtendedContentArea(Composite parent) {
437 // String newWizardLinkText = getNewWizardLinkText();
438 //// if(newWizardLinkText != null){
439 //// newButton1 = this.createButton(this.getShell(), new_id, newWizardLinkText, false);
440 ////
441 //// newButton1.addSelectionListener(getNewWizardLinkSelectionListener());
442 //// return newButton1;
443 //// }
444 // return null;
445 // }
446
447 @Override
448 protected void createButtonsForButtonBar(Composite parent) {
449 String[] newButtonText = getNewWizardText();
450
451 if (newButtonText!= null){
452 this.newButton1 = createButton(parent, this.new_id, newButtonText[0], false);
453 newButton1.addSelectionListener(getNewWizardButtonSelectionListener());
454
455
456 if (newButtonText.length > 1){
457 newButton2 = createButton(parent, this.new_id2, newButtonText[1], false);
458 newButton2.addSelectionListener(getNewWizardButtonSelectionListener());
459
460 }
461
462 }
463 Button space = createButton(parent, this.space_id, " ", false);
464 space.setEnabled(false);
465 space.setVisible(false);
466 GridData gridData = new GridData();
467 gridData.grabExcessHorizontalSpace = false;
468 gridData.widthHint = 3;
469 space.setLayoutData(gridData);
470 GridLayout gridLayout = new GridLayout();
471 gridLayout.makeColumnsEqualWidth= false;
472 if (newButtonText != null){
473 gridLayout.numColumns=newButtonText.length+2;
474 }else{
475 gridLayout.numColumns=2;
476 }
477 parent.setLayout(gridLayout);
478
479 super.createButtonsForButtonBar(parent);
480 super.getButton(IDialogConstants.OK_ID).setEnabled(false);
481 }
482
483 protected SelectionListener getNewWizardButtonSelectionListener(){
484 return new SelectionAdapter() {
485
486 /* (non-Javadoc)
487 * @see org.eclipse.swt.events.SelectionAdapter#widgetSelected(org.eclipse.swt.events.SelectionEvent)
488 */
489 @Override
490 public void widgetSelected(SelectionEvent e) {
491 Object source = e.getSource();
492 String text = null;
493 if (source instanceof Button){
494 Button sourceButton = (Button) source;
495 text = sourceButton.getText();
496 }
497 AbstractNewEntityWizard wizard = getNewEntityWizard(text);
498 if(wizard!=null){
499 if (wizard.getEntity() == null){
500 wizard.init(null, null);
501 }
502 if(wizard.getEntity() != null) {
503 WizardDialog dialog = new WizardDialog(getShell(), wizard);
504 int status = dialog.open();
505
506 if (status == IStatus.OK) {
507
508 T entity = (T) wizard.getEntity();
509 refresh();
510 setPattern(entity);
511
512 // if (getConversationHolder() != null){
513 // getConversationHolder().bind();
514 // }
515 }
516 //FIXME : Need to make sure this is a stable fix (ticket 3822)
517 // if (getConversationHolder() != null){
518 // getConversationHolder().commit();
519 // }
520 }
521 }
522 }
523 };
524 }
525
526 /**
527 * <p>getConversationHolder</p>
528 *
529 * @return a {@link eu.etaxonomy.cdm.api.conversation.ConversationHolder} object.
530 // */
531 // @Override
532 // public ConversationHolder getConversationHolder() {
533 // return conversation;
534 // }
535
536 /** {@inheritDoc} */
537 // @Override
538 // public void update(CdmDataChangeMap changeEvents) {}
539
540 /**
541 * Don't want to add for example a taxon or synonym to itself
542 * so filter the list to remove the taxon in question
543 * (<code>cdmBaseToBeFiltered</code>)
544 * so it is not available in the filtered list.
545 */
546 private void filterExcludedObjects() {
547 if (model != null && cdmBaseToBeFiltered != null) {
548
549 UuidAndTitleCache uuidAndTitleCacheToRemove = null;
550
551 for (UuidAndTitleCache uuidAndTitleCache : model){
552 if (cdmBaseToBeFiltered != null && cdmBaseToBeFiltered.contains(uuidAndTitleCache.getUuid())) {
553 uuidAndTitleCacheToRemove = uuidAndTitleCache;
554 }
555 }
556 model.remove(uuidAndTitleCacheToRemove);
557 }
558 }
559 @Override
560 void createFilterButton(Composite searchAndFilter){
561 //as default no filter button available
562 }
563
564 /** {@inheritDoc} */
565 @Override
566 protected void search() {
567 Control control =getSearchField();
568 String pattern = null;
569 if (control != null){
570 pattern = ((Text)control).getText();
571 if (pattern.equals("*") || pattern.equals("?")){
572 callService(null);
573 }else if (StringUtils.isNotBlank(pattern)){
574 callService(pattern);
575 }
576 fillContentProvider(null);
577 }
578
579 // if (pattern.equals("?")){
580 // model = CdmStore.getService(INameService.class).getUuidAndTitleCache(null, null);
581 // }else if (pattern != null){
582 // model = CdmStore.getService(INameService.class).getUuidAndTitleCache(limitOfInitialElements, pattern);
583 // }
584 }
585
586 abstract void callService(String pattern);
587
588 }