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