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