Project

General

Profile

Download (15.7 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.text.Collator;
14
import java.util.Comparator;
15
import java.util.HashSet;
16
import java.util.Iterator;
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.graphics.Cursor;
36
import org.eclipse.swt.widgets.Composite;
37
import org.eclipse.swt.widgets.Control;
38
import org.eclipse.swt.widgets.Link;
39
import org.eclipse.swt.widgets.Shell;
40
import org.eclipse.swt.widgets.Text;
41
import org.eclipse.ui.IMemento;
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
		CdmFilteredItemsSelectionDialog 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
	protected final int limitOfInitialElements = 100;
72

    
73
	protected T cdmBaseToBeFiltered;
74

    
75

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

    
93
		this.conversation = conversation;
94
		this.cdmBaseToBeFiltered = cdmObject;
95
		Cursor cursor = shell.getCursor();
96
		shell.setCursor(shell.getDisplay().getSystemCursor(SWT.CURSOR_WAIT));
97
		init();
98
		initModel();
99
		shell.setCursor(cursor);
100
		String objectTitle = getTitle(cdmObject);
101
//		if (objectTitle != null) {
102
//			setInitialPattern(objectTitle);
103
//		}
104

    
105
		setListLabelProvider(createListLabelProvider());
106
		setDetailsLabelProvider(createDetailsLabelProvider());
107

    
108
		setSelectionHistory(new ResourceSelectionHistory());
109
	}
110

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

    
122
	/**
123
	 *
124
	 * @return
125
	 */
126
	protected ILabelProvider createListLabelProvider() {
127
		return new FilteredCdmResourceLabelProvider();
128
	}
129

    
130
	/**
131
	 * Override in subclasses.
132
	 * Will run before initModel()
133
	 */
134
	protected void init() {
135

    
136
	}
137

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

    
149
		if (result == Window.CANCEL) {
150
			return null;
151
		}
152

    
153
		UUID uuid = dialog.getSelectedUuidAndTitleCache().getUuid();
154
		if(uuid == null){
155
			return null;
156
		}
157
		return dialog.getCdmObjectByUuid(uuid);
158
	}
159

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

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

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

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

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

    
213
		if (cdmObject instanceof IIdentifiableEntity) {
214
			return ((IIdentifiableEntity) cdmObject).getTitleCache();
215
		}
216

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

    
222

    
223
	/** {@inheritDoc} */
224
	@Override
225
	public void refresh() {
226
		super.refresh();
227
	}
228

    
229

    
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
//			MessagingUtils.error(getClass(), e);
285
//		} catch (NoSuchFieldException e) {
286
//			MessagingUtils.error(getClass(), e);
287
//		} catch (IllegalArgumentException e) {
288
//			MessagingUtils.error(getClass(), e);
289
//		} catch (IllegalAccessException e) {
290
//			MessagingUtils.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

    
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
				filterExcludedObjects();
314
				Iterator<UuidAndTitleCache<T>> iterator = model.iterator();
315
				UuidAndTitleCache<T> element;
316
				while(iterator.hasNext()){
317
				    element = iterator.next();
318
					contentProvider.add(element, itemsFilter);
319
					if (progressMonitor.isCanceled()) {
320
						throw new OperationCanceledException();
321
					}
322
					progressMonitor.worked(1);
323
				}
324
			}else{
325
				MessagingUtils.warn(getClass(), "Model for Filtered Selection is null:" + this.getClass().getSimpleName());
326
			}
327
		}
328
		finally {
329
			progressMonitor.done();
330
		}
331
	}
332

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

    
341
		if (settings == null) {
342
			settings = TaxeditorStorePlugin.getDefault().getDialogSettings().addNewSection(getSettings());
343
		}
344
		return settings;
345
	}
346

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

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

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

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

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

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

    
427
	/**
428
	 * <p>getNewWizardLinkText</p>
429
	 *
430
	 * @return a {@link java.lang.String} object.
431
	 */
432
	protected abstract String getNewWizardLinkText();
433

    
434
	/**
435
	 * <p>getNewEntityWizard</p>
436
	 * @param parameter
437
	 * @return a {@link eu.etaxonomy.taxeditor.newWizard.AbstractNewEntityWizard} object.
438
	 */
439
	protected abstract AbstractNewEntityWizard getNewEntityWizard(String parameter);
440

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

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

    
472
	protected SelectionListener getNewWizardLinkSelectionListener(){
473
		return new SelectionAdapter() {
474

    
475
			/* (non-Javadoc)
476
			 * @see org.eclipse.swt.events.SelectionAdapter#widgetSelected(org.eclipse.swt.events.SelectionEvent)
477
			 */
478
			@Override
479
			public void widgetSelected(SelectionEvent e) {
480

    
481
			    AbstractNewEntityWizard wizard = getNewEntityWizard(e.text);
482
			    if(wizard!=null){
483
			        wizard.init(null, null);
484
			        if(wizard.getEntity() != null) {
485
			            WizardDialog dialog = new WizardDialog(getShell(), wizard);
486
			            int status = dialog.open();
487

    
488
			            if (status == IStatus.OK) {
489

    
490
			                T entity = (T) wizard.getEntity();
491
			               // model.add(new UuidAndTitleCache<T>(entity.getUuid(), entity.getId(), getTitle(entity)));
492
			                refresh();
493
			                setPattern(entity);
494
			                getConversationHolder().bind();
495
			            }
496
			            //FIXME : Need to make sure this is a stable fix (ticket 3822)
497
			            getConversationHolder().commit();
498
			        }
499
			    }
500
			}
501
		};
502
	}
503

    
504
	/**
505
	 * <p>getConversationHolder</p>
506
	 *
507
	 * @return a {@link eu.etaxonomy.cdm.api.conversation.ConversationHolder} object.
508
	 */
509
	@Override
510
	public ConversationHolder getConversationHolder() {
511
		return conversation;
512
	}
513

    
514
	/** {@inheritDoc} */
515
	@Override
516
	public void update(CdmDataChangeMap changeEvents) {}
517

    
518
	/**
519
	 * Don't want to add for example a taxon or synonym to itself
520
	 * so filter the list to remove the taxon in question
521
	 * (<code>cdmBaseToBeFiltered</code>)
522
	 * so it is not available in the filtered list.
523
	 */
524
	private void filterExcludedObjects() {
525
		if (model != null && cdmBaseToBeFiltered != null) {
526

    
527
			UuidAndTitleCache uuidAndTitleCacheToRemove = null;
528

    
529
			for (UuidAndTitleCache uuidAndTitleCache : model){
530
				if ((cdmBaseToBeFiltered.getUuid()).equals(uuidAndTitleCache.getUuid())) {
531
					uuidAndTitleCacheToRemove = uuidAndTitleCache;
532
				}
533
			}
534
			model.remove(uuidAndTitleCacheToRemove);
535
		}
536
	}
537
}
(2-2/34)