Project

General

Profile

Download (18.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.File;
13
import java.util.ArrayList;
14
import java.util.HashMap;
15
import java.util.List;
16
import java.util.Map;
17
import java.util.Properties;
18
import java.util.Set;
19

    
20
import javax.inject.Inject;
21

    
22
import org.eclipse.e4.ui.services.EMenuService;
23
import org.eclipse.e4.ui.workbench.modeling.ESelectionService;
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.CellConfigAttributes;
34
import org.eclipse.nebula.widgets.nattable.config.ConfigRegistry;
35
import org.eclipse.nebula.widgets.nattable.config.DefaultNatTableStyleConfiguration;
36
import org.eclipse.nebula.widgets.nattable.config.IConfigRegistry;
37
import org.eclipse.nebula.widgets.nattable.config.IEditableRule;
38
import org.eclipse.nebula.widgets.nattable.coordinate.Range;
39
import org.eclipse.nebula.widgets.nattable.data.ListDataProvider;
40
import org.eclipse.nebula.widgets.nattable.data.convert.DefaultBooleanDisplayConverter;
41
import org.eclipse.nebula.widgets.nattable.edit.EditConfigAttributes;
42
import org.eclipse.nebula.widgets.nattable.edit.action.MouseEditAction;
43
import org.eclipse.nebula.widgets.nattable.edit.config.DefaultEditConfiguration;
44
import org.eclipse.nebula.widgets.nattable.edit.editor.TextCellEditor;
45
import org.eclipse.nebula.widgets.nattable.extension.e4.selection.E4SelectionListener;
46
import org.eclipse.nebula.widgets.nattable.extension.glazedlists.GlazedListsEventLayer;
47
import org.eclipse.nebula.widgets.nattable.extension.glazedlists.GlazedListsSortModel;
48
import org.eclipse.nebula.widgets.nattable.grid.GridRegion;
49
import org.eclipse.nebula.widgets.nattable.grid.data.DefaultColumnHeaderDataProvider;
50
import org.eclipse.nebula.widgets.nattable.grid.data.DefaultCornerDataProvider;
51
import org.eclipse.nebula.widgets.nattable.grid.data.DefaultRowHeaderDataProvider;
52
import org.eclipse.nebula.widgets.nattable.grid.layer.ColumnHeaderLayer;
53
import org.eclipse.nebula.widgets.nattable.grid.layer.CornerLayer;
54
import org.eclipse.nebula.widgets.nattable.grid.layer.GridLayer;
55
import org.eclipse.nebula.widgets.nattable.grid.layer.RowHeaderLayer;
56
import org.eclipse.nebula.widgets.nattable.layer.AbstractLayer;
57
import org.eclipse.nebula.widgets.nattable.layer.DataLayer;
58
import org.eclipse.nebula.widgets.nattable.layer.stack.DefaultBodyLayerStack;
59
import org.eclipse.nebula.widgets.nattable.painter.cell.CheckBoxPainter;
60
import org.eclipse.nebula.widgets.nattable.painter.cell.ImagePainter;
61
import org.eclipse.nebula.widgets.nattable.sort.SortHeaderLayer;
62
import org.eclipse.nebula.widgets.nattable.sort.config.SingleClickSortConfiguration;
63
import org.eclipse.nebula.widgets.nattable.style.DisplayMode;
64
import org.eclipse.nebula.widgets.nattable.style.theme.ModernNatTableThemeConfiguration;
65
import org.eclipse.nebula.widgets.nattable.ui.binding.UiBindingRegistry;
66
import org.eclipse.nebula.widgets.nattable.ui.matcher.CellEditorMouseEventMatcher;
67
import org.eclipse.nebula.widgets.nattable.ui.matcher.MouseEventMatcher;
68
import org.eclipse.nebula.widgets.nattable.ui.menu.PopupMenuAction;
69
import org.eclipse.nebula.widgets.nattable.ui.menu.PopupMenuBuilder;
70
import org.eclipse.swt.SWT;
71
import org.eclipse.swt.dnd.Clipboard;
72
import org.eclipse.swt.dnd.TextTransfer;
73
import org.eclipse.swt.dnd.Transfer;
74
import org.eclipse.swt.layout.GridData;
75
import org.eclipse.swt.layout.GridLayout;
76
import org.eclipse.swt.widgets.Composite;
77
import org.eclipse.swt.widgets.Display;
78
import org.eclipse.swt.widgets.Menu;
79

    
80
import ca.odell.glazedlists.SortedList;
81
import eu.etaxonomy.cdm.model.common.CdmBase;
82
import eu.etaxonomy.cdm.model.description.SpecimenDescription;
83
import eu.etaxonomy.taxeditor.bulkeditor.BulkEditorQuery;
84
import eu.etaxonomy.taxeditor.bulkeditor.input.AbstractBulkEditorInput;
85
import eu.etaxonomy.taxeditor.model.ImageResources;
86
import eu.etaxonomy.taxeditor.store.StoreUtil;
87

    
88
/**
89
 *
90
 * @author pplitzner
91
 * @since Sep 8, 2017
92
 *
93
 */
94
public class BulkEditorE4Composite extends Composite {
95

    
96
    public static final String LABEL_CANDIDATE = "LABEL_CANDIDATE"; //$NON-NLS-1$
97
    public static final String LABEL_CANDIDATE_ICON = "LABEL_CANDIDATE_ICON"; //$NON-NLS-1$
98

    
99
    public static final String LABEL_TARGET = "LABEL_TARGET"; //$NON-NLS-1$
100
    public static final String LABEL_TARGET_ICON = "LABEL_TARGET_ICON"; //$NON-NLS-1$
101

    
102
    private 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
    private BulkEditorSearchE4 bulkEditorSearch;
124

    
125

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

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

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

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

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

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

    
147
        input.getPropertyKeys().forEach(key->columnList.add(key));
148

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

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

    
157
        createTable();
158

    
159
        configureTable();
160

    
161
        styleTable();
162

    
163
        GridDataFactory.fillDefaults().grab(true, true).applyTo(natTable);
164

    
165
        //propagate selection
166
        // selection listener
167
        E4SelectionListener<CdmBase> selectionListener = new CellSelectionListener(selService, bodyLayer.getSelectionLayer(), bodyDataProvider, this);
168
        bodyLayer.getSelectionLayer().addLayerListener(selectionListener);
169
        selectionListener.setFullySelectedRowsOnly(false);
170

    
171
        bottomComposite.layout();
172

    
173
	}
174

    
175
	private void createTable(){
176
	    ConfigRegistry configRegistry = new ConfigRegistry();
177
	    //property map
178
        Map<String, String> propertyToLabels = new HashMap<>();
179
        columnList.forEach(columnLabel->propertyToLabels.put(columnLabel, columnLabel));
180

    
181
        String[] propertyNames = columnList.toArray(columnList.toArray(new String[columnList.size()]));
182
        //sorted list
183
        SortedList<CdmBase> sortedList = new SortedList<>(bulkEditor.getEditorInput().getModel(), bulkEditor.getEditorInput().getTitleComparator());
184
        //data provider
185
        BulkEditorPropertyAccessor columnPropertyAccessor = new BulkEditorPropertyAccessor(this, bulkEditor.getEditorInput());
186
        bodyDataProvider = new ListDataProvider<CdmBase>(sortedList,
187
                columnPropertyAccessor);
188
        DefaultColumnHeaderDataProvider colHeaderDataProvider = new DefaultColumnHeaderDataProvider(
189
                propertyNames, propertyToLabels);
190
        DefaultRowHeaderDataProvider rowHeaderDataProvider = new DefaultRowHeaderDataProvider(
191
                bodyDataProvider);
192
        //body
193
        DataLayer dataLayer = new DataLayer(bodyDataProvider);
194
        dataLayer.registerCommandHandler(new VisualRefreshCommandHandler());
195
        GlazedListsEventLayer<CdmBase> eventLayer = new GlazedListsEventLayer<>(dataLayer, bulkEditor.getEditorInput().getModel());
196
        bodyLayer = new DefaultBodyLayerStack(eventLayer);
197

    
198
        dataLayer.setColumnPercentageSizing(0, true);
199
        dataLayer.setColumnWidthPercentageByPosition(0, 45);
200
        for(int i=1;i<columnList.size();i++){
201
            if(bulkEditor.getEditorInput().isCacheProperty(columnList.get(i))){
202
                dataLayer.setColumnWidthByPosition(i, 16);
203
            }
204
            else{
205
                dataLayer.setColumnWidthByPosition(i, 100);
206
            }
207
        }
208

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

    
232
        //corner
233
        DefaultCornerDataProvider cornerDataProvider = new DefaultCornerDataProvider(
234
                colHeaderDataProvider, rowHeaderDataProvider);
235
        DataLayer cornerDataLayer = new DataLayer(cornerDataProvider);
236
        CornerLayer cornerLayer = new CornerLayer(cornerDataLayer, rowHeaderLayer, sortHeaderLayer);
237
        //grid
238
        GridLayer gridLayer = new GridLayer(bodyLayer, sortHeaderLayer,
239
                rowHeaderLayer, cornerLayer, false);//set autoconfigure to false to get rid of the single click editing
240
        natTable = new NatTable(bottomComposite, gridLayer, false);
241

    
242
        dataLayer.setConfigLabelAccumulator(new BulkEditorConfigLabelAccumulator(bodyDataProvider, colHeaderDataProvider,
243
                bulkEditor.getEditorInput()));
244

    
245
        natTable.setConfigRegistry(configRegistry);
246

    
247
        //add tooltip to table
248
        new BulkEditorTooltip(natTable, colHeaderDataProvider);
249
	}
250

    
251
	private void configureTable(){
252

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

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

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

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

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

    
312

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

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

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

    
322
        //show boolean values as check boxes
323
        natTable.addConfiguration(new AbstractRegistryConfiguration() {
324
            @Override
325
            public void configureRegistry(IConfigRegistry configRegistry) {
326
                configRegistry.registerConfigAttribute(
327
                        CellConfigAttributes.CELL_PAINTER,
328
                        new CheckBoxPainter(),
329
                        DisplayMode.NORMAL,
330
                        BulkEditorConfigLabelAccumulatorHeader.BOOLEAN_COLUMN);
331

    
332
                configRegistry.registerConfigAttribute(
333
                        CellConfigAttributes.DISPLAY_CONVERTER,
334
                        new DefaultBooleanDisplayConverter(),
335
                        DisplayMode.NORMAL,
336
                        BulkEditorConfigLabelAccumulatorHeader.BOOLEAN_COLUMN);
337
            }
338
        });
339

    
340
        natTable.addConfiguration(new AbstractRegistryConfiguration() {
341
            @Override
342
            public void configureRegistry(IConfigRegistry configRegistry) {
343
                configRegistry.registerConfigAttribute(
344
                        CellConfigAttributes.CELL_PAINTER,
345
                        new ImagePainter(ImageResources.getImage(ImageResources.LOCK_ICON)),
346
                        DisplayMode.NORMAL,
347
                        BulkEditorConfigLabelAccumulatorHeader.CACHE_COLUMN);
348
            }
349
        });
350

    
351
        //register handler for view configuration menu
352
        natTable.registerCommandHandler(bulkEditorSearch.getDisplayPersistenceDialogCommandHandler());
353

    
354
        natTable.configure();
355
	}
356

    
357
	private void styleTable(){
358
	    natTable.setTheme(new ModernNatTableThemeConfiguration());
359
	}
360

    
361
	public void performSearch(BulkEditorQuery query) {
362
	    performSearch(query, null);
363
	}
364

    
365
	/** {@inheritDoc}
366
	 * @param selection */
367
    public void performSearch(BulkEditorQuery query, IStructuredSelection selection) {
368
        if (query != null) {
369
            if(StoreUtil.promptCheckIsDirty(bulkEditor)){
370
                return;
371
            }
372
            bulkEditor.getEditorInput().performSearch(query, selection);
373
            bulkEditor.setLastQuery(query);
374
        }
375
    }
376

    
377
    public void refresh(){
378
        natTable.doCommand(new VisualRefreshCommand());
379
    }
380

    
381
    public List<String> getColumnList() {
382
        return columnList;
383
    }
384

    
385
    public IStructuredSelection getSelection(){
386
        Set<Range> selectedRowPositions = bodyLayer.getSelectionLayer().getSelectedRowPositions();
387
        List<Object> selectedObjects = new ArrayList<>();
388
        for (Range range : selectedRowPositions) {
389
            for(int i=range.start;i<range.end;i++){
390
                selectedObjects.add(bodyDataProvider.getRowObject(i));
391
            }
392
        }
393
        return new StructuredSelection(selectedObjects);
394
    }
395

    
396
    public void setSelection(IStructuredSelection selection){
397
        Object[] objects = selection.toArray();
398
        for (Object object : objects) {
399

    
400
            if(object instanceof CdmBase &&  bulkEditor.getEditorInput().getModel().contains(object)){
401
                bodyLayer.getSelectionLayer().selectRow(0, bodyDataProvider.indexOfRowObject((CdmBase) object), false, false);
402
            }
403
        }
404
    }
405

    
406
    public void copyDataToClipboard() {
407
        String textData = ""; //$NON-NLS-1$
408
        IStructuredSelection selection = getSelection();
409
        Object[] objects = selection.toArray();
410
        for (Object object : objects) {
411
            if(object instanceof CdmBase){
412
                textData += bulkEditor.getEditorInput().getText((CdmBase)object);
413
            }
414
        }
415
        final TextTransfer textTransfer = TextTransfer.getInstance();
416
        final Clipboard clipboard = new Clipboard(Display.getDefault());
417
        try {
418
            clipboard.setContents(new Object[] { textData.toString() },
419
                    new Transfer[] { textTransfer });
420
        } finally {
421
            clipboard.dispose();
422
        }
423
    }
424

    
425
    ListDataProvider<CdmBase> getBodyDataProvider() {
426
        return bodyDataProvider;
427
    }
428

    
429
    ESelectionService getSelService() {
430
        return selService;
431
    }
432

    
433
    NatTable getNatTable() {
434
        return natTable;
435
    }
436

    
437
    public Properties getNatTableState() {
438
        return bulkEditorSearch.getNatTableState();
439
    }
440

    
441
    File getStatePropertiesFile() {
442
        return bulkEditorSearch.getStatePropertiesFile();
443
    }
444

    
445
}
(4-4/9)