Project

General

Profile

Download (21.4 KB) Statistics
| Branch: | Tag: | Revision:
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.bulkeditor.e4;
11

    
12
import java.io.Serializable;
13
import java.util.ArrayList;
14
import java.util.HashMap;
15
import java.util.List;
16
import java.util.Map;
17

    
18
import javax.annotation.PostConstruct;
19
import javax.annotation.PreDestroy;
20
import javax.inject.Inject;
21

    
22
import org.eclipse.core.runtime.IProgressMonitor;
23
import org.eclipse.core.runtime.NullProgressMonitor;
24
import org.eclipse.e4.core.contexts.ContextInjectionFactory;
25
import org.eclipse.e4.core.contexts.IEclipseContext;
26
import org.eclipse.e4.core.di.annotations.Optional;
27
import org.eclipse.e4.core.services.events.IEventBroker;
28
import org.eclipse.e4.ui.di.Focus;
29
import org.eclipse.e4.ui.di.Persist;
30
import org.eclipse.e4.ui.di.UIEventTopic;
31
import org.eclipse.e4.ui.model.application.ui.MDirtyable;
32
import org.eclipse.e4.ui.model.application.ui.basic.MPart;
33
import org.eclipse.e4.ui.services.EMenuService;
34
import org.eclipse.e4.ui.workbench.modeling.ESelectionService;
35
import org.eclipse.jface.dialogs.MessageDialog;
36
import org.eclipse.jface.layout.GridDataFactory;
37
import org.eclipse.jface.viewers.ISelectionChangedListener;
38
import org.eclipse.jface.viewers.IStructuredSelection;
39
import org.eclipse.jface.viewers.StructuredSelection;
40
import org.eclipse.nebula.widgets.nattable.NatTable;
41
import org.eclipse.nebula.widgets.nattable.command.VisualRefreshCommand;
42
import org.eclipse.nebula.widgets.nattable.command.VisualRefreshCommandHandler;
43
import org.eclipse.nebula.widgets.nattable.config.AbstractRegistryConfiguration;
44
import org.eclipse.nebula.widgets.nattable.config.AbstractUiBindingConfiguration;
45
import org.eclipse.nebula.widgets.nattable.config.ConfigRegistry;
46
import org.eclipse.nebula.widgets.nattable.config.DefaultNatTableStyleConfiguration;
47
import org.eclipse.nebula.widgets.nattable.config.IConfigRegistry;
48
import org.eclipse.nebula.widgets.nattable.config.IEditableRule;
49
import org.eclipse.nebula.widgets.nattable.data.IRowIdAccessor;
50
import org.eclipse.nebula.widgets.nattable.data.ListDataProvider;
51
import org.eclipse.nebula.widgets.nattable.edit.EditConfigAttributes;
52
import org.eclipse.nebula.widgets.nattable.extension.glazedlists.GlazedListsEventLayer;
53
import org.eclipse.nebula.widgets.nattable.extension.glazedlists.GlazedListsSortModel;
54
import org.eclipse.nebula.widgets.nattable.grid.GridRegion;
55
import org.eclipse.nebula.widgets.nattable.grid.data.DefaultColumnHeaderDataProvider;
56
import org.eclipse.nebula.widgets.nattable.grid.data.DefaultCornerDataProvider;
57
import org.eclipse.nebula.widgets.nattable.grid.data.DefaultRowHeaderDataProvider;
58
import org.eclipse.nebula.widgets.nattable.grid.layer.ColumnHeaderLayer;
59
import org.eclipse.nebula.widgets.nattable.grid.layer.CornerLayer;
60
import org.eclipse.nebula.widgets.nattable.grid.layer.GridLayer;
61
import org.eclipse.nebula.widgets.nattable.grid.layer.RowHeaderLayer;
62
import org.eclipse.nebula.widgets.nattable.layer.DataLayer;
63
import org.eclipse.nebula.widgets.nattable.layer.stack.DefaultBodyLayerStack;
64
import org.eclipse.nebula.widgets.nattable.selection.RowSelectionModel;
65
import org.eclipse.nebula.widgets.nattable.selection.RowSelectionProvider;
66
import org.eclipse.nebula.widgets.nattable.sort.SortHeaderLayer;
67
import org.eclipse.nebula.widgets.nattable.sort.config.SingleClickSortConfiguration;
68
import org.eclipse.nebula.widgets.nattable.style.DisplayMode;
69
import org.eclipse.nebula.widgets.nattable.style.theme.ModernNatTableThemeConfiguration;
70
import org.eclipse.nebula.widgets.nattable.ui.binding.UiBindingRegistry;
71
import org.eclipse.nebula.widgets.nattable.ui.matcher.MouseEventMatcher;
72
import org.eclipse.nebula.widgets.nattable.ui.menu.PopupMenuAction;
73
import org.eclipse.nebula.widgets.nattable.ui.menu.PopupMenuBuilder;
74
import org.eclipse.swt.SWT;
75
import org.eclipse.swt.dnd.Clipboard;
76
import org.eclipse.swt.dnd.TextTransfer;
77
import org.eclipse.swt.dnd.Transfer;
78
import org.eclipse.swt.layout.GridData;
79
import org.eclipse.swt.layout.GridLayout;
80
import org.eclipse.swt.widgets.Composite;
81
import org.eclipse.swt.widgets.Display;
82
import org.eclipse.swt.widgets.Menu;
83

    
84
import ca.odell.glazedlists.SortedList;
85
import eu.etaxonomy.cdm.api.conversation.ConversationHolder;
86
import eu.etaxonomy.cdm.api.conversation.IConversationEnabled;
87
import eu.etaxonomy.cdm.api.facade.DerivedUnitFacade;
88
import eu.etaxonomy.cdm.model.common.CdmBase;
89
import eu.etaxonomy.cdm.model.description.SpecimenDescription;
90
import eu.etaxonomy.cdm.model.occurrence.DerivedUnit;
91
import eu.etaxonomy.cdm.model.occurrence.FieldUnit;
92
import eu.etaxonomy.cdm.model.taxon.Taxon;
93
import eu.etaxonomy.cdm.persistence.hibernate.CdmDataChangeMap;
94
import eu.etaxonomy.taxeditor.bulkeditor.BulkEditorQuery;
95
import eu.etaxonomy.taxeditor.bulkeditor.NullTextEditor;
96
import eu.etaxonomy.taxeditor.bulkeditor.input.AbstractBulkEditorInput;
97
import eu.etaxonomy.taxeditor.bulkeditor.input.sortprovider.TitleCacheComparator;
98
import eu.etaxonomy.taxeditor.editor.ITaxonEditor;
99
import eu.etaxonomy.taxeditor.event.WorkbenchEventConstants;
100
import eu.etaxonomy.taxeditor.l10n.Messages;
101
import eu.etaxonomy.taxeditor.model.IDerivedUnitFacadePart;
102
import eu.etaxonomy.taxeditor.model.IDirtyMarkable;
103
import eu.etaxonomy.taxeditor.model.IPartContentHasDetails;
104
import eu.etaxonomy.taxeditor.model.IPartContentHasFactualData;
105
import eu.etaxonomy.taxeditor.model.IPartContentHasMedia;
106
import eu.etaxonomy.taxeditor.model.IPartContentHasSupplementalData;
107
import eu.etaxonomy.taxeditor.operation.IPostOperationEnabled;
108
import eu.etaxonomy.taxeditor.workbench.part.IE4SavablePart;
109

    
110
/**
111
 *
112
 * @author pplitzner
113
 * @since Sep 8, 2017
114
 *
115
 */
116
public class BulkEditorE4 implements IPartContentHasDetails, IConversationEnabled, IPostOperationEnabled,
117
        IDirtyMarkable, IDerivedUnitFacadePart, IPartContentHasFactualData,
118
        IPartContentHasSupplementalData, IPartContentHasMedia, IE4SavablePart, ITaxonEditor {
119

    
120
    public static final String TYPE_PROPERTY = Messages.BulkEditorE4_TYPE;
121

    
122
    @Inject
123
	private MDirtyable dirty;
124

    
125
    private AbstractBulkEditorInput input;
126

    
127
    private Composite topComposite;
128

    
129
    private ConversationHolder conversation;
130

    
131
    @Inject
132
    private ESelectionService selService;
133

    
134
    @Inject
135
    private IEventBroker eventBroker;
136

    
137
    private ISelectionChangedListener selectionChangedListener;
138

    
139
    @Inject
140
    IEclipseContext context;
141

    
142
    @Inject
143
    private MPart thisPart;
144

    
145
    private BulkEditorQuery lastQuery = null;
146

    
147
    private Composite bottomComposite;
148

    
149
    @Inject
150
    private EMenuService menuService;
151

    
152
    private NatTable natTable;
153

    
154
    private DefaultBodyLayerStack bodyLayer;
155

    
156
    private ListDataProvider<CdmBase> bodyDataProvider;
157

    
158
    @Inject
159
    public BulkEditorE4() {
160
	}
161

    
162
	@SuppressWarnings("unused")
163
    public void init(AbstractBulkEditorInput<?> input){
164
	    this.input = input;
165
	    this.conversation = input.getConversation();
166

    
167
	    new BulkEditorSearchE4(this, topComposite, SWT.NONE);
168
	    //layout needed because the search bar is added after @PostConstuct method
169
	    topComposite.getParent().layout();
170

    
171
	    thisPart.setLabel(input.getEditorName());
172

    
173
        if(input.getEntityUuid()!=null){
174
            performSearch(new BulkEditorQuery(input.getEntityUuid().toString()));
175
        }
176

    
177
        createTable();
178

    
179
        configureTable();
180

    
181
        styleTable();
182

    
183
        GridDataFactory.fillDefaults().grab(true, true).applyTo(natTable);
184

    
185
        //propagate selection
186
        selectionChangedListener = (event -> selService.setSelection(getSelection()));
187
        RowSelectionProvider<CdmBase> selectionProvider = new RowSelectionProvider<CdmBase>(bodyLayer.getSelectionLayer(), bodyDataProvider, true);
188
        selectionProvider.addSelectionChangedListener(selectionChangedListener);
189

    
190
        bottomComposite.layout();
191
	}
192

    
193
	private void createTable(){
194
	    ConfigRegistry configRegistry = new ConfigRegistry();
195
	    //property map
196
        Map<String, String> propertyToLabels = new HashMap<>();
197
        propertyToLabels.put(getEditorInput().getName(), getEditorInput().getName());
198
        propertyToLabels.put(TYPE_PROPERTY, TYPE_PROPERTY);
199
        String[] propertyNames = new String[] { input.getName(), TYPE_PROPERTY };
200
        //sorted list
201
        SortedList<CdmBase> sortedList = new SortedList<>(input.getModel(), new TitleCacheComparator());
202
        //data provider
203
        BulkEditorPropertyAccessor columnPropertyAccessor = new BulkEditorPropertyAccessor(input);
204
        bodyDataProvider = new ListDataProvider<CdmBase>(sortedList,
205
                columnPropertyAccessor);
206
        DefaultColumnHeaderDataProvider colHeaderDataProvider = new DefaultColumnHeaderDataProvider(
207
                propertyNames, propertyToLabels);
208
        DefaultRowHeaderDataProvider rowHeaderDataProvider = new DefaultRowHeaderDataProvider(
209
                bodyDataProvider);
210
        //body
211
        DataLayer dataLayer = new DataLayer(bodyDataProvider);
212
        dataLayer.registerCommandHandler(new VisualRefreshCommandHandler());
213
        GlazedListsEventLayer<CdmBase> eventLayer = new GlazedListsEventLayer<>(dataLayer, input.getModel());
214
        bodyLayer = new DefaultBodyLayerStack(eventLayer);
215
        //column
216
        DataLayer columnHeaderDataLayer = new DataLayer(colHeaderDataProvider);
217
        ColumnHeaderLayer columnHeaderLayer = new ColumnHeaderLayer(
218
                columnHeaderDataLayer,
219
                bodyLayer, bodyLayer.getSelectionLayer());
220
        // add the SortHeaderLayer to the column header layer stack
221
        // as we use GlazedLists, we use the GlazedListsSortModel which
222
        // delegates the sorting to the SortedList
223
        final SortHeaderLayer<SpecimenDescription> sortHeaderLayer = new SortHeaderLayer<>(
224
                columnHeaderLayer,
225
                new GlazedListsSortModel<>(
226
                        sortedList,
227
                        columnPropertyAccessor,
228
                        configRegistry,
229
                        columnHeaderDataLayer));
230
        //row
231
        DataLayer rowHeaderDataLayer = new DataLayer(rowHeaderDataProvider);
232
        RowHeaderLayer rowHeaderLayer = new RowHeaderLayer(rowHeaderDataLayer,
233
                bodyLayer, bodyLayer.getSelectionLayer());
234
        rowHeaderDataLayer.setDefaultRowHeight(20);
235
        rowHeaderDataLayer.setColumnWidthByPosition(0, 50);
236
        rowHeaderDataLayer.setColumnWidthByPosition(1, 200);
237
        rowHeaderDataLayer.setColumnWidthByPosition(2, 100);
238

    
239
        //corner
240
        DefaultCornerDataProvider cornerDataProvider = new DefaultCornerDataProvider(
241
                colHeaderDataProvider, rowHeaderDataProvider);
242
        CornerLayer cornerLayer = new CornerLayer(new DataLayer(
243
                cornerDataProvider), rowHeaderLayer, sortHeaderLayer);
244
        //grid
245
        GridLayer gridLayer = new GridLayer(bodyLayer, sortHeaderLayer,
246
                rowHeaderLayer, cornerLayer);
247

    
248
        natTable = new NatTable(bottomComposite, gridLayer, false);
249
        natTable.setConfigRegistry(configRegistry);
250

    
251
        //full row selection
252
        bodyLayer.getSelectionLayer().setSelectionModel(new RowSelectionModel<CdmBase>(bodyLayer.getSelectionLayer(), bodyDataProvider, new IRowIdAccessor<CdmBase>() {
253
            @Override
254
            public Serializable getRowId(CdmBase rowObject) {
255
                return input.getModel().indexOf(rowObject);
256
            }
257
        }));
258
	}
259

    
260
	private void configureTable(){
261
        //+++CONTEXT MENU+++
262
        menuService.registerContextMenu(natTable, "eu.etaxonomy.taxeditor.bulkeditor.popupmenu.bulkeditor"); //$NON-NLS-1$
263
        // get the menu registered by EMenuService
264
        final Menu e4Menu = natTable.getMenu();
265
        // remove the menu reference from NatTable instance
266
        natTable.setMenu(null);
267
        natTable.addConfiguration(
268
                new AbstractUiBindingConfiguration() {
269
            @Override
270
            public void configureUiBindings(
271
                    UiBindingRegistry uiBindingRegistry) {
272
                // add e4 menu to NatTable
273
                new PopupMenuBuilder(natTable, e4Menu)
274
                    .build();
275

    
276
                // register the UI binding for header, corner and body region
277
                uiBindingRegistry.registerMouseDownBinding(
278
                        new MouseEventMatcher(
279
                                SWT.NONE,
280
                                GridRegion.BODY,
281
                                MouseEventMatcher.RIGHT_BUTTON),
282
                        new PopupMenuAction(e4Menu));
283
                uiBindingRegistry.registerMouseDownBinding(
284
                        new MouseEventMatcher(
285
                                SWT.NONE,
286
                                GridRegion.COLUMN_HEADER,
287
                                MouseEventMatcher.RIGHT_BUTTON),
288
                        new PopupMenuAction(e4Menu));
289
                uiBindingRegistry.registerMouseDownBinding(
290
                        new MouseEventMatcher(
291
                                SWT.NONE,
292
                                GridRegion.CORNER,
293
                                MouseEventMatcher.RIGHT_BUTTON),
294
                        new PopupMenuAction(e4Menu));
295
            }
296
        });
297

    
298
        //make cells editable to allow selecting the text
299
        natTable.addConfiguration(new AbstractRegistryConfiguration() {
300
            @Override
301
            public void configureRegistry(IConfigRegistry configRegistry) {
302
              //make cell editable
303
                configRegistry.registerConfigAttribute(
304
                        EditConfigAttributes.CELL_EDITABLE_RULE,
305
                        IEditableRule.ALWAYS_EDITABLE,
306
                        DisplayMode.EDIT);
307
                //register editor
308
                NullTextEditor nullTextEditor = new NullTextEditor();
309
                ContextInjectionFactory.inject(nullTextEditor, context);
310
                configRegistry.registerConfigAttribute(
311
                        EditConfigAttributes.CELL_EDITOR,
312
                        nullTextEditor,
313
                        DisplayMode.EDIT);
314
            }
315
        });
316

    
317
        //enable sorting
318
        natTable.addConfiguration(new SingleClickSortConfiguration());
319
        //add default configuration because autoconfigure is set to false in constructor
320
        natTable.addConfiguration(new DefaultNatTableStyleConfiguration());
321
        natTable.configure();
322
	}
323

    
324
	private void styleTable(){
325
	    natTable.setTheme(new ModernNatTableThemeConfiguration());
326
	}
327

    
328
	/** {@inheritDoc} */
329
	@PostConstruct
330
	public void createPartControl(Composite parent) {
331
		parent.setLayout(new GridLayout());
332

    
333
		topComposite = new Composite(parent, SWT.NONE);
334
		topComposite.setLayout(new GridLayout());
335

    
336
		GridData gridData = new GridData(SWT.FILL, SWT.TOP, true, false);
337
		topComposite.setLayoutData(gridData);
338

    
339
		bottomComposite = new Composite(parent, SWT.NONE);
340
		bottomComposite.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true));
341
		bottomComposite.setLayout(new GridLayout());
342
	}
343

    
344
	@Override
345
	@Persist
346
	public void save(IProgressMonitor monitor) {
347
	    save(monitor, true);
348
	}
349

    
350
	@Focus
351
	public void setFocus() {
352
        //make sure to bind again if maybe in another view the conversation was unbound
353
        if(conversation!=null && !conversation.isBound()){
354
            conversation.bind();
355
        }
356
        if(input!=null && input.getCdmEntitySession()!= null) {
357
            input.getCdmEntitySession().bind();
358
        }
359

    
360
	    //make sure to bind again if maybe in another view the conversation was unbound
361
	    eventBroker.post(WorkbenchEventConstants.CURRENT_ACTIVE_EDITOR, this);
362
	}
363

    
364
	@PreDestroy
365
	public void dispose() {
366
	    if(conversation!=null){
367
	        conversation.unregisterForDataStoreChanges(this);
368
	        conversation.close();
369
	    }
370
	    if(input!=null){
371
	        input.dispose();
372
	    }
373
	    dirty.setDirty(false);
374
	}
375

    
376
	public void save(IProgressMonitor monitor, boolean resetMerge) {
377
	    if (!input.getCdmEntitySession().isActive()){
378
            input.getCdmEntitySession().bind();
379
        }
380
	    input.saveModel(resetMerge);
381

    
382
	    IStructuredSelection selection = getSelection();
383

    
384
        dirty.setDirty(false);
385
        input.dispose();
386
        input.bind();
387
        conversation.commit(true);
388

    
389
        if (lastQuery != null){
390
            performSearch(lastQuery, selection);
391
        }
392
	}
393

    
394
	public void performSearch(BulkEditorQuery query) {
395
	    performSearch(query, null);
396
	}
397

    
398
	/** {@inheritDoc}
399
	 * @param selection */
400
    public void performSearch(BulkEditorQuery query, IStructuredSelection selection) {
401
        if (query != null) {
402
            // TODO check if dirty, prompt save
403
            if (isDirty()) {
404
                String[] labels = {Messages.BulkEditorE4_SAVE_AND_SEARCH, Messages.BulkEditorE4_DONT_SAVE,Messages.BulkEditorE4_CANCEL};
405
                MessageDialog dialog =new MessageDialog(topComposite.getShell(), Messages.BulkEditorE4_SAVE_CHANGES_TITLE, null, Messages.BulkEditorE4_SAVE_CHANGES_MESSAGE, MessageDialog.QUESTION,labels, 0);
406
                int result = dialog.open();
407
                if (result == 0) {
408
                    save(new NullProgressMonitor());
409
                } else if (result == 2){
410
                    return;
411
                }
412
            }
413
            dirty.setDirty(false);
414
            input.performSearch(query, selection);
415
            lastQuery = query;
416
        }
417
    }
418

    
419
    @Optional
420
    @Inject
421
    private void updateAfterSearch(@UIEventTopic(WorkbenchEventConstants.BULK_EDITOR_SEARCH_FINISHED)IStructuredSelection selection){
422
        if(selection!=null){
423
            setSelection(selection);
424
        }
425
//        //auto resize columns
426
//        InitializeAutoResizeColumnsCommand command = new InitializeAutoResizeColumnsCommand(
427
//                natTable, 2, natTable.getConfigRegistry(), new GCFactory(
428
//                        natTable));
429
//        natTable.doCommand(command);
430
//        command = new InitializeAutoResizeColumnsCommand(
431
//                natTable, 1, natTable.getConfigRegistry(), new GCFactory(
432
//                        natTable));
433
//        natTable.doCommand(command);
434
    }
435

    
436
    public void refresh(){
437
        natTable.doCommand(new VisualRefreshCommand());
438
    }
439

    
440
    public IStructuredSelection getSelection(){
441
        List<CdmBase> selection = new ArrayList<>();
442
        int[] fullySelectedRowPositions = bodyLayer.getSelectionLayer().getFullySelectedRowPositions();
443
        for (int i : fullySelectedRowPositions) {
444
            Object rowObject = bodyDataProvider.getRowObject(i);
445
            if(rowObject instanceof CdmBase){
446
                selection.add((CdmBase) rowObject);
447
            }
448
        }
449
        return new StructuredSelection(selection);
450
    }
451

    
452
    public void setSelection(IStructuredSelection selection){
453
        Object[] objects = selection.toArray();
454
        for (Object object : objects) {
455
            if(object instanceof CdmBase){
456
                bodyLayer.getSelectionLayer().selectRow(0, bodyDataProvider.indexOfRowObject((CdmBase) object), false, false);
457
            }
458
        }
459
    }
460

    
461
    public void setDirty(){
462
        dirty.setDirty(true);
463
    }
464

    
465
    public boolean isDirty() {
466
        return dirty.isDirty();
467
    }
468

    
469
    public AbstractBulkEditorInput getEditorInput() {
470
        return input;
471
    }
472

    
473
    public void copyDataToClipboard() {
474
        String textData = "";
475
        IStructuredSelection selection = getSelection();
476
        Object[] objects = selection.toArray();
477
        for (Object object : objects) {
478
            if(object instanceof CdmBase){
479
                textData += getEditorInput().getText((CdmBase)object);
480
            }
481
        }
482
        final TextTransfer textTransfer = TextTransfer.getInstance();
483
        final Clipboard clipboard = new Clipboard(Display.getDefault());
484
        try {
485
            clipboard.setContents(new Object[] { textData.toString() },
486
                    new Transfer[] { textTransfer });
487
        } finally {
488
            clipboard.dispose();
489
        }
490
    }
491

    
492
    @Override
493
    public void update(CdmDataChangeMap arg0) {
494
    }
495

    
496
    @Override
497
    public boolean canAttachMedia() {
498
        return true;
499
    }
500

    
501
    @Override
502
    public void changed(Object element) {
503
        if(element instanceof DerivedUnitFacade){
504
            DerivedUnit derivedUnit = ((DerivedUnitFacade) element).innerDerivedUnit();
505
            if(derivedUnit!=null){
506
                getEditorInput().addSaveCandidate(derivedUnit);
507
            }
508
            FieldUnit fieldUnit = ((DerivedUnitFacade) element).innerFieldUnit();
509
            if(fieldUnit!=null){
510
                getEditorInput().addSaveCandidate(fieldUnit);
511
            }
512
        }
513
        else if (element instanceof CdmBase) {
514
            getEditorInput().addSaveCandidate((CdmBase)element);
515
            input.replaceInModel((CdmBase) element);
516
        }
517
        dirty.setDirty(true);
518
        setSelection(new StructuredSelection(element));
519
    }
520

    
521
    @Override
522
    public void forceDirty() {
523
        dirty.setDirty(true);
524
    }
525

    
526
    @Override
527
    public boolean postOperation(CdmBase objectAffectedByOperation) {
528
        return false;
529
    }
530

    
531
    @Override
532
    public boolean onComplete() {
533
        return false;
534
    }
535

    
536
    @Override
537
    public ConversationHolder getConversationHolder() {
538
        return conversation;
539
    }
540

    
541
    public BulkEditorQuery getLastQuery() {
542
       return lastQuery;
543
    }
544

    
545
    public void setLastQuery(BulkEditorQuery lastQuery) {
546
       this.lastQuery = lastQuery;
547

    
548
    }
549

    
550
    @Override
551
    public Taxon getTaxon() {
552
        IStructuredSelection selection = getSelection();
553
        if(selection.size()==1) {
554
            Object object = selection.iterator().next();
555
            if(object instanceof Taxon){
556
                return (Taxon) object;
557
            }
558
        }
559
        return null;
560
    }
561

    
562
}
(1-1/5)