Project

General

Profile

Download (16.8 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.inject.Inject;
19

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

    
77
import ca.odell.glazedlists.SortedList;
78
import eu.etaxonomy.cdm.model.common.CdmBase;
79
import eu.etaxonomy.cdm.model.description.SpecimenDescription;
80
import eu.etaxonomy.taxeditor.bulkeditor.BulkEditorQuery;
81
import eu.etaxonomy.taxeditor.bulkeditor.input.AbstractBulkEditorInput;
82
import eu.etaxonomy.taxeditor.l10n.Messages;
83

    
84
/**
85
 *
86
 * @author pplitzner
87
 * @since Sep 8, 2017
88
 *
89
 */
90
public class BulkEditorE4Composite extends Composite {
91

    
92
    public static final String TYPE_PROPERTY = Messages.BulkEditorE4_TYPE;
93

    
94
    public static final String ID_PROPERTY = "Id";
95

    
96
    public static final String UUID_PROPERTY = "Uuid";
97

    
98
    public static final String CANDIDATE_LABEL = "candidate";
99

    
100
    public static final String TARGET_LABEL = "target";
101

    
102
    public static final List<String> columnList = new ArrayList<>();
103

    
104
    private Composite topComposite;
105

    
106
    @Inject
107
    private ESelectionService selService;
108

    
109
    private ISelectionChangedListener selectionChangedListener;
110

    
111
    private Composite bottomComposite;
112

    
113
    @Inject
114
    private EMenuService menuService;
115

    
116
    private NatTable natTable;
117

    
118
    private DefaultBodyLayerStack bodyLayer;
119

    
120
    private ListDataProvider<CdmBase> bodyDataProvider;
121

    
122
    private BulkEditorE4 bulkEditor;
123

    
124

    
125
    public BulkEditorE4Composite(BulkEditorE4 bulkEditor, Composite parent, int style) {
126
        super(parent, style);
127
        parent.setLayout(new GridLayout());
128
        this.bulkEditor = bulkEditor;
129

    
130
        this.setLayout(new GridLayout());
131

    
132
        topComposite = new Composite(parent, SWT.NONE);
133
        topComposite.setLayout(new GridLayout());
134

    
135
        GridData gridData = new GridData(SWT.FILL, SWT.TOP, true, false);
136
        topComposite.setLayoutData(gridData);
137

    
138
        bottomComposite = new Composite(parent, SWT.NONE);
139
        bottomComposite.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true));
140
        bottomComposite.setLayout(new GridLayout());
141
	}
142

    
143
	@SuppressWarnings("unused")
144
    public void init(AbstractBulkEditorInput<?> input){
145

    
146
        columnList.add(input.getName());
147
        columnList.add(TYPE_PROPERTY);
148
        columnList.add(UUID_PROPERTY);
149
        columnList.add(ID_PROPERTY);
150

    
151
	    new BulkEditorSearchE4(this, topComposite, SWT.NONE);
152
	    //layout needed because the search bar is added after @PostConstuct method
153
	    topComposite.getParent().layout();
154

    
155
        if(input.getEntityUuid()!=null){
156
            performSearch(new BulkEditorQuery(input.getEntityUuid().toString()));
157
        }
158

    
159
        createTable();
160

    
161
        configureTable();
162

    
163
        styleTable();
164

    
165
        GridDataFactory.fillDefaults().grab(true, true).applyTo(natTable);
166

    
167
        //propagate selection
168
        selectionChangedListener = (event -> selService.setSelection(getSelection()));
169
        RowSelectionProvider<CdmBase> selectionProvider = new RowSelectionProvider<CdmBase>(bodyLayer.getSelectionLayer(), bodyDataProvider, true);
170
        selectionProvider.addSelectionChangedListener(selectionChangedListener);
171

    
172
        bottomComposite.layout();
173
	}
174

    
175
	private void createTable(){
176
	    ConfigRegistry configRegistry = new ConfigRegistry();
177
	    //property map
178
        Map<String, String> propertyToLabels = new HashMap<>();
179
        for(String columnLabel:columnList){
180
            propertyToLabels.put(columnLabel, columnLabel);
181
        }
182
        String[] propertyNames = columnList.toArray(columnList.toArray(new String[columnList.size()]));
183
        //sorted list
184
        SortedList<CdmBase> sortedList = new SortedList<>(bulkEditor.getEditorInput().getModel(), bulkEditor.getEditorInput().getTitleComparator());
185
        //data provider
186
        BulkEditorPropertyAccessor columnPropertyAccessor = new BulkEditorPropertyAccessor(bulkEditor.getEditorInput());
187
        bodyDataProvider = new ListDataProvider<CdmBase>(sortedList,
188
                columnPropertyAccessor);
189
        DefaultColumnHeaderDataProvider colHeaderDataProvider = new DefaultColumnHeaderDataProvider(
190
                propertyNames, propertyToLabels);
191
        DefaultRowHeaderDataProvider rowHeaderDataProvider = new DefaultRowHeaderDataProvider(
192
                bodyDataProvider);
193
        //body
194
        DataLayer dataLayer = new DataLayer(bodyDataProvider);
195
        dataLayer.registerCommandHandler(new VisualRefreshCommandHandler());
196
        GlazedListsEventLayer<CdmBase> eventLayer = new GlazedListsEventLayer<>(dataLayer, bulkEditor.getEditorInput().getModel());
197
        bodyLayer = new DefaultBodyLayerStack(eventLayer);
198

    
199
        dataLayer.setColumnPercentageSizing(0, true);
200
        dataLayer.setColumnWidthPercentageByPosition(0, 65);
201
        dataLayer.setColumnWidthByPosition(1, 100);
202
        dataLayer.setColumnWidthByPosition(2, 70);
203
        dataLayer.setColumnWidthByPosition(3, 50);
204

    
205
        //column
206
        DataLayer columnHeaderDataLayer = new DataLayer(colHeaderDataProvider);
207
        ColumnHeaderLayer columnHeaderLayer = new ColumnHeaderLayer(
208
                columnHeaderDataLayer,
209
                bodyLayer, bodyLayer.getSelectionLayer());
210
        // add the SortHeaderLayer to the column header layer stack
211
        // as we use GlazedLists, we use the GlazedListsSortModel which
212
        // delegates the sorting to the SortedList
213
        final SortHeaderLayer<SpecimenDescription> sortHeaderLayer = new SortHeaderLayer<>(
214
                columnHeaderLayer,
215
                new GlazedListsSortModel<>(
216
                        sortedList,
217
                        columnPropertyAccessor,
218
                        configRegistry,
219
                        columnHeaderDataLayer));
220
        //row
221
        DataLayer rowHeaderDataLayer = new DataLayer(rowHeaderDataProvider);
222
        RowHeaderLayer rowHeaderLayer = new RowHeaderLayer(rowHeaderDataLayer,
223
                bodyLayer, bodyLayer.getSelectionLayer());
224
        rowHeaderDataLayer.setColumnWidthByPosition(0, 50);
225

    
226
        //corner
227
        DefaultCornerDataProvider cornerDataProvider = new DefaultCornerDataProvider(
228
                colHeaderDataProvider, rowHeaderDataProvider);
229
        DataLayer cornerDataLayer = new DataLayer(cornerDataProvider);
230
        CornerLayer cornerLayer = new CornerLayer(cornerDataLayer, rowHeaderLayer, sortHeaderLayer);
231
        //grid
232
        GridLayer gridLayer = new GridLayer(bodyLayer, sortHeaderLayer,
233
                rowHeaderLayer, cornerLayer, false);//set autoconfigure to false to get rid of the single click editing
234
        natTable = new NatTable(bottomComposite, gridLayer, false);
235
        natTable.setConfigRegistry(configRegistry);
236

    
237
        //full row selection
238
        bodyLayer.getSelectionLayer().setSelectionModel(new RowSelectionModel<CdmBase>(bodyLayer.getSelectionLayer(), bodyDataProvider, new IRowIdAccessor<CdmBase>() {
239
            @Override
240
            public Serializable getRowId(CdmBase rowObject) {
241
                return bulkEditor.getEditorInput().getModel().indexOf(rowObject);
242
            }
243
        }));
244

    
245
        //add label to deduplication rows
246
        dataLayer.setConfigLabelAccumulator(new BulkEditorConfigLabelAccumulator(natTable, bodyDataProvider, bulkEditor.getEditorInput()));
247

    
248
        //add tooltip to table
249
        new BulkEditorTooltip(natTable);
250
	}
251

    
252
	private void configureTable(){
253

    
254
	    //this configuration enables cell to be editable in general
255
	    //necessary because we disabled this beforehand by setting autoconfigure=false
256
	    //in the GridLayer constructor
257
	    ((AbstractLayer) natTable.getLayer()).addConfiguration(new DefaultEditConfiguration());
258

    
259
        natTable.addConfiguration(new AbstractUiBindingConfiguration() {
260
            @Override
261
            public void configureUiBindings(UiBindingRegistry uiBindingRegistry) {
262
                uiBindingRegistry.registerFirstDoubleClickBinding(new CellEditorMouseEventMatcher(GridRegion.BODY),
263
                        new MouseEditAction());
264
            }
265
        });
266

    
267
        //make cells editable to allow selecting the text
268
        natTable.addConfiguration(new AbstractRegistryConfiguration() {
269
            @Override
270
            public void configureRegistry(IConfigRegistry configRegistry) {
271
                //make cell editable
272
                configRegistry.registerConfigAttribute(
273
                        EditConfigAttributes.CELL_EDITABLE_RULE,
274
                        IEditableRule.ALWAYS_EDITABLE,
275
                        DisplayMode.EDIT);
276
                //register editor
277
                TextCellEditor editor = new TextCellEditor();
278
                editor.setEditable(false);
279
                configRegistry.registerConfigAttribute(
280
                        EditConfigAttributes.CELL_EDITOR,
281
                        editor,
282
                        DisplayMode.NORMAL);
283
            }
284
        });
285

    
286
        //+++CONTEXT MENU+++
287
        menuService.registerContextMenu(natTable, "eu.etaxonomy.taxeditor.bulkeditor.popupmenu.bulkeditor"); //$NON-NLS-1$
288
        // get the menu registered by EMenuService
289
        final Menu e4Menu = natTable.getMenu();
290
        // remove the menu reference from NatTable instance
291
        natTable.setMenu(null);
292
        natTable.addConfiguration(
293
                new AbstractUiBindingConfiguration() {
294
            @Override
295
            public void configureUiBindings(
296
                    UiBindingRegistry uiBindingRegistry) {
297
                // add e4 menu to NatTable
298
                new PopupMenuBuilder(natTable, e4Menu)
299
                    .build();
300

    
301
                // register the UI binding for header, corner and body region
302
                uiBindingRegistry.registerMouseDownBinding(
303
                        new MouseEventMatcher(
304
                                SWT.NONE,
305
                                null,
306
                                MouseEventMatcher.RIGHT_BUTTON),
307
                        new PopupMenuAction(e4Menu));
308
            }
309
        });
310

    
311

    
312
        //enable sorting
313
        natTable.addConfiguration(new SingleClickSortConfiguration());
314

    
315
        // Custom style for deduplication labels
316
        natTable.addConfiguration(new BulkEditorLabelStyleConfiguration());
317

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

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

    
327
	public void performSearch(BulkEditorQuery query) {
328
	    performSearch(query, null);
329
	}
330

    
331
	/** {@inheritDoc}
332
	 * @param selection */
333
    public void performSearch(BulkEditorQuery query, IStructuredSelection selection) {
334
        if (query != null) {
335
            if (bulkEditor.isDirty()) {
336
                String[] labels = {Messages.BulkEditorE4_SAVE_AND_SEARCH, Messages.BulkEditorE4_DONT_SAVE,Messages.BulkEditorE4_CANCEL};
337
                MessageDialog dialog =new MessageDialog(topComposite.getShell(), Messages.BulkEditorE4_SAVE_CHANGES_TITLE, null, Messages.BulkEditorE4_SAVE_CHANGES_MESSAGE, MessageDialog.QUESTION,labels, 0);
338
                int result = dialog.open();
339
                if (result == 0) {
340
                    bulkEditor.save(new NullProgressMonitor());
341
                } else if (result == 2){
342
                    return;
343
                }
344
            }
345
            bulkEditor.setDirty(false);
346
            bulkEditor.getEditorInput().performSearch(query, selection);
347
            bulkEditor.setLastQuery(query);
348
        }
349
    }
350

    
351
    public void refresh(){
352
        natTable.doCommand(new VisualRefreshCommand());
353
    }
354

    
355
    public IStructuredSelection getSelection(){
356
        List<CdmBase> selection = new ArrayList<>();
357
        int[] fullySelectedRowPositions = bodyLayer.getSelectionLayer().getFullySelectedRowPositions();
358
        for (int i : fullySelectedRowPositions) {
359
            if(i<0){
360
                continue;
361
            }
362
            Object rowObject = bodyDataProvider.getRowObject(i);
363
            if(rowObject instanceof CdmBase){
364
                selection.add((CdmBase) rowObject);
365
            }
366
        }
367
        return new StructuredSelection(selection);
368
    }
369

    
370
    public void setSelection(IStructuredSelection selection){
371
        Object[] objects = selection.toArray();
372
        for (Object object : objects) {
373

    
374
            if(object instanceof CdmBase &&  bulkEditor.getEditorInput().getModel().contains(object)){
375
                bodyLayer.getSelectionLayer().selectRow(0, bodyDataProvider.indexOfRowObject((CdmBase) object), false, false);
376
            }
377
        }
378
    }
379

    
380
    public void copyDataToClipboard() {
381
        String textData = "";
382
        IStructuredSelection selection = getSelection();
383
        Object[] objects = selection.toArray();
384
        for (Object object : objects) {
385
            if(object instanceof CdmBase){
386
                textData += bulkEditor.getEditorInput().getText((CdmBase)object);
387
            }
388
        }
389
        final TextTransfer textTransfer = TextTransfer.getInstance();
390
        final Clipboard clipboard = new Clipboard(Display.getDefault());
391
        try {
392
            clipboard.setContents(new Object[] { textData.toString() },
393
                    new Transfer[] { textTransfer });
394
        } finally {
395
            clipboard.dispose();
396
        }
397
    }
398

    
399
}
(3-3/7)