Project

General

Profile

Download (15.1 KB) Statistics
| Branch: | Tag: | Revision:
1
// $Id$
2
/**
3
* Copyright (C) 2007 EDIT
4
* European Distributed Institute of Taxonomy
5
* http://www.e-taxonomy.eu
6
*
7
* The contents of this file are subject to the Mozilla Public License Version 1.1
8
* See LICENSE.TXT at the top of this package for the full license terms.
9
*/
10

    
11
package eu.etaxonomy.taxeditor.ui.dialog.selection;
12

    
13
import java.lang.reflect.Field;
14
import java.text.Collator;
15
import java.util.Comparator;
16
import java.util.HashSet;
17
import java.util.List;
18
import java.util.Set;
19
import java.util.UUID;
20

    
21
import org.eclipse.core.runtime.CoreException;
22
import org.eclipse.core.runtime.IProgressMonitor;
23
import org.eclipse.core.runtime.IStatus;
24
import org.eclipse.core.runtime.OperationCanceledException;
25
import org.eclipse.core.runtime.Status;
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.window.Window;
30
import org.eclipse.jface.wizard.WizardDialog;
31
import org.eclipse.swt.SWT;
32
import org.eclipse.swt.events.SelectionAdapter;
33
import org.eclipse.swt.events.SelectionEvent;
34
import org.eclipse.swt.events.SelectionListener;
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
import org.eclipse.ui.dialogs.FilteredItemsSelectionDialog;
42

    
43
import eu.etaxonomy.cdm.api.conversation.ConversationHolder;
44
import eu.etaxonomy.cdm.api.conversation.IConversationEnabled;
45
import eu.etaxonomy.cdm.model.common.CdmBase;
46
import eu.etaxonomy.cdm.model.common.ICdmBase;
47
import eu.etaxonomy.cdm.model.common.IIdentifiableEntity;
48
import eu.etaxonomy.cdm.persistence.dto.UuidAndTitleCache;
49
import eu.etaxonomy.cdm.persistence.hibernate.CdmDataChangeMap;
50
import eu.etaxonomy.taxeditor.model.MessagingUtils;
51
import eu.etaxonomy.taxeditor.newWizard.AbstractNewEntityWizard;
52
import eu.etaxonomy.taxeditor.preference.IPreferenceKeys;
53
import eu.etaxonomy.taxeditor.preference.PreferencesUtil;
54
import eu.etaxonomy.taxeditor.store.internal.TaxeditorStorePlugin;
55

    
56
/**
57
 * <p>Abstract AbstractFilteredCdmResourceSelectionDialog class.</p>
58
 *
59
 * @author n.hoffmann
60
 * @created 04.06.2009
61
 * @version 1.0
62
 */
63
public abstract class AbstractFilteredCdmResourceSelectionDialog<T extends ICdmBase> extends
64
		FilteredItemsSelectionDialog implements IConversationEnabled {
65

    
66
	private final ConversationHolder conversation;
67

    
68
	protected List<UuidAndTitleCache<T>> model;
69
	private final Set<T> transientCdmObjects = new HashSet<T>();
70
	private final String settings;
71

    
72
	protected T cdmBaseToBeFiltered;
73

    
74
	/**
75
	 * <p>Constructor for AbstractFilteredCdmResourceSelectionDialog.</p>
76
	 *
77
	 * @param shell a {@link org.eclipse.swt.widgets.Shell} object.
78
	 * @param conversation
79
	 * @param title a {@link java.lang.String} object.
80
	 * @param multi a boolean.
81
	 * @param settings a {@link java.lang.String} object.
82
	 * @param cdmObject a T object.
83
	 * @param <T> a T object.
84
	 */
85
	protected AbstractFilteredCdmResourceSelectionDialog(Shell shell, ConversationHolder conversation, String title, boolean multi, String settings, T cdmObject) {
86
		super(shell, multi);
87
		setTitle(title);
88
		setMessage("Use * for wildcard, or ? to see all entries");
89
		this.settings = settings;
90

    
91
		this.conversation = conversation;
92

    
93
		init();
94

    
95
		initModel();
96

    
97
		String objectTitle = getTitle(cdmObject);
98
		if (objectTitle != null) {
99
			setInitialPattern(objectTitle);
100
		}
101

    
102
		setListLabelProvider(createListLabelProvider());
103
		setDetailsLabelProvider(createDetailsLabelProvider());
104

    
105
		setSelectionHistory(new ResourceSelectionHistory());
106
	}
107

    
108
	/**
109
	 * By default, we are returning the standard list label provider
110
	 *
111
	 * Override in subclasses if you want different behavior
112
	 *
113
	 * @return
114
	 */
115
	protected ILabelProvider createDetailsLabelProvider() {
116
		return createListLabelProvider();
117
	}
118

    
119
	/**
120
	 *
121
	 * @return
122
	 */
123
	protected ILabelProvider createListLabelProvider() {
124
		return new FilteredCdmResourceLabelProvider();
125
	}
126

    
127
	/**
128
	 * Override in subclasses.
129
	 * Will run before initModel()
130
	 */
131
	protected void init() {
132

    
133
	}
134

    
135
	/**
136
	 * <p>getSelectionFromDialog</p>
137
	 *
138
	 * @param dialog a {@link eu.etaxonomy.taxeditor.ui.dialog.selection.AbstractFilteredCdmResourceSelectionDialog} object.
139
	 * @param <TYPE> a TYPE object.
140
	 * @return a TYPE object.
141
	 */
142
	protected static <TYPE extends CdmBase> TYPE getSelectionFromDialog(AbstractFilteredCdmResourceSelectionDialog<TYPE> dialog) {
143
		//dialog.setInitialPattern("");
144
		int result = dialog.open();
145

    
146
		if (result == Window.CANCEL) {
147
			return null;
148
		}
149

    
150
		UUID uuid = dialog.getSelectedUuidAndTitleCache().getUuid();
151
		if(uuid == null){
152
			return null;
153
		}
154
		return dialog.getCdmObjectByUuid(uuid);
155
	}
156

    
157
	/**
158
	 * Check if object was created during the life of this dialog. If not,
159
	 * retrieve it from the CdmStore.
160
	 *
161
	 * @param cdmUuid a {@link java.util.UUID} object.
162
	 * @return a T object.
163
	 */
164
	protected T getCdmObjectByUuid(UUID cdmUuid) {
165
		for (T cdmObject : transientCdmObjects) {
166
			if (cdmObject.getUuid().equals(cdmUuid)) {
167
				return cdmObject;
168
			}
169
		}
170
		return getPersistentObject(cdmUuid);
171
	}
172

    
173
	/**
174
	 * <p>getPersistentObject</p>
175
	 *
176
	 * @param uuid a {@link java.util.UUID} object.
177
	 * @return a T object.
178
	 */
179
	abstract protected T getPersistentObject(UUID uuid);
180

    
181
	/**
182
	 * @param cdmObject
183
	 */
184
//	protected void addObjectToModel(T cdmObject) {
185
//		model.add(new UuidAndTitleCache(cdmObject.getClass(), cdmObject.getUuid(), getTitle(cdmObject)));
186
//		transientCdmObjects.add(cdmObject);
187
//	}
188

    
189
	/**
190
	 * <p>isObjectTransient</p>
191
	 *
192
	 * @param cdmObject a T object.
193
	 * @return a boolean.
194
	 */
195
	protected boolean isObjectTransient(T cdmObject) {
196
		return (getPersistentObject(cdmObject.getUuid()) == null);
197
	}
198

    
199
	/**
200
	 * <p>getTitle</p>
201
	 *
202
	 * @param cdmObject a T object.
203
	 * @return a {@link java.lang.String} object.
204
	 */
205
	protected String getTitle(T cdmObject) {
206
		if(cdmObject == null){
207
			return "";
208
		}
209

    
210
		if (cdmObject instanceof IIdentifiableEntity) {
211
			return ((IIdentifiableEntity) cdmObject).getTitleCache();
212
		}
213

    
214
		throw new IllegalArgumentException("Generic method only" +
215
				" supports cdmObject of type IIdentifiableEntity." +
216
				" Please implement specific method in subclass.");
217
	}
218

    
219

    
220
	/** {@inheritDoc} */
221
	@Override
222
	public void refresh() {
223
		initModel();
224
		filterExcludedObjects();
225
		super.refresh();
226
	}
227

    
228
	/**
229
	 * <p>initModel</p>
230
	 */
231
	abstract protected void initModel();
232

    
233
	/* (non-Javadoc)
234
	 * @see org.eclipse.ui.dialogs.FilteredItemsSelectionDialog#createFilter()
235
	 */
236
	/** {@inheritDoc} */
237
	@Override
238
	protected ItemsFilter createFilter() {
239
		return new ItemsFilter() {
240

    
241
			/**
242
			 * Always returns false to enforce refiltering even if the pattern is equal
243
			 */
244
			@Override
245
			public boolean equalsFilter(ItemsFilter filter) {
246
				return false;
247
			}
248

    
249
			@Override
250
			public boolean isConsistentItem(Object item) {
251
				return false;
252
			}
253

    
254
			@Override
255
			public boolean matchItem(Object item) {
256
				String text = null;
257
				if(item instanceof UuidAndTitleCache){
258
					text = ((UuidAndTitleCache) item).getTitleCache();
259
				}else if(item instanceof String){
260
					text = (String) item;
261
				}
262
				return text != null ? matches(text) : false;
263
			}
264

    
265
		};
266
	}
267

    
268

    
269
	/**
270
	 * Set the filter input to the Agent's title cache
271
	 *
272
	 * @param cdmObject a T object.
273
	 */
274
	protected void setPattern(T cdmObject) {
275
		// FilteredSelection does some very tricky caching to make sure it
276
		// runs with high performance.
277
		// This works for most use cases, but we want to change the model while the dialog is open
278
		// and all the clever caching prevents the content provider from knowing that the model has changed
279
		// I am aware, that this is a hack, but the FilteredSelectionDialog API does not offer a convenient
280
		// way to solve the problem.
281
		try {
282
			Field lastCompletedFilter = this.getClass().getSuperclass().getSuperclass().getDeclaredField("lastCompletedFilter");
283
			lastCompletedFilter.setAccessible(true);
284
			lastCompletedFilter.set(this, null);
285
		} catch (SecurityException e) {
286
			MessagingUtils.error(getClass(), e);
287
		} catch (NoSuchFieldException e) {
288
			MessagingUtils.error(getClass(), e);
289
		} catch (IllegalArgumentException e) {
290
			MessagingUtils.error(getClass(), e);
291
		} catch (IllegalAccessException e) {
292
			MessagingUtils.error(getClass(), e);
293
		}
294

    
295
		// this also is not the nicest way to do it.
296
		// I am still amazed, that FilteredSelectionDialog does not offer any methods to change its data
297
		// once it was opened. Am I doing it wrong?
298
		String pattern = getTitle(cdmObject);
299
		((Text) getPatternControl()).setText(pattern);
300
	}
301

    
302
	/* (non-Javadoc)
303
	* @see org.eclipse.ui.dialogs.FilteredItemsSelectionDialog#fillContentProvider(org.eclipse.ui.dialogs.FilteredItemsSelectionDialog.AbstractContentProvider, org.eclipse.ui.dialogs.FilteredItemsSelectionDialog.ItemsFilter, org.eclipse.core.runtime.IProgressMonitor)
304
	*/
305
	/** {@inheritDoc} */
306
	@Override
307
	protected void fillContentProvider(AbstractContentProvider contentProvider,
308
		ItemsFilter itemsFilter, IProgressMonitor progressMonitor)
309
		throws CoreException {
310
		try {
311
			if(model != null){
312
				progressMonitor.beginTask("Looking for entities", model.size());
313
				for(UuidAndTitleCache<T> element : model){
314
					contentProvider.add(element, itemsFilter);
315
					if (progressMonitor.isCanceled()) {
316
						throw new OperationCanceledException();
317
					}
318
					progressMonitor.worked(1);
319
				}
320
			}else{
321
				MessagingUtils.warn(getClass(), "Model for Filtered Selection is null:" + this.getClass().getSimpleName());
322
			}
323
		}
324
		finally {
325
			progressMonitor.done();
326
		}
327
	}
328

    
329
	/* (non-Javadoc)
330
	 * @see org.eclipse.ui.dialogs.FilteredItemsSelectionDialog#getDialogSettings()
331
	 */
332
	/** {@inheritDoc} */
333
	@Override
334
	protected IDialogSettings getDialogSettings() {
335
		IDialogSettings settings = TaxeditorStorePlugin.getDefault().getDialogSettings().getSection(getSettings());
336

    
337
		if (settings == null) {
338
			settings = TaxeditorStorePlugin.getDefault().getDialogSettings().addNewSection(getSettings());
339
		}
340
		return settings;
341
	}
342

    
343
	/* (non-Javadoc)
344
	 * @see org.eclipse.ui.dialogs.FilteredItemsSelectionDialog#getElementName(java.lang.Object)
345
	 */
346
	/** {@inheritDoc} */
347
	@Override
348
	public String getElementName(Object item) {
349
		return ((UuidAndTitleCache) item).getTitleCache();
350
	}
351

    
352
	/* (non-Javadoc)
353
	 * @see org.eclipse.ui.dialogs.FilteredItemsSelectionDialog#getItemsComparator()
354
	 */
355
	/** {@inheritDoc} */
356
	@Override
357
	protected Comparator getItemsComparator() {
358
		return new Comparator<UuidAndTitleCache>() {
359
			@Override
360
			public int compare(UuidAndTitleCache entity1,
361
					UuidAndTitleCache entity2) {
362
				Collator collator = Collator.getInstance();
363
				return collator.compare(entity1.getTitleCache(), entity2.getTitleCache());
364
			}
365
		};
366
	}
367

    
368
	/* (non-Javadoc)
369
	 * @see org.eclipse.ui.dialogs.FilteredItemsSelectionDialog#validateItem(java.lang.Object)
370
	 */
371
	/** {@inheritDoc} */
372
	@Override
373
	protected IStatus validateItem(Object item) {
374
		return Status.OK_STATUS;
375
	}
376

    
377
	/**
378
	 * <p>getSelectedUuidAndTitleCache</p>
379
	 *
380
	 * @return a {@link eu.etaxonomy.cdm.model.common.UuidAndTitleCache} object.
381
	 */
382
	protected UuidAndTitleCache getSelectedUuidAndTitleCache() {
383
		Object[] result = getResult();
384
		return result[0] == null ? null : (UuidAndTitleCache) result[0];
385
	}
386

    
387
	/**
388
	 * <p>Getter for the field <code>settings</code>.</p>
389
	 *
390
	 * @return a {@link java.lang.String} object.
391
	 */
392
	public String getSettings()  {
393
		if(settings == null){
394
			throw new IllegalStateException("No SETTINGS set.");
395
		}
396
		return settings;
397
	}
398

    
399
	/**
400
	 *
401
	 * @author n.hoffmann
402
	 * @created Oct 19, 2009
403
	 * @version 1.0
404
	 */
405
	private class ResourceSelectionHistory extends SelectionHistory {
406
	    /*
407
	    * @see org.eclipse.ui.dialogs.FilteredItemsSelectionDialog.SelectionHistory#restoreItemFromMemento(org.eclipse.ui.IMemento)
408
	   	*/
409
		@Override
410
		protected Object restoreItemFromMemento(IMemento element) {
411
			return element.getString("resource"); //$NON-NLS-1$
412
	  	}
413
	  	/*
414
	  	 * @see org.eclipse.ui.dialogs.FilteredItemsSelectionDialog.SelectionHistory#storeItemToMemento(java.lang.Object,
415
	  	 *      org.eclipse.ui.IMemento)
416
	  	 */
417
		@Override
418
		protected void storeItemToMemento(Object item, IMemento element) {
419
			element.putString("resource", item.toString()); //$NON-NLS-1$
420
		}
421
	}
422

    
423
	/**
424
	 * <p>getNewWizardLinkText</p>
425
	 *
426
	 * @return a {@link java.lang.String} object.
427
	 */
428
	protected abstract String getNewWizardLinkText();
429

    
430
	/**
431
	 * <p>getNewEntityWizard</p>
432
	 * @param parameter
433
	 * @return a {@link eu.etaxonomy.taxeditor.newWizard.AbstractNewEntityWizard} object.
434
	 */
435
	protected abstract AbstractNewEntityWizard getNewEntityWizard(String parameter);
436

    
437
	public class FilteredCdmResourceLabelProvider extends LabelProvider {
438
		@Override
439
		public String getText(Object element) {
440
			if (element == null) {
441
				return null;
442
			}
443
			UuidAndTitleCache uuidAndTitleCache = (UuidAndTitleCache) element;
444
			String titleCache = uuidAndTitleCache.getTitleCache();
445
			if(PreferencesUtil.getPreferenceStore().getBoolean(IPreferenceKeys.SHOW_ID_IN_ENTITY_SELECTION_DIAOLOG)){
446
			    titleCache += " ["+uuidAndTitleCache.getId()+"]";
447
			}
448
            return titleCache;
449
		}
450
	};
451

    
452
	/* (non-Javadoc)
453
	* @see org.eclipse.ui.dialogs.FilteredItemsSelectionDialog#createExtendedContentArea(org.eclipse.swt.widgets.Composite)
454
	*/
455
	/** {@inheritDoc} */
456
	@Override
457
	protected Control createExtendedContentArea(Composite parent) {
458
		String newWizardLinkText = getNewWizardLinkText();
459
        if(newWizardLinkText != null){
460
			Link link = new Link(parent, SWT.NONE);
461
			link.setText(newWizardLinkText);
462
			link.addSelectionListener(getNewWizardLinkSelectionListener());
463
			return link;
464
		}
465
		return null;
466
	}
467

    
468
	protected SelectionListener getNewWizardLinkSelectionListener(){
469
		return new SelectionAdapter() {
470

    
471
			/* (non-Javadoc)
472
			 * @see org.eclipse.swt.events.SelectionAdapter#widgetSelected(org.eclipse.swt.events.SelectionEvent)
473
			 */
474
			@Override
475
			public void widgetSelected(SelectionEvent e) {
476

    
477
				AbstractNewEntityWizard wizard = getNewEntityWizard(e.text);
478

    
479
				wizard.init(null, null);
480
				if(wizard.getEntity() != null) {
481
					WizardDialog dialog = new WizardDialog(getShell(), wizard);
482
					int status = dialog.open();
483

    
484
					if (status == IStatus.OK) {
485

    
486
						T entity = (T) wizard.getEntity();
487
						refresh();
488
						setPattern(entity);
489
						getConversationHolder().bind();
490
					}
491
					//FIXME : Need to make sure this is a stable fix (ticket 3822)
492
					getConversationHolder().commit();
493
				}
494
			}
495
		};
496
	}
497

    
498
	/**
499
	 * <p>getConversationHolder</p>
500
	 *
501
	 * @return a {@link eu.etaxonomy.cdm.api.conversation.ConversationHolder} object.
502
	 */
503
	@Override
504
	public ConversationHolder getConversationHolder() {
505
		return conversation;
506
	}
507

    
508
	/** {@inheritDoc} */
509
	@Override
510
	public void update(CdmDataChangeMap changeEvents) {}
511

    
512
	/**
513
	 * Don't want to add for example a taxon or synonym to itself
514
	 * so filter the list to remove the taxon in question
515
	 * (<code>cdmBaseToBeFiltered</code>)
516
	 * so it is not available in the filtered list.
517
	 */
518
	private void filterExcludedObjects() {
519
		if (model != null && cdmBaseToBeFiltered != null) {
520

    
521
			UuidAndTitleCache uuidAndTitleCacheToRemove = null;
522

    
523
			for (UuidAndTitleCache uuidAndTitleCache : model){
524
				if ((cdmBaseToBeFiltered.getUuid()).equals(uuidAndTitleCache.getUuid())) {
525
					uuidAndTitleCacheToRemove = uuidAndTitleCache;
526
				}
527
			}
528
			model.remove(uuidAndTitleCacheToRemove);
529
		}
530
	}
531
}
(2-2/29)