avoid NPE when no new buttons in selection dialog
[taxeditor.git] / eu.etaxonomy.taxeditor.store / src / main / java / eu / etaxonomy / taxeditor / ui / dialog / selection / AbstractFilteredCdmResourceSelectionDialog.java
1 /**
2 * Copyright (C) 2007 EDIT
3 * European Distributed Institute of Taxonomy
4 * http://www.e-taxonomy.eu
5 *
6 * The contents of this file are subject to the Mozilla Public License Version 1.1
7 * See LICENSE.TXT at the top of this package for the full license terms.
8 */
9
10 package eu.etaxonomy.taxeditor.ui.dialog.selection;
11
12 import java.text.Collator;
13 import java.util.ArrayList;
14 import java.util.Collections;
15 import java.util.Comparator;
16 import java.util.HashSet;
17 import java.util.Iterator;
18 import java.util.List;
19 import java.util.Set;
20 import java.util.UUID;
21
22 import org.apache.commons.lang.StringUtils;
23 import org.eclipse.core.runtime.IProgressMonitor;
24 import org.eclipse.core.runtime.IStatus;
25 import org.eclipse.jface.dialogs.IDialogSettings;
26 import org.eclipse.jface.viewers.CellEditor.LayoutData;
27 import org.eclipse.jface.viewers.ILabelProvider;
28 import org.eclipse.jface.viewers.LabelProvider;
29 import org.eclipse.jface.viewers.StructuredSelection;
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.layout.GridData;
38 import org.eclipse.swt.layout.GridLayout;
39 import org.eclipse.swt.widgets.Button;
40 import org.eclipse.swt.widgets.Composite;
41 import org.eclipse.swt.widgets.Control;
42 import org.eclipse.swt.widgets.Label;
43 import org.eclipse.swt.widgets.Shell;
44 import org.eclipse.swt.widgets.Text;
45
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.taxeditor.l10n.Messages;
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;
56
57 /**
58 * <p>Abstract AbstractFilteredCdmResourceSelectionDialog class.</p>
59 *
60 * @author n.hoffmann
61 * @created 04.06.2009
62 * @version 1.0
63 */
64 public abstract class AbstractFilteredCdmResourceSelectionDialog<T extends ICdmBase> extends
65 SearchDialog {//implements IConversationEnabled {
66
67 // private final ConversationHolder conversation = null;
68
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;
73
74 private T selectedObject;
75
76 protected T cdmBaseToBeFiltered;
77
78
79 /**
80 * <p>Constructor for AbstractFilteredCdmResourceSelectionDialog.</p>
81 *
82 * @param shell a {@link org.eclipse.swt.widgets.Shell} object.
83 * @param conversation
84 * @param title a {@link java.lang.String} object.
85 * @param multi a boolean.
86 * @param settings a {@link java.lang.String} object.
87 * @param cdmObject a T object.
88 * @param <T> a T object.
89 */
90 protected AbstractFilteredCdmResourceSelectionDialog(Shell shell, //ConversationHolder conversation,
91 String title, boolean multi, String settings, T cdmObject) {
92 super(shell, multi);
93 setShellStyle(SWT.DIALOG_TRIM);
94 setTitle(title);
95 setMessage(Messages.SearchDialog_patternLabel);
96 this.settings = settings;
97
98 this.cdmBaseToBeFiltered = cdmObject;
99 Cursor cursor = shell.getCursor();
100 shell.setCursor(shell.getDisplay().getSystemCursor(SWT.CURSOR_WAIT));
101 init();
102 shell.setCursor(cursor);
103 setListLabelProvider(createListLabelProvider());
104
105 }
106
107 /**
108 * By default, we are returning the standard list label provider
109 *
110 * Override in subclasses if you want different behavior
111 *
112 * @return
113 */
114 protected ILabelProvider createDetailsLabelProvider() {
115 return createListLabelProvider();
116 }
117
118 /**
119 *
120 * @return
121 */
122 protected ILabelProvider createListLabelProvider() {
123 return new FilteredCdmResourceLabelProvider();
124 }
125
126 /**
127 * Override in subclasses.
128 * Will run before initModel()
129 */
130 protected void init() {
131
132 }
133
134 /**
135 * <p>getSelectionFromDialog</p>
136 *
137 * @param dialog a {@link eu.etaxonomy.taxeditor.ui.dialog.selection.AbstractFilteredCdmResourceSelectionDialog} object.
138 * @param <TYPE> a TYPE object.
139 * @return a TYPE object.
140 */
141 protected static <TYPE extends CdmBase> TYPE getSelectionFromDialog(AbstractFilteredCdmResourceSelectionDialog<TYPE> dialog) {
142 int result = dialog.open();
143
144 if (result == Window.CANCEL) {
145 return null;
146 }
147
148 UuidAndTitleCache uuid = dialog.getSelectedUuidAndTitleCache();
149 if(uuid == null){
150 return null;
151 }
152 return dialog.getCdmObjectByUuid(uuid.getUuid());
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 /**
181 * <p>isObjectTransient</p>
182 *
183 * @param cdmObject a T object.
184 * @return a boolean.
185 */
186 protected boolean isObjectTransient(T cdmObject) {
187 return (getPersistentObject(cdmObject.getUuid()) == null);
188 }
189
190 /**
191 * <p>getTitle</p>
192 *
193 * @param cdmObject a T object.
194 * @return a {@link java.lang.String} object.
195 */
196 protected String getTitle(T cdmObject) {
197 if(cdmObject == null){
198 return "";
199 }
200
201 if (cdmObject instanceof IIdentifiableEntity) {
202 return ((IIdentifiableEntity) cdmObject).getTitleCache();
203 }
204
205 throw new IllegalArgumentException("Generic method only" +
206 " supports cdmObject of type IIdentifiableEntity." +
207 " Please implement specific method in subclass.");
208 }
209
210
211
212 /**
213 * Set the filter input to the Agent's title cache
214 *
215 * @param cdmObject a T object.
216 */
217 protected void setPattern(T cdmObject) {
218 String pattern = getTitle(cdmObject);
219 getSearchField().setText(pattern);
220 }
221
222
223
224 /* (non-Javadoc)
225 * @see org.eclipse.ui.dialogs.FilteredItemsSelectionDialog#fillContentProvider(org.eclipse.ui.dialogs.FilteredItemsSelectionDialog.AbstractContentProvider, org.eclipse.ui.dialogs.FilteredItemsSelectionDialog.ItemsFilter, org.eclipse.core.runtime.IProgressMonitor)
226 */
227 /** {@inheritDoc} */
228
229 @Override
230 protected void fillContentProvider(IProgressMonitor progressMonitor)
231 {
232 try {
233 if (model == null){
234 model = new ArrayList<UuidAndTitleCache<T>>();
235 }
236 if(model != null){
237 if (progressMonitor != null){
238 progressMonitor.beginTask("Looking for entities", model.size());
239 }
240 sort();
241
242 contentProvider.reset();
243 Iterator<UuidAndTitleCache<T>> iterator = model.iterator();
244 UuidAndTitleCache<T> element;
245 while(iterator.hasNext()){
246 element = iterator.next();
247 if (!element.equals(cdmBaseToBeFiltered)){
248 contentProvider.add(element);
249 }
250 if (progressMonitor != null){
251 if (progressMonitor.isCanceled()) {
252 return;
253 }
254 progressMonitor.worked(1);
255 }
256 }
257 this.refresh();
258 }else{
259
260 MessagingUtils.warn(getClass(), "Model for Filtered Selection is null:" + this.getClass().getSimpleName());
261 }
262 }
263 finally {
264 if (progressMonitor != null) {
265 progressMonitor.done();
266 }
267 }
268 }
269
270
271 protected void sort() {
272 Collections.sort(model, getItemsComparator());
273 }
274
275 /* (non-Javadoc)
276 * @see org.eclipse.ui.dialogs.FilteredItemsSelectionDialog#getDialogSettings()
277 */
278 /** {@inheritDoc} */
279
280 protected IDialogSettings getDialogSettings() {
281 IDialogSettings settings = TaxeditorStorePlugin.getDefault().getDialogSettings().getSection(getSettings());
282
283 if (settings == null) {
284 settings = TaxeditorStorePlugin.getDefault().getDialogSettings().addNewSection(getSettings());
285 }
286 return settings;
287 }
288
289 /* (non-Javadoc)
290 * @see org.eclipse.ui.dialogs.FilteredItemsSelectionDialog#getElementName(java.lang.Object)
291 */
292 /** {@inheritDoc} */
293
294 public String getElementName(Object item) {
295 return ((UuidAndTitleCache) item).getTitleCache();
296 }
297
298 /* (non-Javadoc)
299 * @see org.eclipse.ui.dialogs.FilteredItemsSelectionDialog#getItemsComparator()
300 */
301 /** {@inheritDoc} */
302
303 @Override
304 protected Comparator getItemsComparator() {
305 return new Comparator<UuidAndTitleCache>() {
306 @Override
307 public int compare(UuidAndTitleCache entity1,
308 UuidAndTitleCache entity2) {
309 Collator collator = Collator.getInstance();
310 if (entity1 == entity2){
311 return 0;
312 }
313
314 if (entity1 == null && entity2 != null){
315 return -1;
316 }
317 if (entity2 == null && entity1 != null){
318 return 1;
319 }
320 if (entity1.getUuid().equals(entity2.getUuid())){
321 return 0;
322 }
323 if (entity1.getTitleCache() == null && entity2.getTitleCache() != null){
324 return -1;
325 }
326 if (entity2.getTitleCache() == null){
327 return 1;
328 }
329 int result = collator.compare(entity1.getTitleCache(), entity2.getTitleCache());
330 if (result == 0){
331 result = entity1.getUuid().compareTo(entity2.getUuid());
332 }
333 return result;
334 }
335 };
336 }
337
338
339 /**
340 * <p>getSelectedUuidAndTitleCache</p>
341 *
342 * @return a {@link eu.etaxonomy.cdm.model.common.UuidAndTitleCache} object.
343 */
344 protected UuidAndTitleCache getSelectedUuidAndTitleCache() {
345 Object result = getResult();
346 if (result instanceof UuidAndTitleCache){
347 return (UuidAndTitleCache) result;
348 }
349 return null;
350 }
351
352 /**
353 * @return
354 */
355 private Object getResult() {
356 StructuredSelection selection = getCurrentSelection();
357 if (selection == null){
358 return null;
359 }
360 return selection.getFirstElement();
361 }
362
363 /**
364 * <p>Getter for the field <code>settings</code>.</p>
365 *
366 * @return a {@link java.lang.String} object.
367 */
368 public String getSettings() {
369 if(settings == null){
370 throw new IllegalStateException("No SETTINGS set.");
371 }
372 return settings;
373 }
374
375
376
377 /**
378 * <p>getNewWizardLinkText</p>
379 *
380 * @return a {@link java.lang.String} object.
381 */
382 protected abstract String[] getNewWizardText();
383
384 /**
385 * <p>getNewEntityWizard</p>
386 * @param parameter
387 * @return a {@link eu.etaxonomy.taxeditor.newWizard.AbstractNewEntityWizard} object.
388 */
389 protected abstract AbstractNewEntityWizard getNewEntityWizard(String parameter);
390
391 public class FilteredCdmResourceLabelProvider extends LabelProvider {
392 @Override
393 public String getText(Object element) {
394 if (element == null) {
395 return null;
396 }
397 UuidAndTitleCache uuidAndTitleCache = (UuidAndTitleCache) element;
398 String titleCache = uuidAndTitleCache.getTitleCache();
399 if(PreferencesUtil.getPreferenceStore().getBoolean(IPreferenceKeys.SHOW_ID_IN_ENTITY_SELECTION_DIAOLOG)){
400 titleCache += " ["+uuidAndTitleCache.getId()+"]";
401 }
402 return titleCache;
403 }
404 };
405
406 /* (non-Javadoc)
407 * @see org.eclipse.ui.dialogs.FilteredItemsSelectionDialog#createExtendedContentArea(org.eclipse.swt.widgets.Composite)
408 */
409 /** {@inheritDoc} */
410
411 // @Override
412 // protected Control createExtendedContentArea(Composite parent) {
413 // String newWizardLinkText = getNewWizardLinkText();
414 //// if(newWizardLinkText != null){
415 //// newButton1 = this.createButton(this.getShell(), new_id, newWizardLinkText, false);
416 ////
417 //// newButton1.addSelectionListener(getNewWizardLinkSelectionListener());
418 //// return newButton1;
419 //// }
420 // return null;
421 // }
422
423 @Override
424 protected void createButtonsForButtonBar(Composite parent) {
425 String[] newButtonText = getNewWizardText();
426
427 if (newButtonText!= null){
428 this.newButton1 = createButton(parent, this.new_id, newButtonText[0], false);
429 newButton1.addSelectionListener(getNewWizardButtonSelectionListener());
430
431
432 if (newButtonText.length > 1){
433 newButton2 = createButton(parent, this.new_id2, newButtonText[1], false);
434 newButton2.addSelectionListener(getNewWizardButtonSelectionListener());
435
436 }
437
438 }
439 Button space = createButton(parent, this.space_id, " ", false);
440 space.setEnabled(false);
441 space.setVisible(false);
442 GridData gridData = new GridData();
443 gridData.grabExcessHorizontalSpace = false;
444 gridData.widthHint = 3;
445 space.setLayoutData(gridData);
446 GridLayout gridLayout = new GridLayout();
447 gridLayout.makeColumnsEqualWidth= false;
448 if (newButtonText != null){
449 gridLayout.numColumns=newButtonText.length+2;
450 }else{
451 gridLayout.numColumns=2;
452 }
453 parent.setLayout(gridLayout);
454
455 super.createButtonsForButtonBar(parent);
456 }
457
458 protected SelectionListener getNewWizardButtonSelectionListener(){
459 return new SelectionAdapter() {
460
461 /* (non-Javadoc)
462 * @see org.eclipse.swt.events.SelectionAdapter#widgetSelected(org.eclipse.swt.events.SelectionEvent)
463 */
464 @Override
465 public void widgetSelected(SelectionEvent e) {
466 Object source = e.getSource();
467 String text = null;
468 if (source instanceof Button){
469 Button sourceButton = (Button) source;
470 text = sourceButton.getText();
471 }
472 AbstractNewEntityWizard wizard = getNewEntityWizard(text);
473 if(wizard!=null){
474 wizard.init(null, null);
475 if(wizard.getEntity() != null) {
476 WizardDialog dialog = new WizardDialog(getShell(), wizard);
477 int status = dialog.open();
478
479 if (status == IStatus.OK) {
480
481 T entity = (T) wizard.getEntity();
482 refresh();
483 setPattern(entity);
484 // if (getConversationHolder() != null){
485 // getConversationHolder().bind();
486 // }
487 }
488 //FIXME : Need to make sure this is a stable fix (ticket 3822)
489 // if (getConversationHolder() != null){
490 // getConversationHolder().commit();
491 // }
492 }
493 }
494 }
495 };
496 }
497
498 /**
499 * <p>getConversationHolder</p>
500 *
501 * @return a {@link eu.etaxonomy.cdm.api.conversation.ConversationHolder} object.
502 // */
503 // @Override
504 // public ConversationHolder getConversationHolder() {
505 // return conversation;
506 // }
507
508 /** {@inheritDoc} */
509 // @Override
510 // public void update(CdmDataChangeMap changeEvents) {}
511
512 /**
513 * Don't want to add for example a taxon or synonym to itself
514 * so filter the list to remove the taxon in question
515 * (<code>cdmBaseToBeFiltered</code>)
516 * so it is not available in the filtered list.
517 */
518 private void filterExcludedObjects() {
519 if (model != null && cdmBaseToBeFiltered != null) {
520
521 UuidAndTitleCache uuidAndTitleCacheToRemove = null;
522
523 for (UuidAndTitleCache uuidAndTitleCache : model){
524 if ((cdmBaseToBeFiltered.getUuid()).equals(uuidAndTitleCache.getUuid())) {
525 uuidAndTitleCacheToRemove = uuidAndTitleCache;
526 }
527 }
528 model.remove(uuidAndTitleCacheToRemove);
529 }
530 }
531 @Override
532 void createFilterButton(Composite searchAndFilter){
533 //as default no filter button available
534 }
535
536 /** {@inheritDoc} */
537 @Override
538 protected void search() {
539 Control control =getSearchField();
540 String pattern = null;
541 if (control != null){
542 pattern = ((Text)control).getText();
543 if (pattern.equals("*") || pattern.equals("?")){
544 callService(null);
545 }else if (StringUtils.isNotBlank(pattern)){
546 callService(pattern);
547 }
548 fillContentProvider(null);
549 }
550
551 // if (pattern.equals("?")){
552 // model = CdmStore.getService(INameService.class).getUuidAndTitleCache(null, null);
553 // }else if (pattern != null){
554 // model = CdmStore.getService(INameService.class).getUuidAndTitleCache(limitOfInitialElements, pattern);
555 // }
556 }
557
558 abstract void callService(String pattern);
559
560 }