Project

General

Profile

Download (17.2 KB) Statistics
| Branch: | Tag: | Revision:
1
/**
2
 * Copyright (C) 2015 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.cdm.vaadin.component.distributionStatus;
10

    
11
import java.sql.SQLException;
12
import java.util.ArrayList;
13
import java.util.Collection;
14
import java.util.List;
15
import java.util.Set;
16
import java.util.UUID;
17

    
18
import com.vaadin.data.Container;
19
import com.vaadin.data.Property;
20
import com.vaadin.data.Property.ValueChangeEvent;
21
import com.vaadin.data.Property.ValueChangeListener;
22
import com.vaadin.data.util.BeanItemContainer;
23
import com.vaadin.data.util.sqlcontainer.RowId;
24
import com.vaadin.server.Page;
25
import com.vaadin.server.VaadinSession;
26
import com.vaadin.ui.AbstractLayout;
27
import com.vaadin.ui.Alignment;
28
import com.vaadin.ui.Button.ClickEvent;
29
import com.vaadin.ui.Button.ClickListener;
30
import com.vaadin.ui.ComboBox;
31
import com.vaadin.ui.HorizontalLayout;
32
import com.vaadin.ui.Notification;
33
import com.vaadin.ui.OptionGroup;
34
import com.vaadin.ui.Panel;
35
import com.vaadin.ui.Table.ColumnHeaderMode;
36
import com.vaadin.ui.TextField;
37
import com.vaadin.ui.Tree.ExpandEvent;
38
import com.vaadin.ui.Tree.ExpandListener;
39
import com.vaadin.ui.TreeTable;
40
import com.vaadin.ui.UI;
41
import com.vaadin.ui.VerticalLayout;
42

    
43
import eu.etaxonomy.cdm.common.CdmUtils;
44
import eu.etaxonomy.cdm.i18n.Messages;
45
import eu.etaxonomy.cdm.model.location.NamedArea;
46
import eu.etaxonomy.cdm.model.taxon.Classification;
47
import eu.etaxonomy.cdm.model.taxon.TaxonNode;
48
import eu.etaxonomy.cdm.model.term.TermVocabulary;
49
import eu.etaxonomy.cdm.persistence.dto.TaxonNodeDto;
50
import eu.etaxonomy.cdm.persistence.dto.UuidAndTitleCache;
51
import eu.etaxonomy.cdm.vaadin.container.CdmSQLContainer;
52
import eu.etaxonomy.cdm.vaadin.container.NamedAreaContainer;
53
import eu.etaxonomy.cdm.vaadin.container.TaxonNodeContainer;
54
import eu.etaxonomy.cdm.vaadin.util.CdmQueryFactory;
55
import eu.etaxonomy.cdm.vaadin.util.CdmSpringContextHelper;
56
import eu.etaxonomy.cdm.vaadin.util.DistributionEditorUtil;
57
import eu.etaxonomy.cdm.vaadin.view.distributionStatus.IDistributionTableView;
58
import eu.etaxonomy.cdm.vaadin.view.distributionStatus.settings.AreaAndTaxonSettingsPresenter;
59

    
60
/**
61
 * @author pplitzner
62
 * A Configuration window for choosing distribution areas and taxa to work with.
63
 */
64
public class AreaAndTaxonSettingsConfigWindow
65
            extends SettingsDialogWindowBase<AreaAndTaxonSettingsPresenter>
66
            implements ValueChangeListener, ClickListener, ExpandListener{
67

    
68
    private static final long serialVersionUID = 1439411115014088780L;
69

    
70
    private ComboBox classificationBox;
71
    private TextField taxonFilter;
72
    private ComboBox distAreaBox;
73
    private OptionGroup namedAreaList;
74
    private TreeTable taxonTree;
75
    private IDistributionTableView distributionTableView;
76

    
77
    /**
78
     * The constructor should first build the main layout, set the
79
     * composition root and then do any custom initialization.
80
     *
81
     * The constructor will not be automatically regenerated by the
82
     * visual editor.
83
     * @param distributionTableView
84
     */
85
    public AreaAndTaxonSettingsConfigWindow(IDistributionTableView distributionTableView) {
86
        super();
87
        this.distributionTableView = distributionTableView;
88
    }
89

    
90
    @Override
91
    protected void init() {
92
        //init classification
93
        Classification classification = presenter.getChosenClassification();
94
        try {
95
            CdmSQLContainer classificationContainer = new CdmSQLContainer(CdmQueryFactory.generateTableQuery("Classification")); //$NON-NLS-1$
96
            classificationContainer.sort(new Object[] {"titleCache"}, new boolean[] {true}); //$NON-NLS-1$
97
            classificationBox.setContainerDataSource(classificationContainer);
98
        } catch (SQLException e) {
99
            DistributionEditorUtil.showSqlError(e);
100
        }
101
        RowId classificationRow = null;
102
        if(classification!=null){
103
            classificationRow = new RowId(classification.getId());
104
            TaxonNode root = CdmSpringContextHelper.getClassificationService().getRootNode(classification.getUuid());
105
            showClassificationTaxa(root);
106
        }
107
        else if(classificationBox.getItemIds().size()==1){
108
            //only one classification exists
109
            classificationRow = (RowId) classificationBox.getItemIds().iterator().next();
110
        }
111
        if(classificationRow!=null){
112
            classificationBox.setValue(classificationRow);
113
        }
114

    
115
        classificationBox.addValueChangeListener(this);
116
        taxonFilter.addValueChangeListener(this);
117
        taxonTree.addExpandListener(this);
118

    
119
        //init areas
120
        TermVocabulary<NamedArea> chosenAreaVoc = presenter.getChosenAreaVoc();
121
        Container areaVocContainer = presenter.getAreaContainer();
122
        if (areaVocContainer.size() == 1){
123
            chosenAreaVoc = (TermVocabulary<NamedArea>)areaVocContainer.getItemIds().iterator().next();
124
        }
125
        distAreaBox.setContainerDataSource(areaVocContainer);
126
        distAreaBox.setValue(chosenAreaVoc);
127
        distAreaBox.addValueChangeListener(this);
128

    
129
        if(chosenAreaVoc!=null){
130
            NamedAreaContainer areaContainer = new NamedAreaContainer(chosenAreaVoc);
131
            namedAreaList.setContainerDataSource(areaContainer);
132
        }
133
        Object selectedAreas = VaadinSession.getCurrent().getAttribute(DistributionEditorUtil.SATTR_SELECTED_AREAS);
134
        namedAreaList.setValue(selectedAreas);
135

    
136
        okButton.addClickListener(this);
137
        cancelButton.addClickListener(this);
138
        updateButtons();
139
    }
140

    
141
    @Override
142
    protected AbstractLayout buildMainLayout() {
143

    
144
        mainLayout = new VerticalLayout();
145
        mainLayout.setSizeFull();
146

    
147
        HorizontalLayout leftAndRightContainer = new HorizontalLayout();
148
        leftAndRightContainer.setImmediate(false);
149
        leftAndRightContainer.setSizeFull();
150
        leftAndRightContainer.setMargin(true);
151
        leftAndRightContainer.setSpacing(true);
152

    
153
        VerticalLayout leftContainer = new VerticalLayout();
154
        leftContainer.setImmediate(false);
155
        leftContainer.setSpacing(true);
156
        leftContainer.setSizeFull();
157

    
158
        VerticalLayout rightContainer = new VerticalLayout();
159
        rightContainer.setImmediate(false);
160
        rightContainer.setSpacing(true);
161
        rightContainer.setSizeFull();
162

    
163
        //classification
164
        classificationBox = new ComboBox(Messages.getLocalizedString(Messages.AreaAndTaxonSettingsConfigWindow_CLASSIFICATION));
165
        classificationBox.setItemCaptionPropertyId(TaxonNodeContainer.LABEL);
166
        classificationBox.setInputPrompt(Messages.getLocalizedString(Messages.AreaAndTaxonSettingsConfigWindow_SELECT_CLASSIFICATION));
167
        classificationBox.setImmediate(true);
168
        classificationBox.setNewItemsAllowed(false);
169
        classificationBox.setNullSelectionAllowed(false);
170
        classificationBox.setSizeFull();
171
        classificationBox.setWidth("100%"); //$NON-NLS-1$
172

    
173
        //taxonFilter
174
        taxonFilter = new TextField(Messages.getLocalizedString(Messages.AreaAndTaxonSettingsConfigWindow_FILTER));
175
        taxonFilter.setInputPrompt(Messages.getLocalizedString(Messages.AreaAndTaxonSettingsConfigWindow_FILTER_TAXA_BY_NAME));
176
        taxonFilter.setSizeFull();
177
        taxonFilter.setImmediate(true);
178

    
179
        //distribution area box
180
        distAreaBox = new ComboBox(Messages.getLocalizedString(Messages.AreaAndTaxonSettingsConfigWindow_DISTRIBUTION_AREA));
181
        distAreaBox.setInputPrompt(Messages.getLocalizedString(Messages.AreaAndTaxonSettingsConfigWindow_SELECT_DISTRIBUTION_AREA));
182
        distAreaBox.setImmediate(true);
183
        distAreaBox.setNullSelectionAllowed(false);
184
        distAreaBox.setNewItemsAllowed(false);
185
        distAreaBox.setSizeFull();
186
        distAreaBox.setWidth("100%"); //$NON-NLS-1$
187

    
188
        // named areas
189
        namedAreaList = new OptionGroup();
190
        namedAreaList.setMultiSelect(true);
191
        namedAreaList.setSizeFull();
192
        Panel namedAreaPanel = new Panel(Messages.getLocalizedString(Messages.AreaAndTaxonSettingsConfigWindow_AREAS));
193
        namedAreaPanel.setContent(new VerticalLayout(namedAreaList));
194
        namedAreaPanel.setSizeFull();
195

    
196

    
197
        //taxonomy
198
        taxonTree = new TreeTable(Messages.getLocalizedString(Messages.AreaAndTaxonSettingsConfigWindow_TAXONOMY));
199
        taxonTree.setSelectable(true);
200
        taxonTree.setSizeFull();
201
        taxonTree.setImmediate(true);
202
        taxonTree.setCacheRate(20);
203
        taxonTree.setColumnHeaderMode(ColumnHeaderMode.HIDDEN);
204
        taxonTree.setMultiSelect(true);
205

    
206
        leftContainer.addComponent(distAreaBox);
207
        leftContainer.addComponent(namedAreaPanel);
208
        leftContainer.setExpandRatio(distAreaBox, 0.1f);
209
        leftContainer.setExpandRatio(namedAreaPanel, 0.9f);
210
        leftContainer.setSizeFull();
211

    
212
        rightContainer.addComponent(classificationBox);
213
        rightContainer.addComponent(taxonFilter);
214
        rightContainer.addComponent(taxonTree);
215
        rightContainer.setExpandRatio(classificationBox, 0.1f);
216
        rightContainer.setExpandRatio(taxonFilter, 0.1f);
217
        rightContainer.setExpandRatio(taxonTree, 0.8f);
218

    
219
        leftAndRightContainer.addComponent(leftContainer);
220
        leftAndRightContainer.addComponent(rightContainer);
221

    
222
        //button toolbar
223
        HorizontalLayout buttonToolBar = createOkCancelButtons();
224

    
225
        mainLayout.addComponent(leftAndRightContainer);
226
        mainLayout.addComponent(buttonToolBar);
227
        mainLayout.setExpandRatio(leftAndRightContainer, 0.9f);
228
        mainLayout.setExpandRatio(buttonToolBar, 0.1f);
229
        mainLayout.setComponentAlignment(buttonToolBar, Alignment.BOTTOM_RIGHT);
230

    
231
        return leftAndRightContainer;
232
    }
233

    
234
    @Override
235
    public void valueChange(ValueChangeEvent event) {
236
        Property<?> property = event.getProperty();
237
        if(property==classificationBox){
238
            TaxonNodeDto parent = getTaxonNodeDtoFromRowId(classificationBox.getValue());
239
        	TaxonNode root = CdmSpringContextHelper.getClassificationService().getRootNode(parent.getUuid());
240
        	showClassificationTaxa(root);
241
        }
242
        else if(property==taxonFilter){
243
            String filterText = taxonFilter.getValue();
244
            Property<?> uuidProperty = classificationBox.getContainerProperty(classificationBox.getValue(),"uuid"); //$NON-NLS-1$
245
            if(uuidProperty==null){
246
            	Notification.show(Messages.getLocalizedString(Messages.AreaAndTaxonSettingsConfigWindow_SELECT_CLASSIFICATION));
247
            }
248
            else{
249
            	if(CdmUtils.isNotBlank(filterText)){
250
            		UUID classificationUuid = UUID.fromString((String) uuidProperty.getValue());
251
            		List<TaxonNodeDto> taxonNodeDtos = CdmSpringContextHelper.getTaxonNodeService().getUuidAndTitleCache(null, filterText, classificationUuid);
252
            		BeanItemContainer<UuidAndTitleCache<TaxonNode>> container = new BeanItemContainer<>(UuidAndTitleCache.class);
253
            		taxonTree.setContainerDataSource(container);
254
            		for (TaxonNodeDto taxonNodeDTO : taxonNodeDtos) {
255
            			container.addItem(taxonNodeDTO);
256
            			taxonTree.setChildrenAllowed(taxonNodeDTO, false);
257
            		}
258
            		taxonTree.setVisibleColumns("titleCache"); //$NON-NLS-1$
259
            	}
260
            	else{
261
            	    TaxonNodeDto parent = getTaxonNodeDtoFromRowId(classificationBox.getValue());
262
            		TaxonNode root = CdmSpringContextHelper.getClassificationService().getRootNode(parent.getUuid());
263
            		showClassificationTaxa(root);
264
            	}
265
            }
266
        }
267
        else if(property==distAreaBox){
268
            TermVocabulary<NamedArea> vocabulary = (TermVocabulary<NamedArea>) event.getProperty().getValue();
269
            NamedAreaContainer container = new NamedAreaContainer(vocabulary);
270
            namedAreaList.setContainerDataSource(container);
271
        }
272
        updateButtons();
273
    }
274

    
275
    @Override
276
    protected boolean isValid() {
277
        return classificationBox.getValue()!=null && distAreaBox.getValue()!=null;
278
    }
279

    
280
    @Override
281
    public void buttonClick(ClickEvent event) {
282
        Object source = event.getSource();
283
        if(source==okButton){
284
            List<UUID> taxonNodes = new ArrayList<>();
285
            TermVocabulary<NamedArea> areaVoc = null;
286
            String uuidString = (String) classificationBox.getContainerProperty(classificationBox.getValue(),"uuid").getValue(); //$NON-NLS-1$
287
            UUID classificationUuid = UUID.fromString(uuidString);
288
            Set<UuidAndTitleCache<TaxonNode>> treeSelection = (Set<UuidAndTitleCache<TaxonNode>>) taxonTree.getValue();
289
			if(!treeSelection.isEmpty()){
290
				for (UuidAndTitleCache<TaxonNode> uuidAndTitleCache : treeSelection) {
291
					taxonNodes.add(uuidAndTitleCache.getUuid());
292
				}
293
            }
294
			if(treeSelection.isEmpty() && CdmUtils.isNotBlank(taxonFilter.getValue())) {
295
                for (UuidAndTitleCache<TaxonNode> uuidAndTitleCache : (Collection<UuidAndTitleCache<TaxonNode>>) taxonTree.getItemIds()) {
296
                    taxonNodes.add(uuidAndTitleCache.getUuid());
297
                }
298
			}
299
            areaVoc = (TermVocabulary<NamedArea>) distAreaBox.getValue();
300
            List<NamedArea> selectedAreas = new ArrayList<>((Set<NamedArea>)namedAreaList.getValue()); //getValue is LinkedHashSet and therefore sorted
301
            DistributionEditorUtil.updateDistributionView(distributionTableView, taxonNodes, areaVoc, selectedAreas, classificationUuid);
302
            window.close();
303
        }
304
        else if(source==cancelButton){
305
            window.close();
306
        }
307
    }
308

    
309
    @Override
310
    public void nodeExpand(ExpandEvent event) {
311
        TaxonNodeDto parent = (TaxonNodeDto) event.getItemId();
312
        ((TaxonNodeContainer) taxonTree.getContainerDataSource()).addChildItems(parent);
313
    }
314

    
315
    /**
316
     * Starts a {@link TreeUpdater} thread to populate the {@link #taxonTree} with taxa of the classification specified by the given {@code rootNode}.
317
     * @param rootNode The root node of the classification whose taxa should be shown in the {@link #taxonTree}.
318
     */
319
    private void showClassificationTaxa(TaxonNode rootNode) {
320
        final List<TaxonNodeDto> children = CdmSpringContextHelper.getTaxonNodeService().listChildNodesAsTaxonNodeDto(rootNode);
321
        // Enable polling and set frequency to 0.5 seconds
322
        UI.getCurrent().setPollInterval(500);
323
        taxonTree.setEnabled(false);
324
        taxonTree.removeAllItems();
325
        Notification.show(Messages.getLocalizedString(Messages.AreaAndTaxonSettingsConfigWindow_LOADING_TAXA));
326
        new TreeUpdater(children).start();
327
    }
328

    
329
    /**
330
     * Returns the {@link TaxonNodeDto} object of the classification specified by the given {@link RowId}
331
     * of the {@link CdmSQLContainer} used in the {@link #classificationBox}.
332
     * @param classificationSelection
333
     * @return {@link TaxonNodeDto} object of the given classification specified by {@code classificationSelection}
334
     */
335
    private TaxonNodeDto getTaxonNodeDtoFromRowId(Object classificationSelection) {
336
        String uuidString = (String) classificationBox.getContainerProperty(classificationSelection, "uuid").getValue(); //$NON-NLS-1$
337
        Property<Integer> rootNodeContainerProperty = null;
338

    
339
        Collection<?> ids = classificationBox.getContainerPropertyIds();
340
        //use for loop here because the case of the root node id columns differs between some DBs
341
        for (Object id : ids) {
342
			if(id instanceof String && ((String) id).toLowerCase().equals("rootnode_id")){ //$NON-NLS-1$
343
				rootNodeContainerProperty = classificationBox.getContainerProperty(classificationSelection, id);
344
				break;
345
			}
346
		}
347
		int id = rootNodeContainerProperty.getValue();
348
        String titleCache = (String) classificationBox.getContainerProperty(classificationSelection, "titleCache").getValue(); //$NON-NLS-1$
349
        UUID uuid = UUID.fromString(uuidString);
350
        TaxonNodeDto parent = new TaxonNodeDto(uuid, id, titleCache);
351
        return parent;
352
    }
353

    
354
    @Override
355
    protected AreaAndTaxonSettingsPresenter getPresenter() {
356
        return new AreaAndTaxonSettingsPresenter();
357
    }
358

    
359
    /**
360
     * Thread to populate {@link AreaAndTaxonSettingsConfigWindow#taxonTree}.
361
     *
362
     */
363
    private class TreeUpdater extends Thread{
364

    
365
    	/**
366
    	 * The taxa to show.
367
    	 */
368
    	private Collection<TaxonNodeDto> children;
369

    
370
    	/**
371
    	 * Creates a thread to show the given collection of taxa in {@link AreaAndTaxonSettingsConfigWindow#taxonTree}.
372
    	 * @param children {@link UuidAndTitleCache} of the taxa to show.
373
    	 */
374
		public TreeUpdater(Collection<TaxonNodeDto> children) {
375
			this.children = children;
376
		}
377

    
378
		@Override
379
    	public void run() {
380
			UI.getCurrent().access(new Runnable() {
381

    
382
				@Override
383
				public void run() {
384
					taxonTree.setContainerDataSource(new TaxonNodeContainer(children));
385

    
386
			        Notification notification = new Notification(Messages.getLocalizedString(Messages.AreaAndTaxonSettingsConfigWindow_LOADING_COMPLETE));
387
			        notification.setDelayMsec(500);
388
			        notification.show(Page.getCurrent());
389
			        taxonTree.setEnabled(true);
390
			        taxonTree.setSortContainerPropertyId("titleCache"); //$NON-NLS-1$
391
			        taxonTree.sort();
392

    
393
			        //disable polling when all taxa are loaded
394
			        UI.getCurrent().setPollInterval(-1);
395
				}
396
			});
397
    	}
398
    }
399
}
(1-1/6)