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