commit 029aa66a2a846a47f929e4656fbe112df52506a6
Author: Patrick Plitzner <p.plitzner@bgbm.org>
Date:   Wed Jun 20 09:09:28 2018 +0200

    ref #7439 Add sorting and cell text left-align to bulk editor nat table

diff --git a/eu.etaxonomy.taxeditor.bulkeditor/src/main/java/eu/etaxonomy/taxeditor/bulkeditor/e4/BulkEditorE4.java b/eu.etaxonomy.taxeditor.bulkeditor/src/main/java/eu/etaxonomy/taxeditor/bulkeditor/e4/BulkEditorE4.java
index da3058f7a..7769058bc 100644
--- a/eu.etaxonomy.taxeditor.bulkeditor/src/main/java/eu/etaxonomy/taxeditor/bulkeditor/e4/BulkEditorE4.java
+++ b/eu.etaxonomy.taxeditor.bulkeditor/src/main/java/eu/etaxonomy/taxeditor/bulkeditor/e4/BulkEditorE4.java
@@ -36,10 +36,12 @@ import org.eclipse.jface.viewers.StructuredSelection;
 import org.eclipse.nebula.widgets.nattable.NatTable;
 import org.eclipse.nebula.widgets.nattable.command.VisualRefreshCommand;
 import org.eclipse.nebula.widgets.nattable.config.AbstractUiBindingConfiguration;
+import org.eclipse.nebula.widgets.nattable.config.ConfigRegistry;
 import org.eclipse.nebula.widgets.nattable.config.DefaultNatTableStyleConfiguration;
 import org.eclipse.nebula.widgets.nattable.data.IRowIdAccessor;
 import org.eclipse.nebula.widgets.nattable.data.ListDataProvider;
 import org.eclipse.nebula.widgets.nattable.extension.glazedlists.GlazedListsEventLayer;
+import org.eclipse.nebula.widgets.nattable.extension.glazedlists.GlazedListsSortModel;
 import org.eclipse.nebula.widgets.nattable.grid.GridRegion;
 import org.eclipse.nebula.widgets.nattable.grid.data.DefaultColumnHeaderDataProvider;
 import org.eclipse.nebula.widgets.nattable.grid.data.DefaultCornerDataProvider;
@@ -53,6 +55,9 @@ import org.eclipse.nebula.widgets.nattable.layer.stack.DefaultBodyLayerStack;
 import org.eclipse.nebula.widgets.nattable.selection.RowSelectionModel;
 import org.eclipse.nebula.widgets.nattable.selection.RowSelectionProvider;
 import org.eclipse.nebula.widgets.nattable.selection.SelectionLayer;
+import org.eclipse.nebula.widgets.nattable.sort.SortHeaderLayer;
+import org.eclipse.nebula.widgets.nattable.sort.config.SingleClickSortConfiguration;
+import org.eclipse.nebula.widgets.nattable.style.theme.ModernNatTableThemeConfiguration;
 import org.eclipse.nebula.widgets.nattable.ui.binding.UiBindingRegistry;
 import org.eclipse.nebula.widgets.nattable.ui.matcher.MouseEventMatcher;
 import org.eclipse.nebula.widgets.nattable.ui.menu.PopupMenuAction;
@@ -67,10 +72,12 @@ import org.eclipse.swt.widgets.Composite;
 import org.eclipse.swt.widgets.Display;
 import org.eclipse.swt.widgets.Menu;
 
+import ca.odell.glazedlists.SortedList;
 import eu.etaxonomy.cdm.api.conversation.ConversationHolder;
 import eu.etaxonomy.cdm.api.conversation.IConversationEnabled;
 import eu.etaxonomy.cdm.api.facade.DerivedUnitFacade;
 import eu.etaxonomy.cdm.model.common.CdmBase;
+import eu.etaxonomy.cdm.model.description.SpecimenDescription;
 import eu.etaxonomy.cdm.model.occurrence.DerivedUnit;
 import eu.etaxonomy.cdm.model.occurrence.FieldUnit;
 import eu.etaxonomy.cdm.model.taxon.Taxon;
@@ -87,6 +94,7 @@ import eu.etaxonomy.taxeditor.model.IPartContentHasFactualData;
 import eu.etaxonomy.taxeditor.model.IPartContentHasMedia;
 import eu.etaxonomy.taxeditor.model.IPartContentHasSupplementalData;
 import eu.etaxonomy.taxeditor.operation.IPostOperationEnabled;
+import eu.etaxonomy.taxeditor.ui.section.DefaultCdmBaseComparator;
 import eu.etaxonomy.taxeditor.workbench.part.IE4SavablePart;
 
 /**
@@ -153,14 +161,33 @@ public class BulkEditorE4 implements IPartContentHasDetails, IConversationEnable
             performSearch(new BulkEditorQuery(input.getEntityUuid().toString(), null));
         }
 
-        //++++NatTable++++
+        createTable();
+
+        configureTable();
+
+        styleTable();
+
+        GridDataFactory.fillDefaults().grab(true, true).applyTo(natTable);
+
+        //propagate selection
+        selectionChangedListener = (event -> selService.setSelection(getSelection()));
+        RowSelectionProvider<CdmBase> selectionProvider = new RowSelectionProvider<CdmBase>(selectionLayer, bodyDataProvider, true);
+        selectionProvider.addSelectionChangedListener(selectionChangedListener);
+	}
+
+	private void createTable(){
+	    ConfigRegistry configRegistry = new ConfigRegistry();
+	    //property map
         Map<String, String> propertyToLabels = new HashMap<>();
         propertyToLabels.put(getEditorInput().getName(), getEditorInput().getName());
         propertyToLabels.put(TYPE_PROPERTY, TYPE_PROPERTY);
         String[] propertyNames = new String[] { getEditorInput().getName(), TYPE_PROPERTY };
+        //sorted list
+        SortedList<CdmBase> sortedList = new SortedList<>(getEditorInput().getModel(), new DefaultCdmBaseComparator<CdmBase>());
         //data provider
-        bodyDataProvider = new ListDataProvider<CdmBase>(getEditorInput().getModel(),
-                new BulkEditorPropertyAccessor(getEditorInput()));
+        BulkEditorPropertyAccessor columnPropertyAccessor = new BulkEditorPropertyAccessor(getEditorInput());
+        bodyDataProvider = new ListDataProvider<CdmBase>(sortedList,
+                columnPropertyAccessor);
         DefaultColumnHeaderDataProvider colHeaderDataProvider = new DefaultColumnHeaderDataProvider(
                 propertyNames, propertyToLabels);
         DefaultRowHeaderDataProvider rowHeaderDataProvider = new DefaultRowHeaderDataProvider(
@@ -171,9 +198,20 @@ public class BulkEditorE4 implements IPartContentHasDetails, IConversationEnable
         DefaultBodyLayerStack bodyLayer = new DefaultBodyLayerStack(eventLayer);
         selectionLayer = bodyLayer.getSelectionLayer();
         //column
+        DataLayer columnHeaderDataLayer = new DataLayer(colHeaderDataProvider);
         ColumnHeaderLayer columnHeaderLayer = new ColumnHeaderLayer(
-                new DataLayer(colHeaderDataProvider),
+                columnHeaderDataLayer,
                 bodyLayer, bodyLayer.getSelectionLayer());
+        // add the SortHeaderLayer to the column header layer stack
+        // as we use GlazedLists, we use the GlazedListsSortModel which
+        // delegates the sorting to the SortedList
+        final SortHeaderLayer<SpecimenDescription> sortHeaderLayer = new SortHeaderLayer<>(
+                columnHeaderLayer,
+                new GlazedListsSortModel<>(
+                        sortedList,
+                        columnPropertyAccessor,
+                        configRegistry,
+                        columnHeaderDataLayer));
         //row
         RowHeaderLayer rowHeaderLayer = new RowHeaderLayer(new DataLayer(rowHeaderDataProvider, 50, 20),
                 bodyLayer, bodyLayer.getSelectionLayer());
@@ -181,13 +219,26 @@ public class BulkEditorE4 implements IPartContentHasDetails, IConversationEnable
         DefaultCornerDataProvider cornerDataProvider = new DefaultCornerDataProvider(
                 colHeaderDataProvider, rowHeaderDataProvider);
         CornerLayer cornerLayer = new CornerLayer(new DataLayer(
-                cornerDataProvider), rowHeaderLayer, columnHeaderLayer);
-
-        GridLayer gridLayer = new GridLayer(bodyLayer, columnHeaderLayer,
+                cornerDataProvider), rowHeaderLayer, sortHeaderLayer);
+        //grid
+        GridLayer gridLayer = new GridLayer(bodyLayer, sortHeaderLayer,
                 rowHeaderLayer, cornerLayer);
+
         dataLayer.setColumnPercentageSizing(true);
+
         natTable = new NatTable(bottomComposite, gridLayer, false);
+        natTable.setConfigRegistry(configRegistry);
 
+        //full row selection
+        bodyLayer.getSelectionLayer().setSelectionModel(new RowSelectionModel<CdmBase>(bodyLayer.getSelectionLayer(), bodyDataProvider, new IRowIdAccessor<CdmBase>() {
+            @Override
+            public Serializable getRowId(CdmBase rowObject) {
+                return getEditorInput().getModel().indexOf(rowObject);
+            }
+        }));
+	}
+
+	private void configureTable(){
         //+++CONTEXT MENU+++
         menuService.registerContextMenu(natTable, "eu.etaxonomy.taxeditor.bulkeditor.popupmenu.bulkeditor"); //$NON-NLS-1$
         // get the menu registered by EMenuService
@@ -225,25 +276,15 @@ public class BulkEditorE4 implements IPartContentHasDetails, IConversationEnable
             }
         });
 
+        //enable sorting
+        natTable.addConfiguration(new SingleClickSortConfiguration());
         //add default configuration because autoconfigure is set to false in constructor
         natTable.addConfiguration(new DefaultNatTableStyleConfiguration());
         natTable.configure();
-        GridDataFactory.fillDefaults().grab(true, true).applyTo(natTable);
-
-        //full row selection
-        bodyLayer.getSelectionLayer().setSelectionModel(new RowSelectionModel<CdmBase>(bodyLayer.getSelectionLayer(), bodyDataProvider, new IRowIdAccessor<CdmBase>() {
-
-            @Override
-            public Serializable getRowId(CdmBase rowObject) {
-                return getEditorInput().getModel().indexOf(rowObject);
-            }
-
-        }));
+	}
 
-        //propagate selection
-        selectionChangedListener = (event -> selService.setSelection(getSelection()));
-        RowSelectionProvider<CdmBase> selectionProvider = new RowSelectionProvider<CdmBase>(selectionLayer, bodyDataProvider, true);
-        selectionProvider.addSelectionChangedListener(selectionChangedListener);
+	private void styleTable(){
+	    natTable.setTheme(new ModernNatTableThemeConfiguration());
 	}
 
 	/** {@inheritDoc} */
