Merge branch 'release/5.18.0'
[taxeditor.git] / eu.etaxonomy.taxeditor.editor / src / main / java / eu / etaxonomy / taxeditor / editor / descriptiveDataSet / matrix / SpecimenSelectionDialog.java
1 /**
2 * Copyright (C) 2018 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 package eu.etaxonomy.taxeditor.editor.descriptiveDataSet.matrix;
10
11 import java.util.ArrayList;
12 import java.util.Collection;
13 import java.util.HashSet;
14 import java.util.Iterator;
15 import java.util.List;
16 import java.util.Set;
17 import java.util.stream.Collectors;
18
19 import org.apache.commons.lang3.StringUtils;
20 import org.eclipse.jface.dialogs.Dialog;
21 import org.eclipse.jface.viewers.ArrayContentProvider;
22 import org.eclipse.jface.viewers.ColumnLabelProvider;
23 import org.eclipse.jface.viewers.IStructuredSelection;
24 import org.eclipse.jface.viewers.ITableLabelProvider;
25 import org.eclipse.jface.viewers.TableViewer;
26 import org.eclipse.jface.viewers.TableViewerColumn;
27 import org.eclipse.jface.viewers.Viewer;
28 import org.eclipse.jface.viewers.ViewerComparator;
29 import org.eclipse.swt.SWT;
30 import org.eclipse.swt.custom.ScrolledComposite;
31 import org.eclipse.swt.events.FocusEvent;
32 import org.eclipse.swt.events.FocusListener;
33 import org.eclipse.swt.events.SelectionAdapter;
34 import org.eclipse.swt.events.SelectionEvent;
35 import org.eclipse.swt.graphics.Image;
36 import org.eclipse.swt.layout.GridData;
37 import org.eclipse.swt.layout.GridLayout;
38 import org.eclipse.swt.widgets.Button;
39 import org.eclipse.swt.widgets.Composite;
40 import org.eclipse.swt.widgets.Control;
41 import org.eclipse.swt.widgets.Label;
42 import org.eclipse.swt.widgets.Shell;
43 import org.eclipse.swt.widgets.Table;
44 import org.eclipse.swt.widgets.Text;
45
46 import eu.etaxonomy.cdm.api.service.IDescriptiveDataSetService;
47 import eu.etaxonomy.cdm.common.CdmUtils;
48 import eu.etaxonomy.cdm.persistence.dto.SpecimenNodeWrapper;
49 import eu.etaxonomy.taxeditor.editor.l10n.Messages;
50 import eu.etaxonomy.taxeditor.model.AbstractUtility;
51 import eu.etaxonomy.taxeditor.model.ImageResources;
52 import eu.etaxonomy.taxeditor.preference.Resources;
53 import eu.etaxonomy.taxeditor.store.CdmStore;
54 import eu.etaxonomy.taxeditor.store.StoreUtil;
55
56 /**
57 * Dialog to choose specimens for the character matrix.<br>
58 * Filters specimens that have already been added.
59 * @author pplitzner
60 * @since Jan 3, 2018
61 *
62 */
63 public class SpecimenSelectionDialog extends Dialog {
64
65 /**
66 *
67 */
68 private static final String TAXONOMIC_SUBTREE_FILTER = "Taxonomic Subtree Filter: ";
69
70 private static String TEXT_FILTER_DEFAULT = "Enter text filter";
71
72 private TableViewer list;
73
74 private Collection<SpecimenNodeWrapper> selectedSpecimens = new ArrayList<>();
75 private CharacterMatrix matrix;
76 private Text txtTextFilter;
77 private List<String> treeIndexList;
78 private List<String> taxonTitleList;
79 private Label l_title;
80 Label l_title_filter;
81
82
83 public SpecimenSelectionDialog(Shell parentShell, CharacterMatrix matrix, List<String> treeIndex, List<String> taxonTitleList) {
84 super(parentShell);
85 this.matrix = matrix;
86 this.treeIndexList = treeIndex;
87 this.taxonTitleList = taxonTitleList;
88 }
89
90 @Override
91 protected Control createDialogArea(Composite parent) {
92 Composite composite = (Composite) super.createDialogArea(parent);
93 GridLayout gl_composite = new GridLayout();
94 gl_composite.numColumns = 2;
95 composite.setLayout(gl_composite);
96 Composite composite_1 = new Composite(composite, SWT.NONE);
97 composite_1.setLayoutData(new GridData(SWT.FILL, SWT.TOP, true, false, 2, 2));
98 composite_1.setLayout(new GridLayout(5, false));
99
100 l_title = new Label(composite_1, SWT.NULL);
101 l_title_filter = new Label(composite_1, SWT.NULL);
102 GridData gridData = new GridData();
103 gridData.horizontalAlignment = GridData.BEGINNING;
104 gridData.horizontalSpan = 3;
105 l_title_filter.setLayoutData(gridData);
106 l_title.setText(TAXONOMIC_SUBTREE_FILTER);
107 if (taxonTitleList != null && !taxonTitleList.isEmpty()){
108 Iterator<String> iterator = taxonTitleList.iterator();
109 String titleString=iterator.next();
110 while(iterator.hasNext() ){
111 titleString += ", "+ iterator.next();
112 }
113 l_title_filter.setText(titleString);
114 }else {
115 l_title_filter.setText(" - ");
116 }
117 Button btnRemoveFilterButton = new Button(composite_1, SWT.NONE);
118 btnRemoveFilterButton.setLayoutData(new GridData(SWT.RIGHT, SWT.CENTER, false, false, 1, 1));
119 btnRemoveFilterButton.setToolTipText(Messages.SpecimenSelectionDialog_REMOVE_FILTER);
120 btnRemoveFilterButton.setImage(ImageResources.getImage(ImageResources.TRASH_ICON));
121 btnRemoveFilterButton.addSelectionListener(new SelectionAdapter() {
122 @Override
123 public void widgetSelected(SelectionEvent e) {
124 // txtTextFilter.setText("");
125 treeIndexList = null;
126 l_title.setText(TAXONOMIC_SUBTREE_FILTER);
127 l_title_filter.setText(" - ");
128 refreshInput();
129 }
130 });
131
132 Label l_textFilter = new Label(composite_1, SWT.NULL);
133 GridData data_label = new GridData(SWT.LEFT, SWT.CENTER, false, false, 1, 1);
134
135
136 l_textFilter.setLayoutData(data_label);
137 l_textFilter.setText("Specimen Filter");
138 l_textFilter.setAlignment(SWT.RIGHT);
139 l_textFilter.setToolTipText("Filters for taxon name and specimen titlecache");
140 txtTextFilter = new Text(composite_1, SWT.BORDER);
141 txtTextFilter.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false, 2, 1));
142 txtTextFilter.setText(TEXT_FILTER_DEFAULT);
143 txtTextFilter.addFocusListener(new FocusListener() {
144
145 @Override
146 public void focusGained(FocusEvent e) {
147 txtTextFilter.setForeground(AbstractUtility.getColor(Resources.SEARCH_VIEW_FOCUS));
148 if (TEXT_FILTER_DEFAULT.equals(txtTextFilter.getText())) {
149 StoreUtil.setTextWithoutModifyListeners(txtTextFilter, "");
150 }
151 }
152
153 @Override
154 public void focusLost(FocusEvent e) {
155 if (CdmUtils.isBlank(txtTextFilter.getText())){
156 txtTextFilter.setForeground(AbstractUtility.getColor(Resources.SEARCH_VIEW_FOREGROUND));
157 StoreUtil.setTextWithoutModifyListeners(txtTextFilter, TEXT_FILTER_DEFAULT);
158 }
159 }
160 });
161 txtTextFilter.addModifyListener(e->applyFilter());
162
163 Button btnRefreshButton = new Button(composite_1, SWT.NONE);
164 btnRefreshButton.setLayoutData(new GridData(SWT.RIGHT, SWT.CENTER, false, false, 1, 1));
165 btnRefreshButton.setToolTipText(Messages.SpecimenSelectionDialog_REFRESH);
166 btnRefreshButton.setImage(ImageResources.getImage(ImageResources.REFRESH));
167 btnRefreshButton.addSelectionListener(new SelectionAdapter() {
168 @Override
169 public void widgetSelected(SelectionEvent e) {
170 loadSpecimens();
171 refreshInput();
172 }
173 });
174
175
176
177 Composite composite_2 = new Composite(composite, SWT.NONE);
178 composite_2.setLayoutData(new GridData(SWT.FILL, SWT.TOP, true, false, 2, 1));
179 composite_2.setLayout(new GridLayout(2, false));
180 Label lblNewLabel = new Label(composite_2, SWT.NONE);
181 lblNewLabel.setImage(ImageResources.getImage(ImageResources.WARNING_ICON));
182
183 Label lblNewLabel_1 = new Label(composite_2, SWT.NONE);
184 lblNewLabel_1.setText(": Specimen not associated with taxon");
185
186 ScrolledComposite scrolledComposite = new ScrolledComposite(composite, SWT.BORDER | SWT.H_SCROLL | SWT.V_SCROLL);
187 scrolledComposite.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true, 2, 1));
188 scrolledComposite.setExpandHorizontal(true);
189 scrolledComposite.setExpandVertical(true);
190 //table
191 list = new TableViewer(scrolledComposite, SWT.H_SCROLL | SWT.V_SCROLL | SWT.FULL_SELECTION | SWT.MULTI);
192 Table table = list.getTable();
193
194 //table columns
195 TableViewerColumn columnTaxon = new TableViewerColumn(list, SWT.NONE);
196 columnTaxon.getColumn().setText("Taxon");
197 columnTaxon.getColumn().setWidth(200);
198 columnTaxon.getColumn().setResizable(true);
199 columnTaxon.getColumn().setMoveable(true);
200 TableViewerColumn columnType = new TableViewerColumn(list, SWT.NONE);
201 columnType.getColumn().setText("Type");
202 columnType.getColumn().setWidth(150);
203 columnType.getColumn().setResizable(true);
204 columnType.getColumn().setMoveable(true);
205 TableViewerColumn columnSpecimen = new TableViewerColumn(list, SWT.NONE);
206 columnSpecimen.getColumn().setText("Specimen");
207 columnSpecimen.getColumn().setResizable(true);
208 columnSpecimen.getColumn().setMoveable(true);
209 columnSpecimen.getColumn().setWidth(400);
210
211 table.setHeaderVisible(true);
212 table.setLinesVisible(true);
213 scrolledComposite.setContent(table);
214 scrolledComposite.setMinSize(table.computeSize(SWT.DEFAULT, SWT.DEFAULT));
215 list.setContentProvider(new ArrayContentProvider());
216 list.setLabelProvider(new SpecimenListLabelProvider());
217
218 ViewerComparator comp = new ViewerComparator() {
219 @Override
220 public int compare(Viewer viewer, Object o1, Object o2) {
221 if(o1 == null){
222 if(o2 == null){
223 return 0;
224 }
225 return -1;
226 }
227 if(o2==null){
228 return 1;
229 }
230 try{
231 return ((SpecimenNodeWrapper)o1).getTaxonNode().getTitleCache().compareTo(((SpecimenNodeWrapper)o2).getTaxonNode().getTitleCache());
232
233 }
234 catch(NullPointerException e){
235 return 0;
236 }
237
238 }
239 };
240
241 list.setComparator(comp);
242
243 //gather specimens
244 if(matrix.getSpecimenCache()==null || matrix.getSpecimenCache().isEmpty()){
245 loadSpecimens();
246 }
247 if(treeIndexList !=null){
248 filterByTaxonNode( null);
249 }else{
250 refreshInput();
251 }
252
253 columnSpecimen.getColumn().pack();
254
255 return composite;
256 }
257
258 private void refreshInput(){
259 applyFilter();
260 }
261
262 private void applyFilter(){
263 Set<SpecimenNodeWrapper> result = new HashSet<>();
264 Collection<SpecimenNodeWrapper> specimenCache = matrix.getSpecimenCache();
265 String text = txtTextFilter.getText();
266
267 //filter for treeIndexList is missing
268 if(CdmUtils.isBlank(text) || text.equals(TEXT_FILTER_DEFAULT)){
269 result = new HashSet<>(specimenCache);
270 }
271 else{
272 if(!txtTextFilter.getForeground().equals(AbstractUtility.getColor(Resources.SEARCH_VIEW_FOREGROUND))
273 &&!CdmUtils.isBlank(text)){
274 result.addAll(specimenCache.stream()
275 .filter(wrapper->wrapper.getUuidAndTitleCache().getTitleCache().toLowerCase().contains(text.toLowerCase()))
276 .collect(Collectors.toList()));
277 result.addAll(specimenCache.stream()
278 .filter(wrapper->wrapper.getTaxonNode().getTitleCache().toLowerCase().contains(text.toLowerCase()))
279 .collect(Collectors.toList()));
280 }
281 }
282 filterByTaxonNode(result);
283
284 }
285
286 private void loadSpecimens(){
287 ArrayList<SpecimenNodeWrapper> specimenList = new ArrayList<>(CdmStore.getService(IDescriptiveDataSetService.class).loadSpecimens(matrix.getDescriptiveDataSet().getUuid()));
288 // Collections.sort(specimenList, new Comparator<SpecimenNodeWrapper>() {
289 //
290 // @Override
291 // public int compare(SpecimenNodeWrapper o1, SpecimenNodeWrapper o2) {
292 // if(o1 == null){
293 // if(o2 == null){
294 // return 0;
295 // }
296 // return -1;
297 // }
298 // if(o2==null){
299 // return 1;
300 // }
301 // try{
302 // return o1.getTaxonNode().getTitleCache().compareTo(o2.getTaxonNode().getTitleCache());
303 // }
304 // catch(NullPointerException e){
305 // return 0;
306 // }
307 // }
308 // });
309 matrix.setSpecimenCache(specimenList);
310 }
311
312 @Override
313 protected void configureShell(Shell newShell) {
314 super.configureShell(newShell);
315 newShell.setText(Messages.SpecimenSelectionDialog_SELECT_SPECIMENS);
316 newShell.setMinimumSize(500, 600);
317 newShell.setSize(800, 600);
318 }
319
320 @Override
321 protected void okPressed() {
322 selectedSpecimens.clear();
323 selectedSpecimens = ((IStructuredSelection)list.getSelection()).toList();
324 super.okPressed();
325 }
326
327 @Override
328 protected boolean isResizable() {
329 return true;
330 }
331
332 public Collection<SpecimenNodeWrapper> getSpecimen(){
333 return selectedSpecimens;
334 }
335
336 private class SpecimenListLabelProvider extends ColumnLabelProvider implements ITableLabelProvider {
337
338 @Override
339 public String getToolTipText(Object element) {
340 if(element instanceof SpecimenNodeWrapper
341 && ((SpecimenNodeWrapper) element).getTaxonDescriptionUuid()==null){
342 return "Does not have and IndividualsAssociation with the taxon";
343 }
344 return null;
345 }
346
347 @Override
348 public Image getColumnImage(Object element, int columnIndex) {
349 if(element instanceof SpecimenNodeWrapper && columnIndex == 2
350 && ((SpecimenNodeWrapper) element).getTaxonDescriptionUuid()==null){
351 return ImageResources.getImage(ImageResources.WARNING_ICON);
352 }
353 return null;
354 }
355
356 @Override
357 public String getColumnText(Object element, int columnIndex) {
358 if(element instanceof SpecimenNodeWrapper){
359 SpecimenNodeWrapper wrapper = (SpecimenNodeWrapper)element;
360 switch (columnIndex) {
361 case 0:
362 return wrapper.getTaxonNode().getTitleCache();
363 case 1:
364 return wrapper.getType().getLabel();
365 case 2:
366 return wrapper.getUuidAndTitleCache().getTitleCache();
367 default:
368 break;
369 }
370 }
371 return "";
372 }
373 }
374
375 private void filterByTaxonNode( Collection<SpecimenNodeWrapper> specimenCache){
376 Collection<SpecimenNodeWrapper> result = new ArrayList<>();
377 if (specimenCache == null){
378 specimenCache = matrix.getSpecimenCache();
379 }
380 if (treeIndexList != null){
381 for (String treeIndex: this.treeIndexList){
382 if (StringUtils.isNotBlank(treeIndex)){
383 result.addAll(specimenCache.stream()
384 .filter(wrapper->wrapper.getTaxonNode().getTreeIndex().startsWith(treeIndex))
385 .collect(Collectors.toList()));
386 }
387 }
388 }else{
389 result.addAll(specimenCache);
390 }
391
392
393 list.setInput(result);
394 }
395 }