Project

General

Profile

Download (14.8 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.model.common.UuidAndTitleCache;
49
import eu.etaxonomy.cdm.persistence.hibernate.CdmDataChangeMap;
50
import eu.etaxonomy.taxeditor.model.AbstractUtility;
51
import eu.etaxonomy.taxeditor.newWizard.AbstractNewEntityWizard;
52
import eu.etaxonomy.taxeditor.store.internal.TaxeditorStorePlugin;
53

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

    
64
	private final ConversationHolder conversation;
65

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

    
70
	protected T cdmBaseToBeFiltered;
71

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

    
89
		this.conversation = conversation;
90

    
91
		init();
92

    
93
		initModel();
94

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

    
100
		setListLabelProvider(createListLabelProvider());
101
		setDetailsLabelProvider(createDetailsLabelProvider());
102

    
103
		setSelectionHistory(new ResourceSelectionHistory());
104
	}
105

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

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

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

    
131
	}
132

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

    
144
		if (result == Window.CANCEL) {
145
			return null;
146
		}
147

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

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

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

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

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

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

    
208
		if (cdmObject instanceof IIdentifiableEntity) {
209
			return ((IIdentifiableEntity) cdmObject).getTitleCache();
210
		}
211

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

    
217

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

    
226
	/**
227
	 * <p>initModel</p>
228
	 */
229
	abstract protected void initModel();
230

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

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

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

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

    
263
		};
264
	}
265

    
266

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

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

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

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

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

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

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

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

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

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

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

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

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

    
435
	public class FilteredCdmResourceLabelProvider extends LabelProvider {
436
		@Override
437
        public String getText(Object element) {
438
			if (element == null) {
439
				return null;
440
			}
441
			return ((UuidAndTitleCache) element).getTitleCache();
442
		}
443
	};
444

    
445
	/* (non-Javadoc)
446
	* @see org.eclipse.ui.dialogs.FilteredItemsSelectionDialog#createExtendedContentArea(org.eclipse.swt.widgets.Composite)
447
	*/
448
	/** {@inheritDoc} */
449
	@Override
450
	protected Control createExtendedContentArea(Composite parent) {
451
		String newWizardLinkText = getNewWizardLinkText();
452
        if(newWizardLinkText != null){
453
			Link link = new Link(parent, SWT.NONE);
454
			link.setText(newWizardLinkText);
455
			link.addSelectionListener(getNewWizardLinkSelectionListener());
456
			return link;
457
		}
458
		return null;
459
	}
460

    
461
	protected SelectionListener getNewWizardLinkSelectionListener(){
462
		return new SelectionAdapter() {
463

    
464
			/* (non-Javadoc)
465
			 * @see org.eclipse.swt.events.SelectionAdapter#widgetSelected(org.eclipse.swt.events.SelectionEvent)
466
			 */
467
			@Override
468
			public void widgetSelected(SelectionEvent e) {
469

    
470
				AbstractNewEntityWizard wizard = getNewEntityWizard(e.text);
471

    
472
				wizard.init(null, null);
473
				WizardDialog dialog = new WizardDialog(getShell(), wizard);
474
				int status = dialog.open();
475

    
476
				if (status == IStatus.OK) {
477

    
478
					T entity = (T) wizard.getEntity();
479

    
480
//					addObjectToModel(teamOrPerson);
481
					refresh();
482
					setPattern(entity);
483
					getConversationHolder().bind();
484
					//FIXME : Need to make sure this is a stable fix (ticket 3822)
485
					getConversationHolder().commit();
486
				}
487
			}
488
		};
489
	}
490

    
491
	/**
492
	 * <p>getConversationHolder</p>
493
	 *
494
	 * @return a {@link eu.etaxonomy.cdm.api.conversation.ConversationHolder} object.
495
	 */
496
	@Override
497
    public ConversationHolder getConversationHolder() {
498
		return conversation;
499
	}
500

    
501
	/** {@inheritDoc} */
502
	@Override
503
    public void update(CdmDataChangeMap changeEvents) {}
504

    
505
	/**
506
	 * Don't want to add for example a taxon or synonym to itself
507
	 * so filter the list to remove the taxon in question
508
	 * (<code>cdmBaseToBeFiltered</code>)
509
	 * so it is not available in the filtered list.
510
	 */
511
	private void filterExcludedObjects() {
512
		if (model != null && cdmBaseToBeFiltered != null) {
513

    
514
			UuidAndTitleCache uuidAndTitleCacheToRemove = null;
515

    
516
			for (UuidAndTitleCache uuidAndTitleCache : model){
517
				if ((cdmBaseToBeFiltered.getUuid()).equals(uuidAndTitleCache.getUuid())) {
518
					uuidAndTitleCacheToRemove = uuidAndTitleCache;
519
				}
520
			}
521
			model.remove(uuidAndTitleCacheToRemove);
522
		}
523
	}
524
}
(2-2/25)