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