revert changes in selection dialogs for enums
[taxeditor.git] / eu.etaxonomy.taxeditor.store / src / main / java / eu / etaxonomy / taxeditor / ui / dialog / selection / AbstractFilteredIdentifierSelectionDialog.java
1 package eu.etaxonomy.taxeditor.ui.dialog.selection;
2
3 import java.text.Collator;
4 /**
5 * Copyright (C) 2007 EDIT
6 * European Distributed Institute of Taxonomy
7 * http://www.e-taxonomy.eu
8 *
9 * The contents of this file are subject to the Mozilla Public License Version 1.1
10 * See LICENSE.TXT at the top of this package for the full license terms.
11 */
12 import java.util.Comparator;
13 import java.util.HashSet;
14 import java.util.Iterator;
15 import java.util.List;
16 import java.util.Set;
17 import java.util.UUID;
18
19 import org.eclipse.core.runtime.CoreException;
20 import org.eclipse.core.runtime.IProgressMonitor;
21 import org.eclipse.core.runtime.IStatus;
22 import org.eclipse.core.runtime.OperationCanceledException;
23 import org.eclipse.core.runtime.Status;
24 import org.eclipse.jface.dialogs.IDialogSettings;
25 import org.eclipse.jface.viewers.ILabelProvider;
26 import org.eclipse.jface.viewers.LabelProvider;
27 import org.eclipse.jface.window.Window;
28 import org.eclipse.jface.wizard.WizardDialog;
29 import org.eclipse.swt.SWT;
30 import org.eclipse.swt.events.SelectionAdapter;
31 import org.eclipse.swt.events.SelectionEvent;
32 import org.eclipse.swt.events.SelectionListener;
33 import org.eclipse.swt.widgets.Composite;
34 import org.eclipse.swt.widgets.Control;
35 import org.eclipse.swt.widgets.Link;
36 import org.eclipse.swt.widgets.Shell;
37 import org.eclipse.swt.widgets.Text;
38 import org.eclipse.ui.IMemento;
39
40 import eu.etaxonomy.cdm.api.conversation.ConversationHolder;
41 import eu.etaxonomy.cdm.api.conversation.IConversationEnabled;
42 import eu.etaxonomy.cdm.api.service.dto.IdentifiedEntityDTO;
43 import eu.etaxonomy.cdm.model.common.CdmBase;
44 import eu.etaxonomy.cdm.model.common.ICdmBase;
45 import eu.etaxonomy.cdm.model.common.IIdentifiableEntity;
46 import eu.etaxonomy.cdm.persistence.hibernate.CdmDataChangeMap;
47 import eu.etaxonomy.taxeditor.model.MessagingUtils;
48 import eu.etaxonomy.taxeditor.newWizard.AbstractNewEntityWizard;
49 import eu.etaxonomy.taxeditor.preference.IPreferenceKeys;
50 import eu.etaxonomy.taxeditor.preference.PreferencesUtil;
51 import eu.etaxonomy.taxeditor.store.internal.TaxeditorStorePlugin;
52
53 public abstract class AbstractFilteredIdentifierSelectionDialog<T extends ICdmBase> extends CdmFilteredItemsSelectionDialog implements IConversationEnabled {
54
55 private final ConversationHolder conversation;
56
57 protected List<IdentifiedEntityDTO> model;
58 private final Set<T> transientCdmObjects = new HashSet<T>();
59 private final String settings;
60 protected final int limitOfInitialElements = 100;
61
62 protected T cdmBaseToBeFiltered;
63
64
65 /**
66 * <p>Constructor for AbstractFilteredCdmResourceSelectionDialog.</p>
67 *
68 * @param shell a {@link org.eclipse.swt.widgets.Shell} object.
69 * @param conversation
70 * @param title a {@link java.lang.String} object.
71 * @param multi a boolean.
72 * @param settings a {@link java.lang.String} object.
73 * @param cdmObject a T object.
74 * @param <T> a T object.
75 */
76 protected AbstractFilteredIdentifierSelectionDialog(Shell shell, ConversationHolder conversation, String title, boolean multi, String settings, T cdmObject) {
77 super(shell, multi);
78 setTitle(title);
79 setMessage("Use * for wildcard, or ? to see all entries");
80 this.settings = settings;
81
82 this.conversation = conversation;
83 this.cdmBaseToBeFiltered = cdmObject;
84 org.eclipse.swt.graphics.Cursor cursor = shell.getCursor();
85 shell.setCursor(shell.getDisplay().getSystemCursor(SWT.CURSOR_WAIT));
86 init();
87 // initModel();
88 shell.setCursor(cursor);
89 String objectTitle = getTitle(cdmObject);
90 // if (objectTitle != null) {
91 // setInitialPattern(objectTitle);
92 // }
93
94 setListLabelProvider(createListLabelProvider());
95 setDetailsLabelProvider(createDetailsLabelProvider());
96
97 setSelectionHistory(new IdentifierSelectionHistory());
98 }
99
100 /**
101 * By default, we are returning the standard list label provider
102 *
103 * Override in subclasses if you want different behavior
104 *
105 * @return
106 */
107 protected ILabelProvider createDetailsLabelProvider() {
108 return createListLabelProvider();
109 }
110
111 /**
112 *
113 * @return
114 */
115 protected ILabelProvider createListLabelProvider() {
116 return new FilteredIdentifiedEntityLabelProvider();
117 }
118
119 /**
120 * Override in subclasses.
121 * Will run before initModel()
122 */
123 protected void init() {
124
125 }
126
127 /**
128 * <p>getSelectionFromDialog</p>
129 *
130 * @param dialog a {@link eu.etaxonomy.taxeditor.ui.dialog.selection.AbstractFilteredCdmResourceSelectionDialog} object.
131 * @param <TYPE> a TYPE object.
132 * @return a TYPE object.
133 */
134 protected static <TYPE extends CdmBase> TYPE getSelectionFromDialog(AbstractFilteredCdmResourceSelectionDialog<TYPE> dialog) {
135 //dialog.setInitialPattern("");
136 int result = dialog.open();
137
138 if (result == Window.CANCEL) {
139 return null;
140 }
141
142 UUID uuid = dialog.getSelectedUuidAndTitleCache().getUuid();
143 if(uuid == null){
144 return null;
145 }
146 return dialog.getCdmObjectByUuid(uuid);
147 }
148
149 /**
150 * Check if object was created during the life of this dialog. If not,
151 * retrieve it from the CdmStore.
152 *
153 * @param cdmUuid a {@link java.util.UUID} object.
154 * @return a T object.
155 */
156 protected T getCdmObjectByUuid(UUID cdmUuid) {
157 for (T cdmObject : transientCdmObjects) {
158 if (cdmObject.getUuid().equals(cdmUuid)) {
159 return cdmObject;
160 }
161 }
162 return getPersistentObject(cdmUuid);
163 }
164
165 /**
166 * <p>getPersistentObject</p>
167 *
168 * @param uuid a {@link java.util.UUID} object.
169 * @return a T object.
170 */
171 abstract protected T getPersistentObject(UUID uuid);
172
173 /**
174 * @param cdmObject
175 */
176 // protected void addObjectToModel(T cdmObject) {
177 // model.add(new UuidAndTitleCache(cdmObject.getClass(), cdmObject.getUuid(), getTitle(cdmObject)));
178 // transientCdmObjects.add(cdmObject);
179 // }
180
181 /**
182 * <p>isObjectTransient</p>
183 *
184 * @param cdmObject a T object.
185 * @return a boolean.
186 */
187 protected boolean isObjectTransient(T cdmObject) {
188 return (getPersistentObject(cdmObject.getUuid()) == null);
189 }
190
191 /**
192 * <p>getTitle</p>
193 *
194 * @param cdmObject a T object.
195 * @return a {@link java.lang.String} object.
196 */
197 protected String getTitle(T cdmObject) {
198 if(cdmObject == null){
199 return "";
200 }
201
202 if (cdmObject instanceof IIdentifiableEntity) {
203 return ((IIdentifiableEntity) cdmObject).getTitleCache();
204 }
205
206 throw new IllegalArgumentException("Generic method only" +
207 " supports cdmObject of type IIdentifiableEntity." +
208 " Please implement specific method in subclass.");
209 }
210
211
212 /** {@inheritDoc} */
213 @Override
214 public void refresh() {
215 super.refresh();
216 }
217
218
219
220 /* (non-Javadoc)
221 * @see org.eclipse.ui.dialogs.FilteredItemsSelectionDialog#createFilter()
222 */
223 /** {@inheritDoc} */
224 @Override
225 protected ItemsFilter createFilter() {
226 return new ItemsFilter() {
227
228 /**
229 * Always returns false to enforce refiltering even if the pattern is equal
230 */
231 @Override
232 public boolean equalsFilter(ItemsFilter filter) {
233 return false;
234 }
235
236 @Override
237 public boolean isConsistentItem(Object item) {
238 return false;
239 }
240
241 @Override
242 public boolean matchItem(Object item) {
243 String text = null;
244 if(item instanceof IdentifiedEntityDTO){
245 text = ((IdentifiedEntityDTO) item).getCdmEntity().getTitleCache();
246 }else if(item instanceof String){
247 text = (String) item;
248 }
249 return text != null ? matches(text) : false;
250 }
251
252 };
253 }
254
255
256 /**
257 * Set the filter input to the Agent's title cache
258 *
259 * @param cdmObject a T object.
260 */
261 protected void setPattern(T cdmObject) {
262 // FilteredSelection does some very tricky caching to make sure it
263 // runs with high performance.
264 // This works for most use cases, but we want to change the model while the dialog is open
265 // and all the clever caching prevents the content provider from knowing that the model has changed
266 // I am aware, that this is a hack, but the FilteredSelectionDialog API does not offer a convenient
267 // way to solve the problem.
268 // try {
269 // Field lastCompletedFilter = this.getClass().getSuperclass().getSuperclass().getDeclaredField("lastCompletedFilter");
270 // lastCompletedFilter.setAccessible(true);
271 // lastCompletedFilter.set(this, null);
272 // } catch (SecurityException e) {
273 // MessagingUtils.error(getClass(), e);
274 // } catch (NoSuchFieldException e) {
275 // MessagingUtils.error(getClass(), e);
276 // } catch (IllegalArgumentException e) {
277 // MessagingUtils.error(getClass(), e);
278 // } catch (IllegalAccessException e) {
279 // MessagingUtils.error(getClass(), e);
280 // }
281
282 // this also is not the nicest way to do it.
283 // I am still amazed, that FilteredSelectionDialog does not offer any methods to change its data
284 // once it was opened. Am I doing it wrong?
285 String pattern = getTitle(cdmObject);
286 ((Text) getPatternControl()).setText(pattern);
287 }
288
289
290
291 /* (non-Javadoc)
292 * @see org.eclipse.ui.dialogs.FilteredItemsSelectionDialog#fillContentProvider(org.eclipse.ui.dialogs.FilteredItemsSelectionDialog.AbstractContentProvider, org.eclipse.ui.dialogs.FilteredItemsSelectionDialog.ItemsFilter, org.eclipse.core.runtime.IProgressMonitor)
293 */
294 /** {@inheritDoc} */
295 @Override
296 protected void fillContentProvider(AbstractContentProvider contentProvider,
297 ItemsFilter itemsFilter, IProgressMonitor progressMonitor)
298 throws CoreException {
299 try {
300 if(model != null){
301 progressMonitor.beginTask("Looking for entities", model.size());
302 filterExcludedObjects();
303 Iterator<IdentifiedEntityDTO> iterator = model.iterator();
304 IdentifiedEntityDTO element;
305 while(iterator.hasNext()){
306 element = iterator.next();
307 if (!element.equals(cdmBaseToBeFiltered)){
308 contentProvider.add(element, itemsFilter);
309 }
310 if (progressMonitor.isCanceled()) {
311 throw new OperationCanceledException();
312 }
313 progressMonitor.worked(1);
314 }
315 }else{
316 MessagingUtils.warn(getClass(), "Model for Filtered Selection is null:" + this.getClass().getSimpleName());
317 }
318 }
319 finally {
320 progressMonitor.done();
321 }
322 }
323
324 /* (non-Javadoc)
325 * @see org.eclipse.ui.dialogs.FilteredItemsSelectionDialog#getDialogSettings()
326 */
327 /** {@inheritDoc} */
328 @Override
329 protected IDialogSettings getDialogSettings() {
330 IDialogSettings settings = TaxeditorStorePlugin.getDefault().getDialogSettings().getSection(getSettings());
331
332 if (settings == null) {
333 settings = TaxeditorStorePlugin.getDefault().getDialogSettings().addNewSection(getSettings());
334 }
335 return settings;
336 }
337
338 /* (non-Javadoc)
339 * @see org.eclipse.ui.dialogs.FilteredItemsSelectionDialog#getElementName(java.lang.Object)
340 */
341 /** {@inheritDoc} */
342 @Override
343 public String getElementName(Object item) {
344 return ((IdentifiedEntityDTO) item).getCdmEntity().getTitleCache();
345 }
346
347 /* (non-Javadoc)
348 * @see org.eclipse.ui.dialogs.FilteredItemsSelectionDialog#getItemsComparator()
349 */
350 /** {@inheritDoc} */
351 @Override
352 protected Comparator getItemsComparator() {
353 return new Comparator<IdentifiedEntityDTO>() {
354 @Override
355 public int compare(IdentifiedEntityDTO entity1,
356 IdentifiedEntityDTO entity2) {
357 Collator collator = Collator.getInstance();
358 if (entity1.getCdmEntity().getCdmUuid().equals(entity2.getCdmEntity().getCdmUuid())){
359 return 0;
360 }
361 int result = collator.compare(entity1.getCdmEntity().getTitleCache(), entity2.getCdmEntity().getTitleCache());
362 if (result == 0){
363 result = entity1.getCdmEntity().getCdmUuid().compareTo(entity2.getCdmEntity().getCdmUuid());
364 }
365 return result;
366 }
367 };
368 }
369
370 /* (non-Javadoc)
371 * @see org.eclipse.ui.dialogs.FilteredItemsSelectionDialog#validateItem(java.lang.Object)
372 */
373 /** {@inheritDoc} */
374 @Override
375 protected IStatus validateItem(Object item) {
376 return Status.OK_STATUS;
377 }
378
379 /**
380 * <p>getSelectedUuidAndTitleCache</p>
381 *
382 * @return a {@link eu.etaxonomy.cdm.model.common.UuidAndTitleCache} object.
383 */
384 protected IdentifiedEntityDTO getSelectedUuidAndTitleCache() {
385 Object[] result = getResult();
386 return result[0] == null ? null : (IdentifiedEntityDTO) result[0];
387 }
388
389 /**
390 * <p>Getter for the field <code>settings</code>.</p>
391 *
392 * @return a {@link java.lang.String} object.
393 */
394 public String getSettings() {
395 if(settings == null){
396 throw new IllegalStateException("No SETTINGS set.");
397 }
398 return settings;
399 }
400
401 /**
402 *
403 * @author n.hoffmann
404 * @created Oct 19, 2009
405 * @version 1.0
406 */
407 private class IdentifierSelectionHistory extends SelectionHistory {
408 /*
409 * @see org.eclipse.ui.dialogs.FilteredItemsSelectionDialog.SelectionHistory#restoreItemFromMemento(org.eclipse.ui.IMemento)
410 */
411 @Override
412 protected Object restoreItemFromMemento(IMemento element) {
413 return element.getString("resource"); //$NON-NLS-1$
414 }
415 /*
416 * @see org.eclipse.ui.dialogs.FilteredItemsSelectionDialog.SelectionHistory#storeItemToMemento(java.lang.Object,
417 * org.eclipse.ui.IMemento)
418 */
419 @Override
420 protected void storeItemToMemento(Object item, IMemento element) {
421 element.putString("resource", item.toString()); //$NON-NLS-1$
422 }
423 }
424
425 /**
426 * <p>getNewWizardLinkText</p>
427 *
428 * @return a {@link java.lang.String} object.
429 */
430 protected abstract String getNewWizardLinkText();
431
432 /**
433 * <p>getNewEntityWizard</p>
434 * @param parameter
435 * @return a {@link eu.etaxonomy.taxeditor.newWizard.AbstractNewEntityWizard} object.
436 */
437 protected abstract AbstractNewEntityWizard getNewEntityWizard(String parameter);
438
439 public class FilteredIdentifiedEntityLabelProvider extends LabelProvider {
440 @Override
441 public String getText(Object element) {
442 if (element == null) {
443 return null;
444 }
445 IdentifiedEntityDTO identifiedEntity = (IdentifiedEntityDTO) element;
446 String titleCache = identifiedEntity.getCdmEntity().getTitleCache();
447 if(PreferencesUtil.getPreferenceStore().getBoolean(IPreferenceKeys.SHOW_ID_IN_ENTITY_SELECTION_DIAOLOG)){
448 titleCache += " ["+identifiedEntity.getCdmEntity().getCdmUuid()+"]";
449 }
450 return titleCache;
451 }
452 };
453
454 /* (non-Javadoc)
455 * @see org.eclipse.ui.dialogs.FilteredItemsSelectionDialog#createExtendedContentArea(org.eclipse.swt.widgets.Composite)
456 */
457 /** {@inheritDoc} */
458 @Override
459 protected Control createExtendedContentArea(Composite parent) {
460 String newWizardLinkText = getNewWizardLinkText();
461 if(newWizardLinkText != null){
462 Link link = new Link(parent, SWT.NONE);
463 link.setText(newWizardLinkText);
464 link.addSelectionListener(getNewWizardLinkSelectionListener());
465 return link;
466 }
467 return null;
468 }
469
470 protected SelectionListener getNewWizardLinkSelectionListener(){
471 return new SelectionAdapter() {
472
473 /* (non-Javadoc)
474 * @see org.eclipse.swt.events.SelectionAdapter#widgetSelected(org.eclipse.swt.events.SelectionEvent)
475 */
476 @Override
477 public void widgetSelected(SelectionEvent e) {
478
479 AbstractNewEntityWizard wizard = getNewEntityWizard(e.text);
480 if(wizard!=null){
481 wizard.init(null, null);
482 if(wizard.getEntity() != null) {
483 WizardDialog dialog = new WizardDialog(getShell(), wizard);
484 int status = dialog.open();
485
486 if (status == IStatus.OK) {
487
488 T entity = (T) wizard.getEntity();
489 // model.add(new UuidAndTitleCache<T>(entity.getUuid(), entity.getId(), getTitle(entity)));
490 refresh();
491 setPattern(entity);
492 if (getConversationHolder() != null){
493 getConversationHolder().bind();
494 }
495 }
496 //FIXME : Need to make sure this is a stable fix (ticket 3822)
497 if (getConversationHolder() != null){
498 getConversationHolder().commit();
499 }
500 }
501 }
502 }
503 };
504 }
505
506 /**
507 * <p>getConversationHolder</p>
508 *
509 * @return a {@link eu.etaxonomy.cdm.api.conversation.ConversationHolder} object.
510 */
511 @Override
512 public ConversationHolder getConversationHolder() {
513 return conversation;
514 }
515
516 /** {@inheritDoc} */
517 @Override
518 public void update(CdmDataChangeMap changeEvents) {}
519
520 /**
521 * Don't want to add for example a taxon or synonym to itself
522 * so filter the list to remove the taxon in question
523 * (<code>cdmBaseToBeFiltered</code>)
524 * so it is not available in the filtered list.
525 */
526 private void filterExcludedObjects() {
527 if (model != null && cdmBaseToBeFiltered != null) {
528
529 IdentifiedEntityDTO identifiedEntityToRemove = null;
530
531 for (IdentifiedEntityDTO identifiedEntity : model){
532 if ((cdmBaseToBeFiltered.getUuid()).equals(identifiedEntity.getCdmEntity().getCdmUuid())) {
533 identifiedEntityToRemove = identifiedEntity;
534 }
535 }
536 model.remove(identifiedEntityToRemove);
537 }
538 }
539
540
541
542 }