3 * Copyright (C) 2007 EDIT
4 * European Distributed Institute of Taxonomy
5 * http://www.e-taxonomy.eu
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.
11 package eu
.etaxonomy
.taxeditor
.ui
.dialog
.selection
;
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
.Iterator
;
18 import java
.util
.List
;
20 import java
.util
.UUID
;
22 import org
.eclipse
.core
.runtime
.CoreException
;
23 import org
.eclipse
.core
.runtime
.IProgressMonitor
;
24 import org
.eclipse
.core
.runtime
.IStatus
;
25 import org
.eclipse
.core
.runtime
.OperationCanceledException
;
26 import org
.eclipse
.core
.runtime
.Status
;
27 import org
.eclipse
.jface
.dialogs
.IDialogSettings
;
28 import org
.eclipse
.jface
.viewers
.ILabelProvider
;
29 import org
.eclipse
.jface
.viewers
.LabelProvider
;
30 import org
.eclipse
.jface
.window
.Window
;
31 import org
.eclipse
.jface
.wizard
.WizardDialog
;
32 import org
.eclipse
.swt
.SWT
;
33 import org
.eclipse
.swt
.events
.SelectionAdapter
;
34 import org
.eclipse
.swt
.events
.SelectionEvent
;
35 import org
.eclipse
.swt
.events
.SelectionListener
;
36 import org
.eclipse
.swt
.graphics
.Cursor
;
37 import org
.eclipse
.swt
.widgets
.Composite
;
38 import org
.eclipse
.swt
.widgets
.Control
;
39 import org
.eclipse
.swt
.widgets
.Link
;
40 import org
.eclipse
.swt
.widgets
.Shell
;
41 import org
.eclipse
.swt
.widgets
.Text
;
42 import org
.eclipse
.ui
.IMemento
;
44 import eu
.etaxonomy
.cdm
.api
.conversation
.ConversationHolder
;
45 import eu
.etaxonomy
.cdm
.api
.conversation
.IConversationEnabled
;
46 import eu
.etaxonomy
.cdm
.model
.common
.CdmBase
;
47 import eu
.etaxonomy
.cdm
.model
.common
.ICdmBase
;
48 import eu
.etaxonomy
.cdm
.model
.common
.IIdentifiableEntity
;
49 import eu
.etaxonomy
.cdm
.persistence
.dto
.UuidAndTitleCache
;
50 import eu
.etaxonomy
.cdm
.persistence
.hibernate
.CdmDataChangeMap
;
51 import eu
.etaxonomy
.taxeditor
.model
.MessagingUtils
;
52 import eu
.etaxonomy
.taxeditor
.newWizard
.AbstractNewEntityWizard
;
53 import eu
.etaxonomy
.taxeditor
.preference
.IPreferenceKeys
;
54 import eu
.etaxonomy
.taxeditor
.preference
.PreferencesUtil
;
55 import eu
.etaxonomy
.taxeditor
.store
.internal
.TaxeditorStorePlugin
;
58 * <p>Abstract AbstractFilteredCdmResourceSelectionDialog class.</p>
64 public abstract class AbstractFilteredCdmResourceSelectionDialog
<T
extends ICdmBase
> extends
65 CdmFilteredItemsSelectionDialog
implements IConversationEnabled
{
67 private final ConversationHolder conversation
;
69 protected List
<UuidAndTitleCache
<T
>> model
;
70 private final Set
<T
> transientCdmObjects
= new HashSet
<T
>();
71 private final String settings
;
72 protected final int limitOfInitialElements
= 100;
74 protected T cdmBaseToBeFiltered
;
78 * <p>Constructor for AbstractFilteredCdmResourceSelectionDialog.</p>
80 * @param shell a {@link org.eclipse.swt.widgets.Shell} object.
82 * @param title a {@link java.lang.String} object.
83 * @param multi a boolean.
84 * @param settings a {@link java.lang.String} object.
85 * @param cdmObject a T object.
86 * @param <T> a T object.
88 protected AbstractFilteredCdmResourceSelectionDialog(Shell shell
, ConversationHolder conversation
, String title
, boolean multi
, String settings
, T cdmObject
) {
91 setMessage("Use * for wildcard, or ? to see all entries");
92 this.settings
= settings
;
94 this.conversation
= conversation
;
95 this.cdmBaseToBeFiltered
= cdmObject
;
96 Cursor cursor
= shell
.getCursor();
97 shell
.setCursor(shell
.getDisplay().getSystemCursor(SWT
.CURSOR_WAIT
));
100 shell
.setCursor(cursor
);
101 String objectTitle
= getTitle(cdmObject
);
102 if (objectTitle
!= null) {
103 setInitialPattern(objectTitle
);
106 setListLabelProvider(createListLabelProvider());
107 setDetailsLabelProvider(createDetailsLabelProvider());
109 setSelectionHistory(new ResourceSelectionHistory());
113 * By default, we are returning the standard list label provider
115 * Override in subclasses if you want different behavior
119 protected ILabelProvider
createDetailsLabelProvider() {
120 return createListLabelProvider();
127 protected ILabelProvider
createListLabelProvider() {
128 return new FilteredCdmResourceLabelProvider();
132 * Override in subclasses.
133 * Will run before initModel()
135 protected void init() {
140 * <p>getSelectionFromDialog</p>
142 * @param dialog a {@link eu.etaxonomy.taxeditor.ui.dialog.selection.AbstractFilteredCdmResourceSelectionDialog} object.
143 * @param <TYPE> a TYPE object.
144 * @return a TYPE object.
146 protected static <TYPE
extends CdmBase
> TYPE
getSelectionFromDialog(AbstractFilteredCdmResourceSelectionDialog
<TYPE
> dialog
) {
147 //dialog.setInitialPattern("");
148 int result
= dialog
.open();
150 if (result
== Window
.CANCEL
) {
154 UUID uuid
= dialog
.getSelectedUuidAndTitleCache().getUuid();
158 return dialog
.getCdmObjectByUuid(uuid
);
162 * Check if object was created during the life of this dialog. If not,
163 * retrieve it from the CdmStore.
165 * @param cdmUuid a {@link java.util.UUID} object.
166 * @return a T object.
168 protected T
getCdmObjectByUuid(UUID cdmUuid
) {
169 for (T cdmObject
: transientCdmObjects
) {
170 if (cdmObject
.getUuid().equals(cdmUuid
)) {
174 return getPersistentObject(cdmUuid
);
178 * <p>getPersistentObject</p>
180 * @param uuid a {@link java.util.UUID} object.
181 * @return a T object.
183 abstract protected T
getPersistentObject(UUID uuid
);
188 // protected void addObjectToModel(T cdmObject) {
189 // model.add(new UuidAndTitleCache(cdmObject.getClass(), cdmObject.getUuid(), getTitle(cdmObject)));
190 // transientCdmObjects.add(cdmObject);
194 * <p>isObjectTransient</p>
196 * @param cdmObject a T object.
199 protected boolean isObjectTransient(T cdmObject
) {
200 return (getPersistentObject(cdmObject
.getUuid()) == null);
206 * @param cdmObject a T object.
207 * @return a {@link java.lang.String} object.
209 protected String
getTitle(T cdmObject
) {
210 if(cdmObject
== null){
214 if (cdmObject
instanceof IIdentifiableEntity
) {
215 return ((IIdentifiableEntity
) cdmObject
).getTitleCache();
218 throw new IllegalArgumentException("Generic method only" +
219 " supports cdmObject of type IIdentifiableEntity." +
220 " Please implement specific method in subclass.");
226 public void refresh() {
233 * @see org.eclipse.ui.dialogs.FilteredItemsSelectionDialog#createFilter()
237 protected ItemsFilter
createFilter() {
238 return new ItemsFilter() {
241 * Always returns false to enforce refiltering even if the pattern is equal
244 public boolean equalsFilter(ItemsFilter filter
) {
249 public boolean isConsistentItem(Object item
) {
254 public boolean matchItem(Object item
) {
256 if(item
instanceof UuidAndTitleCache
){
257 text
= ((UuidAndTitleCache
) item
).getTitleCache();
258 }else if(item
instanceof String
){
259 text
= (String
) item
;
261 return text
!= null ?
matches(text
) : false;
269 * Set the filter input to the Agent's title cache
271 * @param cdmObject a T object.
273 protected void setPattern(T cdmObject
) {
274 // FilteredSelection does some very tricky caching to make sure it
275 // runs with high performance.
276 // This works for most use cases, but we want to change the model while the dialog is open
277 // and all the clever caching prevents the content provider from knowing that the model has changed
278 // I am aware, that this is a hack, but the FilteredSelectionDialog API does not offer a convenient
279 // way to solve the problem.
281 Field lastCompletedFilter
= this.getClass().getSuperclass().getSuperclass().getDeclaredField("lastCompletedFilter");
282 lastCompletedFilter
.setAccessible(true);
283 lastCompletedFilter
.set(this, null);
284 } catch (SecurityException e
) {
285 MessagingUtils
.error(getClass(), e
);
286 } catch (NoSuchFieldException e
) {
287 MessagingUtils
.error(getClass(), e
);
288 } catch (IllegalArgumentException e
) {
289 MessagingUtils
.error(getClass(), e
);
290 } catch (IllegalAccessException e
) {
291 MessagingUtils
.error(getClass(), e
);
294 // this also is not the nicest way to do it.
295 // I am still amazed, that FilteredSelectionDialog does not offer any methods to change its data
296 // once it was opened. Am I doing it wrong?
297 String pattern
= getTitle(cdmObject
);
298 ((Text
) getPatternControl()).setText(pattern
);
304 * @see org.eclipse.ui.dialogs.FilteredItemsSelectionDialog#fillContentProvider(org.eclipse.ui.dialogs.FilteredItemsSelectionDialog.AbstractContentProvider, org.eclipse.ui.dialogs.FilteredItemsSelectionDialog.ItemsFilter, org.eclipse.core.runtime.IProgressMonitor)
308 protected void fillContentProvider(AbstractContentProvider contentProvider
,
309 ItemsFilter itemsFilter
, IProgressMonitor progressMonitor
)
310 throws CoreException
{
313 progressMonitor
.beginTask("Looking for entities", model
.size());
314 filterExcludedObjects();
315 Iterator
<UuidAndTitleCache
<T
>> iterator
= model
.iterator();
316 UuidAndTitleCache
<T
> element
;
317 while(iterator
.hasNext()){
318 element
= iterator
.next();
319 contentProvider
.add(element
, itemsFilter
);
320 if (progressMonitor
.isCanceled()) {
321 throw new OperationCanceledException();
323 progressMonitor
.worked(1);
326 MessagingUtils
.warn(getClass(), "Model for Filtered Selection is null:" + this.getClass().getSimpleName());
330 progressMonitor
.done();
335 * @see org.eclipse.ui.dialogs.FilteredItemsSelectionDialog#getDialogSettings()
339 protected IDialogSettings
getDialogSettings() {
340 IDialogSettings settings
= TaxeditorStorePlugin
.getDefault().getDialogSettings().getSection(getSettings());
342 if (settings
== null) {
343 settings
= TaxeditorStorePlugin
.getDefault().getDialogSettings().addNewSection(getSettings());
349 * @see org.eclipse.ui.dialogs.FilteredItemsSelectionDialog#getElementName(java.lang.Object)
353 public String
getElementName(Object item
) {
354 return ((UuidAndTitleCache
) item
).getTitleCache();
358 * @see org.eclipse.ui.dialogs.FilteredItemsSelectionDialog#getItemsComparator()
362 protected Comparator
getItemsComparator() {
363 return new Comparator
<UuidAndTitleCache
>() {
365 public int compare(UuidAndTitleCache entity1
,
366 UuidAndTitleCache entity2
) {
367 Collator collator
= Collator
.getInstance();
368 return collator
.compare(entity1
.getTitleCache(), entity2
.getTitleCache());
374 * @see org.eclipse.ui.dialogs.FilteredItemsSelectionDialog#validateItem(java.lang.Object)
378 protected IStatus
validateItem(Object item
) {
379 return Status
.OK_STATUS
;
383 * <p>getSelectedUuidAndTitleCache</p>
385 * @return a {@link eu.etaxonomy.cdm.model.common.UuidAndTitleCache} object.
387 protected UuidAndTitleCache
getSelectedUuidAndTitleCache() {
388 Object
[] result
= getResult();
389 return result
[0] == null ?
null : (UuidAndTitleCache
) result
[0];
393 * <p>Getter for the field <code>settings</code>.</p>
395 * @return a {@link java.lang.String} object.
397 public String
getSettings() {
398 if(settings
== null){
399 throw new IllegalStateException("No SETTINGS set.");
407 * @created Oct 19, 2009
410 private class ResourceSelectionHistory
extends SelectionHistory
{
412 * @see org.eclipse.ui.dialogs.FilteredItemsSelectionDialog.SelectionHistory#restoreItemFromMemento(org.eclipse.ui.IMemento)
415 protected Object
restoreItemFromMemento(IMemento element
) {
416 return element
.getString("resource"); //$NON-NLS-1$
419 * @see org.eclipse.ui.dialogs.FilteredItemsSelectionDialog.SelectionHistory#storeItemToMemento(java.lang.Object,
420 * org.eclipse.ui.IMemento)
423 protected void storeItemToMemento(Object item
, IMemento element
) {
424 element
.putString("resource", item
.toString()); //$NON-NLS-1$
429 * <p>getNewWizardLinkText</p>
431 * @return a {@link java.lang.String} object.
433 protected abstract String
getNewWizardLinkText();
436 * <p>getNewEntityWizard</p>
438 * @return a {@link eu.etaxonomy.taxeditor.newWizard.AbstractNewEntityWizard} object.
440 protected abstract AbstractNewEntityWizard
getNewEntityWizard(String parameter
);
442 public class FilteredCdmResourceLabelProvider
extends LabelProvider
{
444 public String
getText(Object element
) {
445 if (element
== null) {
448 UuidAndTitleCache uuidAndTitleCache
= (UuidAndTitleCache
) element
;
449 String titleCache
= uuidAndTitleCache
.getTitleCache();
450 if(PreferencesUtil
.getPreferenceStore().getBoolean(IPreferenceKeys
.SHOW_ID_IN_ENTITY_SELECTION_DIAOLOG
)){
451 titleCache
+= " ["+uuidAndTitleCache
.getId()+"]";
458 * @see org.eclipse.ui.dialogs.FilteredItemsSelectionDialog#createExtendedContentArea(org.eclipse.swt.widgets.Composite)
462 protected Control
createExtendedContentArea(Composite parent
) {
463 String newWizardLinkText
= getNewWizardLinkText();
464 if(newWizardLinkText
!= null){
465 Link link
= new Link(parent
, SWT
.NONE
);
466 link
.setText(newWizardLinkText
);
467 link
.addSelectionListener(getNewWizardLinkSelectionListener());
473 protected SelectionListener
getNewWizardLinkSelectionListener(){
474 return new SelectionAdapter() {
477 * @see org.eclipse.swt.events.SelectionAdapter#widgetSelected(org.eclipse.swt.events.SelectionEvent)
480 public void widgetSelected(SelectionEvent e
) {
482 AbstractNewEntityWizard wizard
= getNewEntityWizard(e
.text
);
484 wizard
.init(null, null);
485 if(wizard
.getEntity() != null) {
486 WizardDialog dialog
= new WizardDialog(getShell(), wizard
);
487 int status
= dialog
.open();
489 if (status
== IStatus
.OK
) {
491 T entity
= (T
) wizard
.getEntity();
492 // model.add(new UuidAndTitleCache<T>(entity.getUuid(), entity.getId(), getTitle(entity)));
495 getConversationHolder().bind();
497 //FIXME : Need to make sure this is a stable fix (ticket 3822)
498 getConversationHolder().commit();
506 * <p>getConversationHolder</p>
508 * @return a {@link eu.etaxonomy.cdm.api.conversation.ConversationHolder} object.
511 public ConversationHolder
getConversationHolder() {
517 public void update(CdmDataChangeMap changeEvents
) {}
520 * Don't want to add for example a taxon or synonym to itself
521 * so filter the list to remove the taxon in question
522 * (<code>cdmBaseToBeFiltered</code>)
523 * so it is not available in the filtered list.
525 private void filterExcludedObjects() {
526 if (model
!= null && cdmBaseToBeFiltered
!= null) {
528 UuidAndTitleCache uuidAndTitleCacheToRemove
= null;
530 for (UuidAndTitleCache uuidAndTitleCache
: model
){
531 if ((cdmBaseToBeFiltered
.getUuid()).equals(uuidAndTitleCache
.getUuid())) {
532 uuidAndTitleCacheToRemove
= uuidAndTitleCache
;
535 model
.remove(uuidAndTitleCacheToRemove
);