diff --git a/.gitignore b/.gitignore
index 5abffee43749afc5d07d2735617b71e4130a8b93..b2f15ce895696fd311b35bd9ebb831c094d75ac0 100644
--- a/.gitignore
+++ b/.gitignore
@@ -7,4 +7,5 @@ bin/
 *.jar
 .classpath
 .project
-export.jardesc
\ No newline at end of file
+export.jardesc
+**/.DS_Store
\ No newline at end of file
diff --git a/pom.xml b/pom.xml
index 60cfc9066a4a919ad3666494740ec0a97fe5d6e0..a5ccbe4314135b83ced5fd81681d37cdcd1af00a 100644
--- a/pom.xml
+++ b/pom.xml
@@ -6,12 +6,12 @@
 
     <parent>
         <groupId>org.bioimageanalysis.icy</groupId>
-        <artifactId>parent-pom-plugin</artifactId>
-        <version>1.0.6</version>
+        <artifactId>pom-icy</artifactId>
+        <version>2.2.0</version>
     </parent>
 
     <artifactId>workbooks</artifactId>
-    <version>3.4.12</version>
+    <version>4.0.0</version>
 
     <packaging>jar</packaging>
 
@@ -20,27 +20,49 @@
         Toolbox to create and manipulate result tables with plug-ins and protocols, and export as text file or to your favorite spreadsheet software
     </description>
 
+    <properties>
+        <artifact-to-extract>JMathPlot,poi,poi-ooxml,poi-ooxml-lite,log4j-api,log4j-core</artifact-to-extract>
+    </properties>
+
     <dependencies>
         <dependency>
             <groupId>org.bioimageanalysis.icy</groupId>
-            <artifactId>blocks</artifactId>
-            <version>${blocks.version}</version>
+            <artifactId>protocols</artifactId>
         </dependency>
+
         <dependency>
             <groupId>com.github.yannrichet</groupId>
             <artifactId>JMathPlot</artifactId>
             <version>1.0.1</version>
         </dependency>
+
+        <dependency>
+            <groupId>org.apache.poi</groupId>
+            <artifactId>poi-ooxml</artifactId>
+            <version>5.2.3</version>
+        </dependency>
         <dependency>
             <groupId>org.apache.poi</groupId>
             <artifactId>poi</artifactId>
-            <version>3.17</version>
+            <version>5.2.3</version>
         </dependency>
         <dependency>
             <groupId>org.apache.poi</groupId>
-            <artifactId>poi-ooxml</artifactId>
-            <version>3.17</version>
+            <artifactId>poi-ooxml-lite</artifactId>
+            <version>5.2.3</version>
+        </dependency>
+
+        <dependency>
+            <groupId>org.apache.logging.log4j</groupId>
+            <artifactId>log4j-api</artifactId>
+            <version>2.20.0</version>
         </dependency>
+        <dependency>
+            <groupId>org.apache.logging.log4j</groupId>
+            <artifactId>log4j-core</artifactId>
+            <version>2.20.0</version>
+        </dependency>
+
     </dependencies>
 
     <repositories>
diff --git a/src/main/java/plugins/adufour/blocks/tools/io/FileToWorkbook.java b/src/main/java/plugins/adufour/blocks/tools/io/FileToWorkbook.java
index de15784f17d15320bd89c81270fa9db35ab5729b..a571dc7fa006b368d1e1224e49a2a3c007e4919a 100644
--- a/src/main/java/plugins/adufour/blocks/tools/io/FileToWorkbook.java
+++ b/src/main/java/plugins/adufour/blocks/tools/io/FileToWorkbook.java
@@ -1,48 +1,57 @@
-package plugins.adufour.blocks.tools.io;
-
-import java.io.BufferedReader;
-import java.io.File;
-import java.io.FileInputStream;
-import java.io.FileReader;
+/*
+ * Copyright (c) 2010-2023. Institut Pasteur.
+ *
+ * This file is part of Icy.
+ * Icy is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Icy is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Icy. If not, see <https://www.gnu.org/licenses/>.
+ */
 
-import org.apache.poi.ss.usermodel.Cell;
-import org.apache.poi.ss.usermodel.Row;
-import org.apache.poi.ss.usermodel.Sheet;
-import org.apache.poi.ss.usermodel.Workbook;
-import org.apache.poi.ss.usermodel.WorkbookFactory;
+package plugins.adufour.blocks.tools.io;
 
 import icy.plugin.abstract_.Plugin;
+import org.apache.poi.ss.usermodel.*;
 import plugins.adufour.blocks.tools.io.WorkbookToFile.MergePolicy;
 import plugins.adufour.blocks.util.VarList;
 import plugins.adufour.vars.lang.VarFile;
 import plugins.adufour.vars.lang.VarWorkbook;
 import plugins.adufour.workbooks.Workbooks;
 
+import java.io.BufferedReader;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileReader;
+
 /**
  * IO block that reads a workbook file from disk using the POI library
- * 
+ *
  * @author Alexandre Dufour
  */
-public class FileToWorkbook extends Plugin implements IOBlock
-{
+public class FileToWorkbook extends Plugin implements IOBlock {
     VarFile inputFile = new VarFile("input file", null);
     VarWorkbook workbook = new VarWorkbook("workbook", (Workbook) null);
 
     @Override
-    public void run()
-    {
+    public void run() {
         workbook.setValue(readWorkbook(inputFile.getValue(true)));
     }
 
     @Override
-    public void declareInput(VarList inputMap)
-    {
+    public void declareInput(final VarList inputMap) {
         inputMap.add("input file", inputFile);
     }
 
     @Override
-    public void declareOutput(VarList outputMap)
-    {
+    public void declareOutput(final VarList outputMap) {
         outputMap.add("workbook", workbook);
     }
 
@@ -57,41 +66,34 @@ public class FileToWorkbook extends Plugin implements IOBlock
      * item3 (tab) item4</code><br>
      * (the same convention is followed by
      * {@link WorkbookToFile#saveAsText(Workbook, String, MergePolicy)}
-     * 
-     * @param file
-     *        input file
+     *
+     * @param file input file
      * @return the workbook read from input file
      */
-    public static Workbook readWorkbook(File file)
-    {
+    public static Workbook readWorkbook(final File file) {
         if (!file.exists() || file.isDirectory())
             throw new IllegalArgumentException("Cannot read a workbook from " + file.getPath());
 
-        try
-        {
-            FileInputStream fis = new FileInputStream(file);
-            Workbook workbook = WorkbookFactory.create(fis);
+        try {
+            final FileInputStream fis = new FileInputStream(file);
+            final Workbook workbook = WorkbookFactory.create(fis);
             fis.close();
             return workbook;
         }
-        catch (Exception e)
-        {
+        catch (final Exception e) {
             // try text
-            Workbook wb = Workbooks.createEmptyWorkbook();
+            final Workbook wb = Workbooks.createEmptyWorkbook();
             Sheet sheet = null;
 
-            try
-            {
-                BufferedReader reader = new BufferedReader(new FileReader(file));
+            try {
+                final BufferedReader reader = new BufferedReader(new FileReader(file));
                 int rowID = 0;
                 boolean newLine = false;
 
-                while (reader.ready())
-                {
-                    String line = reader.readLine();
+                while (reader.ready()) {
+                    final String line = reader.readLine();
 
-                    if (line.isEmpty())
-                    {
+                    if (line.isEmpty()) {
                         // remember there is a new line, deal with it later
                         newLine = true;
                         continue;
@@ -100,11 +102,10 @@ public class FileToWorkbook extends Plugin implements IOBlock
                     // 1) fetch (or create) the sheet
 
                     // special case: sheet name saved using FileToWorkbook
-                    if (line.startsWith("== "))
-                    {
+                    if (line.startsWith("== ")) {
                         // don't add the new line if we create a new sheet
                         newLine = false;
-                        String sheetName = line.substring(3, line.indexOf(" =="));
+                        final String sheetName = line.substring(3, line.indexOf(" =="));
                         sheet = wb.createSheet(sheetName);
 
                         // reset the row
@@ -115,8 +116,7 @@ public class FileToWorkbook extends Plugin implements IOBlock
                     }
 
                     // otherwise, create a (default) empty sheet
-                    if (sheet == null)
-                    {
+                    if (sheet == null) {
                         sheet = wb.createSheet();
                         // reset the row
                         rowID = 0;
@@ -127,7 +127,7 @@ public class FileToWorkbook extends Plugin implements IOBlock
                         sheet.createRow(rowID++);
 
                     // 3) Create a new row for the current input
-                    Row row = sheet.createRow(rowID++);
+                    final Row row = sheet.createRow(rowID++);
 
                     // skip empty lines
                     if (line.isEmpty())
@@ -135,18 +135,14 @@ public class FileToWorkbook extends Plugin implements IOBlock
 
                     int colID = 0;
 
-                    String[] words = line.split("\t");
-                    for (String word : words)
-                    {
-                        if (!word.isEmpty())
-                        {
-                            Cell cell = row.createCell(colID);
-                            try
-                            {
+                    final String[] words = line.split("\t");
+                    for (final String word : words) {
+                        if (!word.isEmpty()) {
+                            final Cell cell = row.createCell(colID);
+                            try {
                                 cell.setCellValue(Double.parseDouble(word));
                             }
-                            catch (NumberFormatException formatError)
-                            {
+                            catch (final NumberFormatException formatError) {
                                 cell.setCellValue(word);
                             }
                         }
@@ -158,8 +154,7 @@ public class FileToWorkbook extends Plugin implements IOBlock
 
                 return wb;
             }
-            catch (Exception e2)
-            {
+            catch (final Exception e2) {
                 throw new RuntimeException(e2);
             }
         }
diff --git a/src/main/java/plugins/adufour/blocks/tools/io/WorkbookToFile.java b/src/main/java/plugins/adufour/blocks/tools/io/WorkbookToFile.java
index 5692fdaa96f501af29a280b4d2a5e74fa5769a2b..7e22a20fa3b1cbb46c027d82a72254bc8045c3e1 100644
--- a/src/main/java/plugins/adufour/blocks/tools/io/WorkbookToFile.java
+++ b/src/main/java/plugins/adufour/blocks/tools/io/WorkbookToFile.java
@@ -1,49 +1,63 @@
-package plugins.adufour.blocks.tools.io;
-
-import java.io.File;
-import java.io.FileNotFoundException;
-import java.io.FileOutputStream;
-import java.io.FileWriter;
-import java.io.IOException;
-import java.util.HashMap;
+/*
+ * Copyright (c) 2010-2023. Institut Pasteur.
+ *
+ * This file is part of Icy.
+ * Icy is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Icy is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Icy. If not, see <https://www.gnu.org/licenses/>.
+ */
 
-import org.apache.poi.ss.usermodel.Cell;
-import org.apache.poi.ss.usermodel.CellStyle;
-import org.apache.poi.ss.usermodel.Row;
-import org.apache.poi.ss.usermodel.Sheet;
-import org.apache.poi.ss.usermodel.Workbook;
+package plugins.adufour.blocks.tools.io;
 
 import icy.file.FileUtil;
 import icy.plugin.abstract_.Plugin;
 import icy.system.IcyHandledException;
+import org.apache.poi.ss.usermodel.*;
 import plugins.adufour.blocks.util.VarList;
 import plugins.adufour.vars.lang.VarEnum;
 import plugins.adufour.vars.lang.VarFile;
 import plugins.adufour.vars.lang.VarWorkbook;
 import plugins.adufour.workbooks.Workbooks;
 
+import java.io.*;
+import java.util.HashMap;
+
 /**
  * IO block that writes a workbook to a file using the POI library
- * 
+ *
  * @author Alexandre Dufour
  */
-public class WorkbookToFile extends Plugin implements IOBlock
-{
-    public enum WorkbookFormat
-    {
-        /** A format compatible with most spreadsheet software (~ XLS) */
+public class WorkbookToFile extends Plugin implements IOBlock {
+    public enum WorkbookFormat {
+        /**
+         * A format compatible with most spreadsheet software (~ XLS)
+         */
         Spreadsheet,
 
-        /** A tab-delimited text format */
+        /**
+         * A tab-delimited text format
+         */
         Text
     }
 
-    public enum MergePolicy
-    {
-        /** File is overwritten entirely */
+    public enum MergePolicy {
+        /**
+         * File is overwritten entirely
+         */
         Overwrite,
 
-        /** New sheets are merged into existing ones if they have the same name */
+        /**
+         * New sheets are merged into existing ones if they have the same name
+         */
         Merge_sheets,
 
         /**
@@ -52,22 +66,20 @@ public class WorkbookToFile extends Plugin implements IOBlock
          */
         Merge_sheets___excluding_first_row;
 
-        public String toString()
-        {
+        @Override
+        public String toString() {
             return super.toString().replace("__", ",").replace("_", " ");
         }
     }
 
     VarWorkbook workbook = new VarWorkbook("workbook", (Workbook) null);
     VarFile file = new VarFile("output file", null);
-    VarEnum<WorkbookFormat> format = new VarEnum<WorkbookFormat>("file format", WorkbookFormat.Spreadsheet);
-    VarEnum<MergePolicy> append = new VarEnum<MergePolicy>("If file exists", MergePolicy.Overwrite);
+    VarEnum<WorkbookFormat> format = new VarEnum<>("file format", WorkbookFormat.Spreadsheet);
+    VarEnum<MergePolicy> append = new VarEnum<>("If file exists", MergePolicy.Overwrite);
 
     @Override
-    public void run()
-    {
-        switch (format.getValue())
-        {
+    public void run() {
+        switch (format.getValue()) {
             case Spreadsheet:
                 saveAsSpreadSheet(workbook.getValue(true), file.getValue(true).getAbsolutePath(), append.getValue());
                 break;
@@ -81,8 +93,7 @@ public class WorkbookToFile extends Plugin implements IOBlock
     }
 
     @Override
-    public void declareInput(VarList inputMap)
-    {
+    public void declareInput(final VarList inputMap) {
         inputMap.add("workbook", workbook);
         inputMap.add("file format", format);
         inputMap.add("output file", file);
@@ -90,77 +101,50 @@ public class WorkbookToFile extends Plugin implements IOBlock
     }
 
     @Override
-    public void declareOutput(VarList outputMap)
-    {
+    public void declareOutput(final VarList outputMap) {
     }
 
     /**
      * Saves the specified workbook to a spreadsheet file. By default, the ".xls" extension will be
      * added to the file name if it is not present
-     * 
-     * @param workbook
-     *        workbook to save
-     * @param fileName
-     *        file name where to save workbook
-     * @deprecated Use {@link #saveAsSpreadSheet(Workbook, String, MergePolicy)} instead.
+     *
+     * @param workbook    workbook to save
+     * @param fileName    file name where to save workbook
+     * @param mergePolicy indicates if and how the file should be appended
      */
-    @Deprecated
-    public static void saveAsSpreadSheet(Workbook workbook, String fileName)
-    {
-        saveAsSpreadSheet(workbook, fileName, MergePolicy.Overwrite);
-    }
-
-    /**
-     * Saves the specified workbook to a spreadsheet file. By default, the ".xls" extension will be
-     * added to the file name if it is not present
-     * 
-     * @param workbook
-     *        workbook to save
-     * @param fileName
-     *        file name where to save workbook
-     * @param mergePolicy
-     *        indicates if and how the file should be appended
-     */
-    public static void saveAsSpreadSheet(Workbook workbook, String fileName, MergePolicy mergePolicy)
-    {
+    public static void saveAsSpreadSheet(final Workbook workbook, final String fileName, final MergePolicy mergePolicy) {
         File file = new File(fileName);
 
         if (file.isDirectory())
             throw new IcyHandledException("Cannot save workbook: the specified file is a folder");
 
         // Add a default extension (if necessary)
-        String extension = Workbooks.getFormat(workbook).getExtension();
+        final String extension = Workbooks.getFormat(workbook).getExtension();
         if (!file.exists() && !fileName.toLowerCase().endsWith(extension))
             file = new File(FileUtil.setExtension(file.getPath(), extension));
 
         // should we merge?
-        if (file.exists() && mergePolicy != MergePolicy.Overwrite)
-        {
-            try
-            {
+        if (file.exists() && mergePolicy != MergePolicy.Overwrite) {
+            try {
                 mergeWorkbooks(FileToWorkbook.readWorkbook(file), workbook, mergePolicy);
             }
-            catch (IllegalArgumentException e)
-            {
-                String message = "Unable to merge (target file has not the same format)";
+            catch (final IllegalArgumentException e) {
+                final String message = "Unable to merge (target file has not the same format)";
                 throw new IcyHandledException(message);
             }
-            catch (Exception e)
-            {
+            catch (final Exception e) {
                 throw new RuntimeException(e);
             }
         }
 
-        try
-        {
-            File tmp = File.createTempFile("icy_tmp_workbook", extension);
-            FileOutputStream stream = new FileOutputStream(tmp);
+        try {
+            final File tmp = File.createTempFile("icy_tmp_workbook", extension);
+            final FileOutputStream stream = new FileOutputStream(tmp);
             workbook.write(stream);
             stream.close();
             FileUtil.rename(tmp, file, true);
         }
-        catch (FileNotFoundException e)
-        {
+        catch (final FileNotFoundException e) {
             String error = "Cannot create file " + fileName + "\n";
             error += "Reason: " + e.getMessage() + "\n\n";
             error += "Please ensure that:\n";
@@ -169,8 +153,7 @@ public class WorkbookToFile extends Plugin implements IOBlock
 
             throw new IcyHandledException(error);
         }
-        catch (IOException e)
-        {
+        catch (final IOException e) {
             String error = "Cannot write file " + fileName + "\n";
             error += "Reason: " + e.getMessage() + "\n\n";
             error += "Please ensure that the file is not opened with another application.";
@@ -179,22 +162,6 @@ public class WorkbookToFile extends Plugin implements IOBlock
         }
     }
 
-    /**
-     * Saves the specified workbook to a spreadsheet file. By default, the ".txt" extension will be
-     * added to the file name if it is not present
-     * 
-     * @param workbook
-     *        workbook to save
-     * @param fileName
-     *        file name where to save workbook
-     * @deprecated Use {@link #saveAsText(Workbook, String, MergePolicy)} instead.
-     */
-    @Deprecated
-    public static void saveAsText(Workbook workbook, String fileName)
-    {
-        saveAsText(workbook, fileName, MergePolicy.Overwrite);
-    }
-
     /**
      * Saves the specified workbook to a spreadsheet file. By default, the ".txt" extension will be
      * added to the file name if it is not present. If the workbook contains multiple sheets, they
@@ -204,16 +171,12 @@ public class WorkbookToFile extends Plugin implements IOBlock
      * <br>
      * == sheet 2 ==<br>
      * item3 (tab) item4</code><br>
-     * 
-     * @param workbook
-     *        the workbook to save
-     * @param fileName
-     *        the name of the file to save to
-     * @param mergePolicy
-     *        indicates if and how the file should be appended
+     *
+     * @param workbook    the workbook to save
+     * @param fileName    the name of the file to save to
+     * @param mergePolicy indicates if and how the file should be appended
      */
-    public static void saveAsText(Workbook workbook, String fileName, MergePolicy mergePolicy)
-    {
+    public static void saveAsText(final Workbook workbook, final String fileName, final MergePolicy mergePolicy) {
         File file = new File(fileName);
 
         if (file.isDirectory())
@@ -225,36 +188,29 @@ public class WorkbookToFile extends Plugin implements IOBlock
 
         // should we merge?
         if (file.exists() && mergePolicy != MergePolicy.Overwrite)
-            try
-            {
+            try {
                 mergeWorkbooks(FileToWorkbook.readWorkbook(file), workbook, mergePolicy);
             }
-            catch (Exception e)
-            {
+            catch (final Exception e) {
                 throw new RuntimeException(e);
             }
 
-        try
-        {
-            FileWriter fw = new FileWriter(file);
+        try {
+            final FileWriter fw = new FileWriter(file);
 
-            int n = workbook.getNumberOfSheets();
+            final int n = workbook.getNumberOfSheets();
 
-            for (int i = 0; i < n; i++)
-            {
-                Sheet sheet = workbook.getSheetAt(i);
+            for (int i = 0; i < n; i++) {
+                final Sheet sheet = workbook.getSheetAt(i);
 
                 fw.write("== " + sheet.getSheetName() + " ==\n");
 
-                for (int r = sheet.getFirstRowNum(); r <= sheet.getLastRowNum(); r++)
-                {
-                    Row row = sheet.getRow(r);
+                for (int r = sheet.getFirstRowNum(); r <= sheet.getLastRowNum(); r++) {
+                    final Row row = sheet.getRow(r);
 
-                    if (row != null)
-                    {
-                        for (int c = row.getFirstCellNum(); c < row.getLastCellNum(); c++)
-                        {
-                            Cell cell = row.getCell(c, Row.MissingCellPolicy.RETURN_BLANK_AS_NULL);
+                    if (row != null) {
+                        for (int c = row.getFirstCellNum(); c < row.getLastCellNum(); c++) {
+                            final Cell cell = row.getCell(c, Row.MissingCellPolicy.RETURN_BLANK_AS_NULL);
                             if (cell != null)
                                 fw.write(cell.toString());
                             fw.write("\t");
@@ -269,8 +225,7 @@ public class WorkbookToFile extends Plugin implements IOBlock
             fw.flush();
             fw.close();
         }
-        catch (FileNotFoundException e)
-        {
+        catch (final FileNotFoundException e) {
             String error = "Cannot create file " + fileName + "\n";
             error += "Reason: " + e.getMessage() + "\n\n";
             error += "Please ensure that:\n";
@@ -279,8 +234,7 @@ public class WorkbookToFile extends Plugin implements IOBlock
 
             throw new IcyHandledException(error);
         }
-        catch (IOException e)
-        {
+        catch (final IOException e) {
             String error = "Cannot write file " + fileName + "\n";
             error += "Reason: " + e.getMessage() + "\n\n";
             error += "Please ensure that the file is not opened with another application.";
@@ -289,14 +243,7 @@ public class WorkbookToFile extends Plugin implements IOBlock
         }
     }
 
-    /**
-     * @param source
-     * @param target
-     * @param policy
-     * @return
-     */
-    private static void mergeWorkbooks(Workbook source, Workbook target, MergePolicy policy)
-    {
+    private static void mergeWorkbooks(final Workbook source, final Workbook target, final MergePolicy policy) {
         if (policy == MergePolicy.Overwrite)
             return;
 
@@ -349,42 +296,36 @@ public class WorkbookToFile extends Plugin implements IOBlock
         // }
         // }
 
-        HashMap<Integer, CellStyle> styles = new HashMap<Integer, CellStyle>();
+        final HashMap<Integer, CellStyle> styles = new HashMap<>();
 
-        for (int i = 0; i < source.getNumberOfSheets(); i++)
-        {
-            Sheet sourceSheet = source.getSheetAt(i);
-            String sourceSheetName = sourceSheet.getSheetName();
+        for (int i = 0; i < source.getNumberOfSheets(); i++) {
+            final Sheet sourceSheet = source.getSheetAt(i);
+            final String sourceSheetName = sourceSheet.getSheetName();
 
             // does the sheet exist in the target workbook?
             Sheet targetSheet = target.getSheet(sourceSheetName);
 
             int sourceRowNum = 0;
-            if (targetSheet == null)
-            {
+            if (targetSheet == null) {
                 targetSheet = target.createSheet(sourceSheetName);
             }
-            else if (policy == MergePolicy.Merge_sheets___excluding_first_row)
-            {
+            else if (policy == MergePolicy.Merge_sheets___excluding_first_row) {
                 sourceRowNum++;
             }
 
             int targetRowNum = targetSheet.getLastRowNum() + 1;
 
-            for (int r = sourceRowNum; r <= sourceSheet.getLastRowNum(); r++, targetRowNum++)
-            {
-                Row sourceRow = sourceSheet.getRow(r);
+            for (int r = sourceRowNum; r <= sourceSheet.getLastRowNum(); r++, targetRowNum++) {
+                final Row sourceRow = sourceSheet.getRow(r);
                 if (sourceRow == null)
                     continue;
-                Row targetRow = targetSheet.createRow(targetRowNum);
-                for (Cell sourceCell : sourceRow)
-                {
+                final Row targetRow = targetSheet.createRow(targetRowNum);
+                for (final Cell sourceCell : sourceRow) {
                     // Copy the cell
-                    Cell targetCell = targetRow.createCell(sourceCell.getColumnIndex());
-                    int hashCode = sourceCell.getCellStyle().hashCode();
-                    if (!styles.containsKey(hashCode))
-                    {
-                        CellStyle targetStyle = target.createCellStyle();
+                    final Cell targetCell = targetRow.createCell(sourceCell.getColumnIndex());
+                    final int hashCode = sourceCell.getCellStyle().hashCode();
+                    if (!styles.containsKey(hashCode)) {
+                        final CellStyle targetStyle = target.createCellStyle();
                         Workbooks.copyStyle(sourceCell.getCellStyle(), targetStyle);
                         styles.put(hashCode, targetStyle);
                     }
diff --git a/src/main/java/plugins/adufour/vars/gui/swing/PersistentColumnControlButton.java b/src/main/java/plugins/adufour/vars/gui/swing/PersistentColumnControlButton.java
index 5a3cadad6faabdd068d1803c83ec7d30f1f93c17..0c6e326923d085a711f2270bb0c099729744dc7d 100644
--- a/src/main/java/plugins/adufour/vars/gui/swing/PersistentColumnControlButton.java
+++ b/src/main/java/plugins/adufour/vars/gui/swing/PersistentColumnControlButton.java
@@ -1,18 +1,31 @@
-package plugins.adufour.vars.gui.swing;
-
-import java.util.List;
+/*
+ * Copyright (c) 2010-2023. Institut Pasteur.
+ *
+ * This file is part of Icy.
+ * Icy is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Icy is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Icy. If not, see <https://www.gnu.org/licenses/>.
+ */
 
-import javax.swing.Action;
-import javax.swing.JCheckBoxMenuItem;
-import javax.swing.JMenuItem;
-import javax.swing.MenuSelectionManager;
+package plugins.adufour.vars.gui.swing;
 
 import org.jdesktop.swingx.JXTable;
 import org.jdesktop.swingx.action.AbstractActionExt;
 import org.jdesktop.swingx.action.ActionContainerFactory;
 import org.jdesktop.swingx.table.ColumnControlButton;
 import org.jdesktop.swingx.table.ColumnControlPopup;
-import org.pushingpixels.substance.internal.ui.SubstanceCheckBoxMenuItemUI;
+
+import javax.swing.*;
+import java.util.List;
 
 /**
  * Persistent version of JXTable's column control button that keeps the pop-up open even after a
@@ -22,49 +35,27 @@ import org.pushingpixels.substance.internal.ui.SubstanceCheckBoxMenuItemUI;
  * This code was adapted from the <a
  * href="http://www.coding-dude.com/wp/java/custom-columncontrolbutton-java-swing-jxtable/">
  * following page</a>.
- * 
+ *
  * @author John Negoita
  * @author Alexandre Dufour
  */
-@SuppressWarnings("serial")
-public class PersistentColumnControlButton extends ColumnControlButton
-{
-    public PersistentColumnControlButton(JXTable table)
-    {
+public class PersistentColumnControlButton extends ColumnControlButton {
+    public PersistentColumnControlButton(final JXTable table) {
         super(table);
     }
 
     @Override
-    protected ColumnControlPopup createColumnControlPopup()
-    {
-        return new DefaultColumnControlPopup()
-        {
+    protected ColumnControlPopup createColumnControlPopup() {
+        return new DefaultColumnControlPopup() {
             @Override
-            public void addVisibilityActionItems(List<? extends AbstractActionExt> actions)
-            {
+            public void addVisibilityActionItems(final List<? extends AbstractActionExt> actions) {
 
-                ActionContainerFactory factory = new ActionContainerFactory(null);
-                for (Action action : actions)
-                {
-                    JMenuItem mi = factory.createMenuItem(action);
-                    mi.setUI(new MyCheckBoxMenuItemUI((JCheckBoxMenuItem) mi));
+                final ActionContainerFactory factory = new ActionContainerFactory(null);
+                for (final Action action : actions) {
+                    final JMenuItem mi = factory.createMenuItem(action);
                     addItem(mi);
                 }
             }
-
         };
     }
-
-    private static class MyCheckBoxMenuItemUI extends SubstanceCheckBoxMenuItemUI
-    {
-        public MyCheckBoxMenuItemUI(JCheckBoxMenuItem menuItem)
-        {
-            super(menuItem);
-        }
-
-        synchronized protected void doClick(MenuSelectionManager msm)
-        {
-            menuItem.doClick(0);
-        }
-    }
 }
\ No newline at end of file
diff --git a/src/main/java/plugins/adufour/vars/gui/swing/WorkbookEditor.java b/src/main/java/plugins/adufour/vars/gui/swing/WorkbookEditor.java
index 562cd8dd6bfc06f5d75e6288310865dbe3e37ac9..bef71591417f0fbb46b322ea1b6398b0f4e5a140 100644
--- a/src/main/java/plugins/adufour/vars/gui/swing/WorkbookEditor.java
+++ b/src/main/java/plugins/adufour/vars/gui/swing/WorkbookEditor.java
@@ -1,57 +1,30 @@
-package plugins.adufour.vars.gui.swing;
+/*
+ * Copyright (c) 2010-2023. Institut Pasteur.
+ *
+ * This file is part of Icy.
+ * Icy is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Icy is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Icy. If not, see <https://www.gnu.org/licenses/>.
+ */
 
-import java.awt.BorderLayout;
-import java.awt.Color;
-import java.awt.Component;
-import java.awt.Dimension;
-import java.awt.Font;
-import java.awt.event.ActionEvent;
-import java.awt.event.ActionListener;
-import java.awt.event.MouseAdapter;
-import java.awt.event.MouseEvent;
-import java.io.File;
-import java.util.ArrayList;
-import java.util.Comparator;
-import java.util.HashMap;
-import java.util.List;
-
-import javax.swing.Box;
-import javax.swing.BoxLayout;
-import javax.swing.DefaultCellEditor;
-import javax.swing.JButton;
-import javax.swing.JCheckBox;
-import javax.swing.JComponent;
-import javax.swing.JFileChooser;
-import javax.swing.JLabel;
-import javax.swing.JMenu;
-import javax.swing.JMenuItem;
-import javax.swing.JOptionPane;
-import javax.swing.JPanel;
-import javax.swing.JPopupMenu;
-import javax.swing.JScrollPane;
-import javax.swing.JTabbedPane;
-import javax.swing.JTable;
-import javax.swing.JTextField;
-import javax.swing.ListSelectionModel;
-import javax.swing.SortOrder;
-import javax.swing.event.ChangeEvent;
-import javax.swing.event.ChangeListener;
-import javax.swing.event.ListSelectionEvent;
-import javax.swing.event.ListSelectionListener;
-import javax.swing.event.MenuEvent;
-import javax.swing.event.MenuListener;
-import javax.swing.event.RowSorterEvent;
-import javax.swing.event.RowSorterListener;
-import javax.swing.event.TableColumnModelEvent;
-import javax.swing.event.TableColumnModelListener;
-import javax.swing.event.TableModelEvent;
-import javax.swing.filechooser.FileNameExtensionFilter;
-import javax.swing.table.AbstractTableModel;
-import javax.swing.table.DefaultTableCellRenderer;
-import javax.swing.table.TableCellEditor;
-import javax.swing.table.TableCellRenderer;
-import javax.swing.table.TableColumn;
+package plugins.adufour.vars.gui.swing;
 
+import icy.gui.dialog.MessageDialog;
+import icy.gui.dialog.OpenDialog;
+import icy.gui.frame.IcyFrame;
+import icy.math.ArrayMath;
+import icy.resource.ResourceUtil;
+import icy.system.IcyHandledException;
+import icy.system.thread.ThreadUtil;
 import org.apache.poi.ss.formula.FormulaParseException;
 import org.apache.poi.ss.usermodel.Sheet;
 import org.apache.poi.ss.usermodel.Workbook;
@@ -61,14 +34,6 @@ import org.jdesktop.swingx.JXTable;
 import org.math.plot.Plot2DPanel;
 import org.math.plot.Plot3DPanel;
 import org.math.plot.utils.Array;
-
-import icy.gui.dialog.MessageDialog;
-import icy.gui.dialog.OpenDialog;
-import icy.gui.frame.IcyFrame;
-import icy.math.ArrayMath;
-import icy.resource.ResourceUtil;
-import icy.system.IcyHandledException;
-import icy.system.thread.ThreadUtil;
 import plugins.adufour.blocks.tools.io.WorkbookToFile;
 import plugins.adufour.blocks.tools.io.WorkbookToFile.MergePolicy;
 import plugins.adufour.ezplug.EzButton;
@@ -84,46 +49,47 @@ import plugins.adufour.vars.util.VarListener;
 import plugins.adufour.workbooks.IcySpreadSheet;
 import plugins.adufour.workbooks.Workbooks;
 
-public class WorkbookEditor extends SwingVarEditor<Workbook>
-{
+import javax.swing.*;
+import javax.swing.event.*;
+import javax.swing.filechooser.FileNameExtensionFilter;
+import javax.swing.table.*;
+import java.awt.*;
+import java.awt.event.MouseAdapter;
+import java.awt.event.MouseEvent;
+import java.io.File;
+import java.util.ArrayList;
+import java.util.Comparator;
+import java.util.HashMap;
+import java.util.List;
+
+public class WorkbookEditor extends SwingVarEditor<Workbook> {
     final VarString formula = new VarString("Formula", "");
     final VarBoolean useHeader = new VarBoolean("Header", false);
     final VarBoolean readOnly = new VarBoolean("read-only", false);
-    final VarBoolean openButtonVisible = new VarBoolean("show open button", true)
-    {
-        public void valueChanged(Var<Boolean> source, Boolean oldValue, Boolean newValue)
-        {
+    final VarBoolean openButtonVisible = new VarBoolean("show open button", true) {
+        @Override
+        public void valueChanged(final Var<Boolean> source, final Boolean oldValue, final Boolean newValue) {
             super.valueChanged(source, oldValue, newValue);
             if (openButton != null)
-                ThreadUtil.invokeLater(new Runnable()
-                {
-                    @Override
-                    public void run()
-                    {
-                        openButton.setVisible(false);
-                    }
-                });
-        };
+                ThreadUtil.invokeLater(() -> openButton.setVisible(false));
+        }
     };
 
     private JButton openButton, exportButton, plotButton;
     private JTabbedPane tabs;
-    private final HashMap<Sheet, JXTable> tables = new HashMap<Sheet, JXTable>();
-    private final HashMap<Sheet, JXTable> headers = new HashMap<Sheet, JXTable>();
+    private final HashMap<Sheet, JXTable> tables = new HashMap<>();
+    private final HashMap<Sheet, JXTable> headers = new HashMap<>();
 
     // cached workbook to avoid reference of old book being leaked by GUI
     private Workbook book;
 
-    class TabChangeListener implements ChangeListener
-    {
+    class TabChangeListener implements ChangeListener {
         @Override
-        public void stateChanged(ChangeEvent arg0)
-        {
+        public void stateChanged(final ChangeEvent arg0) {
             final Workbook book = variable.getValue();
             final int sheetIndex = tabs.getSelectedIndex();
 
-            if (sheetIndex == book.getNumberOfSheets())
-            {
+            if (sheetIndex == book.getNumberOfSheets()) {
                 tabs.removeTabAt(book.getNumberOfSheets());
                 createSheet(book);
                 updateInterfaceValue();
@@ -131,14 +97,12 @@ public class WorkbookEditor extends SwingVarEditor<Workbook>
                 book.setActiveSheet(book.getNumberOfSheets() - 1);
             }
 
-            if (sheetIndex >= 0)
-            {
-                Sheet sheet = book.getSheetAt(sheetIndex);
+            if (sheetIndex >= 0) {
+                final Sheet sheet = book.getSheetAt(sheetIndex);
                 book.setActiveSheet(sheetIndex);
-                if (tables.containsKey(sheet))
-                {
-                    JXTable table = tables.get(sheet);
-                    SheetModel model = (SheetModel) table.getModel();
+                if (tables.containsKey(sheet)) {
+                    final JXTable table = tables.get(sheet);
+                    final SheetModel model = (SheetModel) table.getModel();
                     updateFormulaField(model, table.getSelectedRow(), table.getSelectedColumn());
                 }
             }
@@ -147,136 +111,105 @@ public class WorkbookEditor extends SwingVarEditor<Workbook>
 
     private final TabChangeListener tabChangeListener = new TabChangeListener();
 
-    public WorkbookEditor(VarWorkbook variable)
-    {
+    public WorkbookEditor(final VarWorkbook variable) {
         super(variable);
     }
 
     @Override
-    protected JComponent createEditorComponent()
-    {
+    protected JComponent createEditorComponent() {
         return new JXPanel(new BorderLayout());
     }
 
     @Override
-    protected void activateListeners()
-    {
-        useHeader.addListener(new VarListener<Boolean>()
-        {
+    protected void activateListeners() {
+        useHeader.addListener(new VarListener<>() {
             @Override
-            public void valueChanged(Var<Boolean> source, Boolean oldValue, Boolean newValue)
-            {
+            public void valueChanged(final Var<Boolean> source, final Boolean oldValue, final Boolean newValue) {
                 updateInterfaceValue();
             }
 
             @Override
-            public void referenceChanged(Var<Boolean> source, Var<? extends Boolean> oldReference,
-                    Var<? extends Boolean> newReference)
-            {
+            public void referenceChanged(final Var<Boolean> source, final Var<? extends Boolean> oldReference, final Var<? extends Boolean> newReference) {
             }
         });
     }
 
     @Override
-    protected void deactivateListeners()
-    {
+    protected void deactivateListeners() {
         useHeader.removeListeners();
     }
 
     @Override
-    public void dispose()
-    {
+    public void dispose() {
         super.dispose();
 
         tables.clear();
         headers.clear();
         book = null;
 
-        if (tabs != null)
-        {
+        if (tabs != null) {
             tabs.removeChangeListener(tabChangeListener);
             tabs.removeAll();
         }
     }
 
     @Override
-    public Dimension getPreferredSize()
-    {
+    public Dimension getPreferredSize() {
         return new Dimension(400, 100);
     }
 
     @Override
-    public double getComponentVerticalResizeFactor()
-    {
+    public double getComponentVerticalResizeFactor() {
         return 1.0;
     }
 
     @Override
-    public boolean isComponentResizeable()
-    {
+    public boolean isComponentResizeable() {
         return true;
     }
 
     /**
      * Indicates whether the first table row should be used as a header. If so, the first row will
      * virtually disappear from the table and its values will be used to rename the table columns
-     * 
-     * @param header
-     *        <code>true</code> to use the first row as a header, <code>false</code> otherwise
+     *
+     * @param header <code>true</code> to use the first row as a header, <code>false</code> otherwise
      */
-    public void setFirstRowAsHeader(boolean header)
-    {
+    public void setFirstRowAsHeader(final boolean header) {
         useHeader.setValue(header);
     }
 
     /**
      * Sets whether the open button should be visible
-     * 
-     * @param visible
-     *        visible state
+     *
+     * @param visible visible state
      */
-    public void setOpenButtonVisible(boolean visible)
-    {
+    public void setOpenButtonVisible(final boolean visible) {
         openButtonVisible.setValue(visible);
     }
 
     /**
      * Sets whether the table editor is read-only, and therefore rejects user input
-     * 
-     * @param readOnly
-     *        read only state
+     *
+     * @param readOnly read only state
      */
-    public void setReadOnly(boolean readOnly)
-    {
+    public void setReadOnly(final boolean readOnly) {
         this.readOnly.setValue(readOnly);
     }
 
-    private MergePolicy confirm()
-    {
+    private MergePolicy confirm() {
         final EzDialog confirmDialog = new EzDialog("Confirmation");
 
         confirmDialog.addEzComponent(new EzLabel("This file already exists."));
-        final EzVarEnum<MergePolicy> policy = new EzVarEnum<WorkbookToFile.MergePolicy>("Action: ",
-                MergePolicy.values());
+        final EzVarEnum<MergePolicy> policy = new EzVarEnum<>("Action: ", MergePolicy.values());
         confirmDialog.addEzComponent(policy);
         final VarBoolean confirmed = new VarBoolean("confirmed", true);
-        confirmDialog.addEzComponent(new EzButton("Ok", new ActionListener()
-        {
-            @Override
-            public void actionPerformed(ActionEvent arg0)
-            {
-                confirmed.setValue(true);
-                confirmDialog.close();
-            }
+        confirmDialog.addEzComponent(new EzButton("Ok", e -> {
+            confirmed.setValue(true);
+            confirmDialog.close();
         }));
-        confirmDialog.addEzComponent(new EzButton("Cancel", new ActionListener()
-        {
-            @Override
-            public void actionPerformed(ActionEvent arg0)
-            {
-                confirmed.setValue(false);
-                confirmDialog.close();
-            }
+        confirmDialog.addEzComponent(new EzButton("Cancel", e -> {
+            confirmed.setValue(false);
+            confirmDialog.close();
         }));
 
         // show confirm dialog and wait for user choice...
@@ -290,10 +223,8 @@ public class WorkbookEditor extends SwingVarEditor<Workbook>
     }
 
     @Override
-    protected void updateInterfaceValue()
-    {
-        if (variable.getReference() != null)
-        {
+    protected void updateInterfaceValue() {
+        if (variable.getReference() != null) {
             setReadOnly(true);
             setOpenButtonVisible(false);
         }
@@ -304,18 +235,17 @@ public class WorkbookEditor extends SwingVarEditor<Workbook>
         if (book == null)
             return;
 
-        JXPanel wbPanel = (JXPanel) getEditorComponent();
-        String bookID = "" + book.hashCode();
+        final JXPanel wbPanel = (JXPanel) getEditorComponent();
+        final String bookID = "" + book.hashCode();
 
-        boolean buildNewEditor = (wbPanel.getName() == null || !wbPanel.getName().equalsIgnoreCase(bookID));
+        final boolean buildNewEditor = (wbPanel.getName() == null || !wbPanel.getName().equalsIgnoreCase(bookID));
 
-        if (buildNewEditor)
-        {
+        if (buildNewEditor) {
             // create a new table
             wbPanel.removeAll();
 
             // Option panel
-            JPanel optionBar = new JPanel();
+            final JPanel optionBar = new JPanel();
             optionBar.setLayout(new BoxLayout(optionBar, BoxLayout.X_AXIS));
 
             // Open
@@ -325,23 +255,16 @@ public class WorkbookEditor extends SwingVarEditor<Workbook>
             openButton.setFocusable(false);
             openButton.setContentAreaFilled(false);
             openButton.setToolTipText("Open/Create workbook...");
-            openButton.addActionListener(new ActionListener()
-            {
-                @Override
-                public void actionPerformed(ActionEvent e)
-                {
-                    String path = OpenDialog.chooseFile("Load/Create workbook...", null, "Workbook", ".xls");
-                    if (path == null)
-                        return;
+            openButton.addActionListener(e -> {
+                final String path = OpenDialog.chooseFile("Load/Create workbook...", null, "Workbook", ".xls");
+                if (path == null)
+                    return;
 
-                    try
-                    {
-                        variable.setValue(WorkbookFactory.create(new File(path)));
-                    }
-                    catch (Exception e1)
-                    {
-                        MessageDialog.showDialog(e1.getMessage(), MessageDialog.ERROR_MESSAGE);
-                    }
+                try {
+                    variable.setValue(WorkbookFactory.create(new File(path)));
+                }
+                catch (final Exception e1) {
+                    MessageDialog.showDialog(e1.getMessage(), MessageDialog.ERROR_MESSAGE);
                 }
             });
             optionBar.add(openButton);
@@ -358,60 +281,41 @@ public class WorkbookEditor extends SwingVarEditor<Workbook>
             final FileNameExtensionFilter xlsFilter = new FileNameExtensionFilter("Spreadsheets (.xlsx)", "xlsx");
 
             final JPopupMenu exportPopupMenu = new JPopupMenu();
-            JMenuItem exportXLS = new JMenuItem("Export to an Excel file");
-            exportXLS.addActionListener(new ActionListener()
-            {
-                @Override
-                public void actionPerformed(ActionEvent e)
-                {
-                    fileChooser.setFileFilter(xlsFilter);
-                    if (fileChooser.showSaveDialog(exportPopupMenu) != JFileChooser.APPROVE_OPTION)
-                        return;
-                    File outputFile = fileChooser.getSelectedFile();
-                    if (outputFile.exists())
-                    {
-                        // ask for confirmation + merging policy
-                        final MergePolicy mergingPolicy = confirm();
-                        // confirmed ?
-                        if (mergingPolicy != null)
-                            WorkbookToFile.saveAsSpreadSheet(book, outputFile.getPath(), mergingPolicy);
-                    }
-                    else
-                        WorkbookToFile.saveAsSpreadSheet(book, outputFile.getPath(), MergePolicy.Overwrite);
+            final JMenuItem exportXLS = new JMenuItem("Export to an Excel file");
+            exportXLS.addActionListener(e -> {
+                fileChooser.setFileFilter(xlsFilter);
+                if (fileChooser.showSaveDialog(exportPopupMenu) != JFileChooser.APPROVE_OPTION)
+                    return;
+                final File outputFile = fileChooser.getSelectedFile();
+                if (outputFile.exists()) {
+                    // ask for confirmation + merging policy
+                    final MergePolicy mergingPolicy = confirm();
+                    // confirmed ?
+                    if (mergingPolicy != null)
+                        WorkbookToFile.saveAsSpreadSheet(book, outputFile.getPath(), mergingPolicy);
                 }
+                else
+                    WorkbookToFile.saveAsSpreadSheet(book, outputFile.getPath(), MergePolicy.Overwrite);
             });
-            JMenuItem exportTXT = new JMenuItem("Export to a text file");
-            exportTXT.addActionListener(new ActionListener()
-            {
-                @Override
-                public void actionPerformed(ActionEvent e)
-                {
-                    fileChooser.setFileFilter(txtFilter);
-                    if (fileChooser.showSaveDialog(exportPopupMenu) != JFileChooser.APPROVE_OPTION)
-                        return;
-                    File outputFile = fileChooser.getSelectedFile();
-                    if (outputFile.exists())
-                    {
-                        // ask for confirmation + merging policy
-                        final MergePolicy mergingPolicy = confirm();
-                        // confirmed ?
-                        if (mergingPolicy != null)
-                            WorkbookToFile.saveAsText(book, outputFile.getPath(), mergingPolicy);
-                    }
-                    else
-                        WorkbookToFile.saveAsText(book, outputFile.getPath(), MergePolicy.Overwrite);
+            final JMenuItem exportTXT = new JMenuItem("Export to a text file");
+            exportTXT.addActionListener(e -> {
+                fileChooser.setFileFilter(txtFilter);
+                if (fileChooser.showSaveDialog(exportPopupMenu) != JFileChooser.APPROVE_OPTION)
+                    return;
+                final File outputFile = fileChooser.getSelectedFile();
+                if (outputFile.exists()) {
+                    // ask for confirmation + merging policy
+                    final MergePolicy mergingPolicy = confirm();
+                    // confirmed ?
+                    if (mergingPolicy != null)
+                        WorkbookToFile.saveAsText(book, outputFile.getPath(), mergingPolicy);
                 }
+                else
+                    WorkbookToFile.saveAsText(book, outputFile.getPath(), MergePolicy.Overwrite);
             });
             exportPopupMenu.add(exportTXT);
             exportPopupMenu.add(exportXLS);
-            exportButton.addActionListener(new ActionListener()
-            {
-                @Override
-                public void actionPerformed(ActionEvent e)
-                {
-                    exportPopupMenu.show(exportButton, 0, exportButton.getHeight());
-                }
-            });
+            exportButton.addActionListener(e -> exportPopupMenu.show(exportButton, 0, exportButton.getHeight()));
             optionBar.add(exportButton);
 
             // Plot (START)
@@ -425,89 +329,75 @@ public class WorkbookEditor extends SwingVarEditor<Workbook>
             final JPopupMenu plotPopupMenu = new JPopupMenu();
 
             final JMenu plotHistogram1D = new JMenu("Histogram (1D)");
-            plotHistogram1D.addMenuListener(new MenuListener()
-            {
+            plotHistogram1D.addMenuListener(new MenuListener() {
                 @Override
-                public void menuSelected(MenuEvent e)
-                {
-                    int sheetIndex = book.getActiveSheetIndex();
+                public void menuSelected(final MenuEvent e) {
+                    final int sheetIndex = book.getActiveSheetIndex();
                     if (sheetIndex == -1)
                         return;
 
-                    Sheet sheet = book.getSheetAt(sheetIndex);
+                    final Sheet sheet = book.getSheetAt(sheetIndex);
                     final IcySpreadSheet icySheet = Workbooks.getSheet(book, book.getSheetName(sheetIndex));
 
-                    for (int i = 0; i < icySheet.getNumberOfColumns(); i++)
-                    {
+                    for (int i = 0; i < icySheet.getNumberOfColumns(); i++) {
                         final double[] histData = icySheet.getColumnValues(i);
                         if (histData == null || histData.length < 2)
                             continue;
 
                         final String columnName = tables.get(sheet).getColumnName(i);
-                        JMenuItem plotColHistogram = new JMenuItem(columnName);
-                        plotColHistogram.addActionListener(new ActionListener()
-                        {
-                            @Override
-                            public void actionPerformed(ActionEvent actionEvent)
-                            {
-                                double min = ArrayMath.min(histData);
-                                double max = ArrayMath.max(histData);
-                                int bins = Math.max(10, (int) Math.round(Math.sqrt(histData.length)));
-                                Plot2DPanel panel = new Plot2DPanel();
-                                panel.addHistogramPlot(columnName, histData, min, max, bins);
-                                panel.setFixedBounds(0, min, max);
-
-                                // HistogramChart histoChart = new HistogramChart(histData);
-                                // Group group = new Group(histoChart);
-                                // final Scene scene = new Scene(group);
-                                // JFXPanel panel = new JFXPanel();
-                                // panel.setLayout(new BorderLayout());
-                                // panel.setScene(scene);
-
-                                IcyFrame plot = new IcyFrame("Histogram of " + columnName, true);
-                                plot.setPreferredSize(new Dimension(520, 420));
-                                plot.addToDesktopPane();
-                                plot.add(panel);
-                                plot.pack();
-                                plot.setVisible(true);
-                            }
+                        final JMenuItem plotColHistogram = new JMenuItem(columnName);
+                        plotColHistogram.addActionListener(actionEvent -> {
+                            final double min = ArrayMath.min(histData);
+                            final double max = ArrayMath.max(histData);
+                            final int bins = Math.max(10, (int) Math.round(Math.sqrt(histData.length)));
+                            final Plot2DPanel panel = new Plot2DPanel();
+                            panel.addHistogramPlot(columnName, histData, min, max, bins);
+                            panel.setFixedBounds(0, min, max);
+
+                            // HistogramChart histoChart = new HistogramChart(histData);
+                            // Group group = new Group(histoChart);
+                            // final Scene scene = new Scene(group);
+                            // JFXPanel panel = new JFXPanel();
+                            // panel.setLayout(new BorderLayout());
+                            // panel.setScene(scene);
+
+                            final IcyFrame plot = new IcyFrame("Histogram of " + columnName, true);
+                            plot.setPreferredSize(new Dimension(520, 420));
+                            plot.addToDesktopPane();
+                            plot.add(panel);
+                            plot.pack();
+                            plot.setVisible(true);
                         });
                         plotHistogram1D.add(plotColHistogram);
                     }
                 }
 
                 @Override
-                public void menuDeselected(MenuEvent e)
-                {
+                public void menuDeselected(final MenuEvent e) {
                     plotHistogram1D.removeAll();
                 }
 
                 @Override
-                public void menuCanceled(MenuEvent e)
-                {
-
+                public void menuCanceled(final MenuEvent e) {
                 }
             });
 
             final JMenu plotHistogram2D = new JMenu("Histogram (2D)");
-            plotHistogram2D.addMenuListener(new MenuListener()
-            {
+            plotHistogram2D.addMenuListener(new MenuListener() {
                 @Override
-                public void menuSelected(MenuEvent e)
-                {
-                    int sheetIndex = book.getActiveSheetIndex();
+                public void menuSelected(final MenuEvent e) {
+                    final int sheetIndex = book.getActiveSheetIndex();
                     if (sheetIndex == -1)
                         return;
 
-                    Sheet sheet = book.getSheetAt(sheetIndex);
+                    final Sheet sheet = book.getSheetAt(sheetIndex);
                     final IcySpreadSheet icySheet = Workbooks.getSheet(book, book.getSheetName(sheetIndex));
 
-                    JMenuItem labelFirstColumn = new JMenuItem("Select X axis...");
+                    final JMenuItem labelFirstColumn = new JMenuItem("Select X axis...");
                     labelFirstColumn.setEnabled(false);
                     plotHistogram2D.add(labelFirstColumn);
                     plotHistogram2D.addSeparator();
-                    for (int i = 0; i < icySheet.getNumberOfColumns(); i++)
-                    {
+                    for (int i = 0; i < icySheet.getNumberOfColumns(); i++) {
                         final double[] xValues = icySheet.getColumnValues(i);
                         if (xValues == null)
                             continue;
@@ -517,15 +407,14 @@ public class WorkbookEditor extends SwingVarEditor<Workbook>
                         final int binsX = Math.max(10, (int) Math.round(Math.sqrt(xValues.length)));
 
                         final String xColumnName = tables.get(sheet).getColumnName(i);
-                        JMenu plotFirstColumn = new JMenu(xColumnName);
+                        final JMenu plotFirstColumn = new JMenu(xColumnName);
                         plotHistogram2D.add(plotFirstColumn);
 
-                        JMenuItem labelSecondColumn = new JMenuItem("Select Y axis...");
+                        final JMenuItem labelSecondColumn = new JMenuItem("Select Y axis...");
                         labelSecondColumn.setEnabled(false);
                         plotFirstColumn.add(labelSecondColumn);
                         plotFirstColumn.addSeparator();
-                        for (int j = 0; j < icySheet.getNumberOfColumns(); j++)
-                        {
+                        for (int j = 0; j < icySheet.getNumberOfColumns(); j++) {
                             if (i == j)
                                 continue;
 
@@ -544,24 +433,19 @@ public class WorkbookEditor extends SwingVarEditor<Workbook>
                             final String yColumnName = tables.get(sheet).getColumnName(j);
                             final String plotTitle = xColumnName + " vs. " + yColumnName;
 
-                            JMenuItem plotSecondColumn = new JMenuItem(yColumnName);
-                            plotSecondColumn.addActionListener(new ActionListener()
-                            {
-                                @Override
-                                public void actionPerformed(ActionEvent actionEvent)
-                                {
-                                    Plot3DPanel panel = new Plot3DPanel();
-                                    double[][] xy = Array.mergeColumns(xValues, yValues);
-                                    panel.addHistogramPlot(plotTitle, xy, binsX, binsY);
-                                    panel.setFixedBounds(new double[] {minX, minY}, new double[] {maxX, maxY});
-
-                                    IcyFrame plot = new IcyFrame(plotTitle, true);
-                                    plot.setPreferredSize(new Dimension(520, 420));
-                                    plot.addToDesktopPane();
-                                    plot.add(panel);
-                                    plot.pack();
-                                    plot.setVisible(true);
-                                }
+                            final JMenuItem plotSecondColumn = new JMenuItem(yColumnName);
+                            plotSecondColumn.addActionListener(actionEvent -> {
+                                final Plot3DPanel panel = new Plot3DPanel();
+                                final double[][] xy = Array.mergeColumns(xValues, yValues);
+                                panel.addHistogramPlot(plotTitle, xy, binsX, binsY);
+                                panel.setFixedBounds(new double[]{minX, minY}, new double[]{maxX, maxY});
+
+                                final IcyFrame plot = new IcyFrame(plotTitle, true);
+                                plot.setPreferredSize(new Dimension(520, 420));
+                                plot.addToDesktopPane();
+                                plot.add(panel);
+                                plot.pack();
+                                plot.setVisible(true);
                             });
                             plotFirstColumn.add(plotSecondColumn);
                         }
@@ -569,37 +453,31 @@ public class WorkbookEditor extends SwingVarEditor<Workbook>
                 }
 
                 @Override
-                public void menuDeselected(MenuEvent e)
-                {
+                public void menuDeselected(final MenuEvent e) {
                     plotHistogram2D.removeAll();
                 }
 
                 @Override
-                public void menuCanceled(MenuEvent e)
-                {
-
+                public void menuCanceled(final MenuEvent e) {
                 }
             });
 
             final JMenu plotScatter2D = new JMenu("Scatter plot (2D)");
-            plotScatter2D.addMenuListener(new MenuListener()
-            {
+            plotScatter2D.addMenuListener(new MenuListener() {
                 @Override
-                public void menuSelected(MenuEvent e)
-                {
-                    int sheetIndex = book.getActiveSheetIndex();
+                public void menuSelected(final MenuEvent e) {
+                    final int sheetIndex = book.getActiveSheetIndex();
                     if (sheetIndex == -1)
                         return;
 
-                    Sheet sheet = book.getSheetAt(sheetIndex);
+                    final Sheet sheet = book.getSheetAt(sheetIndex);
                     final IcySpreadSheet icySheet = Workbooks.getSheet(book, book.getSheetName(sheetIndex));
 
-                    JMenuItem labelFirstColumn = new JMenuItem("Select X axis...");
+                    final JMenuItem labelFirstColumn = new JMenuItem("Select X axis...");
                     labelFirstColumn.setEnabled(false);
                     plotScatter2D.add(labelFirstColumn);
                     plotScatter2D.addSeparator();
-                    for (int i = 0; i < icySheet.getNumberOfColumns(); i++)
-                    {
+                    for (int i = 0; i < icySheet.getNumberOfColumns(); i++) {
                         final double[] xValues = icySheet.getColumnValues(i);
                         if (xValues == null)
                             continue;
@@ -608,15 +486,14 @@ public class WorkbookEditor extends SwingVarEditor<Workbook>
                         final double maxX = ArrayMath.max(xValues);
 
                         final String xColumnName = tables.get(sheet).getColumnName(i);
-                        JMenu plotFirstColumn = new JMenu(xColumnName);
+                        final JMenu plotFirstColumn = new JMenu(xColumnName);
                         plotScatter2D.add(plotFirstColumn);
 
-                        JMenuItem labelSecondColumn = new JMenuItem("Select Y axis...");
+                        final JMenuItem labelSecondColumn = new JMenuItem("Select Y axis...");
                         labelSecondColumn.setEnabled(false);
                         plotFirstColumn.add(labelSecondColumn);
                         plotFirstColumn.addSeparator();
-                        for (int j = 0; j < icySheet.getNumberOfColumns(); j++)
-                        {
+                        for (int j = 0; j < icySheet.getNumberOfColumns(); j++) {
                             if (i == j)
                                 continue;
 
@@ -625,31 +502,25 @@ public class WorkbookEditor extends SwingVarEditor<Workbook>
                                 continue;
 
                             if (xValues.length != yValues.length)
-                                throw new IcyHandledException(
-                                        "Cannot create scatter plot: datasets have different sizes");
+                                throw new IcyHandledException("Cannot create scatter plot: datasets have different sizes");
 
                             final double minY = ArrayMath.min(yValues);
                             final double maxY = ArrayMath.max(yValues);
 
                             final String yColumnName = tables.get(sheet).getColumnName(j);
-                            JMenuItem plotSecondColumn = new JMenuItem(yColumnName);
-                            plotSecondColumn.addActionListener(new ActionListener()
-                            {
-                                @Override
-                                public void actionPerformed(ActionEvent actionEvent)
-                                {
-                                    Plot2DPanel panel = new Plot2DPanel();
-                                    panel.addScatterPlot("Scatter plot", xValues, yValues);
-                                    panel.setAxisLabels(xColumnName, yColumnName);
-                                    panel.setFixedBounds(new double[] {minX, minY}, new double[] {maxX, maxY});
-
-                                    IcyFrame plot = new IcyFrame(xColumnName + " vs. " + yColumnName, true);
-                                    plot.setPreferredSize(new Dimension(520, 420));
-                                    plot.addToDesktopPane();
-                                    plot.add(panel);
-                                    plot.pack();
-                                    plot.setVisible(true);
-                                }
+                            final JMenuItem plotSecondColumn = new JMenuItem(yColumnName);
+                            plotSecondColumn.addActionListener(actionEvent -> {
+                                final Plot2DPanel panel = new Plot2DPanel();
+                                panel.addScatterPlot("Scatter plot", xValues, yValues);
+                                panel.setAxisLabels(xColumnName, yColumnName);
+                                panel.setFixedBounds(new double[]{minX, minY}, new double[]{maxX, maxY});
+
+                                final IcyFrame plot = new IcyFrame(xColumnName + " vs. " + yColumnName, true);
+                                plot.setPreferredSize(new Dimension(520, 420));
+                                plot.addToDesktopPane();
+                                plot.add(panel);
+                                plot.pack();
+                                plot.setVisible(true);
                             });
                             plotFirstColumn.add(plotSecondColumn);
                         }
@@ -657,37 +528,31 @@ public class WorkbookEditor extends SwingVarEditor<Workbook>
                 }
 
                 @Override
-                public void menuDeselected(MenuEvent e)
-                {
+                public void menuDeselected(final MenuEvent e) {
                     plotScatter2D.removeAll();
                 }
 
                 @Override
-                public void menuCanceled(MenuEvent e)
-                {
-
+                public void menuCanceled(final MenuEvent e) {
                 }
             });
 
             final JMenu plotScatter3D = new JMenu("Scatter plot (3D)");
-            plotScatter3D.addMenuListener(new MenuListener()
-            {
+            plotScatter3D.addMenuListener(new MenuListener() {
                 @Override
-                public void menuSelected(MenuEvent e)
-                {
-                    int sheetIndex = book.getActiveSheetIndex();
+                public void menuSelected(final MenuEvent e) {
+                    final int sheetIndex = book.getActiveSheetIndex();
                     if (sheetIndex == -1)
                         return;
 
-                    Sheet sheet = book.getSheetAt(sheetIndex);
+                    final Sheet sheet = book.getSheetAt(sheetIndex);
                     final IcySpreadSheet icySheet = Workbooks.getSheet(book, book.getSheetName(sheetIndex));
 
-                    JMenuItem labelFirstColumn = new JMenuItem("Select X axis...");
+                    final JMenuItem labelFirstColumn = new JMenuItem("Select X axis...");
                     labelFirstColumn.setEnabled(false);
                     plotScatter3D.add(labelFirstColumn);
                     plotScatter3D.addSeparator();
-                    for (int i = 0; i < icySheet.getNumberOfColumns(); i++)
-                    {
+                    for (int i = 0; i < icySheet.getNumberOfColumns(); i++) {
                         final double[] xValues = icySheet.getColumnValues(i);
                         if (xValues == null)
                             continue;
@@ -696,16 +561,15 @@ public class WorkbookEditor extends SwingVarEditor<Workbook>
                         final double maxX = ArrayMath.max(xValues);
 
                         final String xColumnName = tables.get(sheet).getColumnName(i);
-                        JMenu plotFirstColumn = new JMenu(xColumnName);
+                        final JMenu plotFirstColumn = new JMenu(xColumnName);
                         plotScatter3D.add(plotFirstColumn);
 
-                        JMenuItem labelSecondColumn = new JMenuItem("Select Y axis...");
+                        final JMenuItem labelSecondColumn = new JMenuItem("Select Y axis...");
                         labelSecondColumn.setEnabled(false);
                         plotFirstColumn.add(labelSecondColumn);
                         plotFirstColumn.addSeparator();
 
-                        for (int j = 0; j < icySheet.getNumberOfColumns(); j++)
-                        {
+                        for (int j = 0; j < icySheet.getNumberOfColumns(); j++) {
                             if (i == j)
                                 continue;
 
@@ -721,16 +585,15 @@ public class WorkbookEditor extends SwingVarEditor<Workbook>
                             final double maxY = ArrayMath.max(yValues);
 
                             final String yColumnName = tables.get(sheet).getColumnName(j);
-                            JMenu plotSecondColumn = new JMenu(yColumnName);
+                            final JMenu plotSecondColumn = new JMenu(yColumnName);
                             plotFirstColumn.add(plotSecondColumn);
 
-                            JMenuItem labelThirdColumn = new JMenuItem("Select Z axis...");
+                            final JMenuItem labelThirdColumn = new JMenuItem("Select Z axis...");
                             labelThirdColumn.setEnabled(false);
                             plotSecondColumn.add(labelThirdColumn);
                             plotSecondColumn.addSeparator();
 
-                            for (int k = 0; k < icySheet.getNumberOfColumns(); k++)
-                            {
+                            for (int k = 0; k < icySheet.getNumberOfColumns(); k++) {
                                 if (i == k || j == k)
                                     continue;
 
@@ -746,28 +609,23 @@ public class WorkbookEditor extends SwingVarEditor<Workbook>
                                 final double maxZ = ArrayMath.max(zValues);
 
                                 final String zColumnName = tables.get(sheet).getColumnName(k);
-                                JMenuItem plotThirdColumn = new JMenuItem(zColumnName);
+                                final JMenuItem plotThirdColumn = new JMenuItem(zColumnName);
                                 plotSecondColumn.add(plotThirdColumn);
 
-                                plotThirdColumn.addActionListener(new ActionListener()
-                                {
-                                    @Override
-                                    public void actionPerformed(ActionEvent actionEvent)
-                                    {
-                                        Plot3DPanel panel = new Plot3DPanel();
-                                        panel.addScatterPlot("Scatter plot", xValues, yValues, zValues);
-                                        panel.setAxisLabels(xColumnName, yColumnName, zColumnName);
-                                        panel.setFixedBounds(new double[] {minX, minY, minZ},
-                                                new double[] {maxX, maxY, maxZ});
-
-                                        IcyFrame plot = new IcyFrame(
-                                                xColumnName + " vs. " + yColumnName + " vs. " + zColumnName, true);
-                                        plot.setPreferredSize(new Dimension(520, 420));
-                                        plot.addToDesktopPane();
-                                        plot.add(panel);
-                                        plot.pack();
-                                        plot.setVisible(true);
-                                    }
+                                plotThirdColumn.addActionListener(actionEvent -> {
+                                    final Plot3DPanel panel = new Plot3DPanel();
+                                    panel.addScatterPlot("Scatter plot", xValues, yValues, zValues);
+                                    panel.setAxisLabels(xColumnName, yColumnName, zColumnName);
+                                    panel.setFixedBounds(new double[]{minX, minY, minZ},
+                                            new double[]{maxX, maxY, maxZ});
+
+                                    final IcyFrame plot = new IcyFrame(
+                                            xColumnName + " vs. " + yColumnName + " vs. " + zColumnName, true);
+                                    plot.setPreferredSize(new Dimension(520, 420));
+                                    plot.addToDesktopPane();
+                                    plot.add(panel);
+                                    plot.pack();
+                                    plot.setVisible(true);
                                 });
                             }
                         }
@@ -775,14 +633,12 @@ public class WorkbookEditor extends SwingVarEditor<Workbook>
                 }
 
                 @Override
-                public void menuDeselected(MenuEvent e)
-                {
+                public void menuDeselected(final MenuEvent e) {
                     plotScatter3D.removeAll();
                 }
 
                 @Override
-                public void menuCanceled(MenuEvent e)
-                {
+                public void menuCanceled(final MenuEvent e) {
 
                 }
             });
@@ -791,21 +647,14 @@ public class WorkbookEditor extends SwingVarEditor<Workbook>
             plotPopupMenu.add(plotHistogram2D);
             plotPopupMenu.add(plotScatter2D);
             plotPopupMenu.add(plotScatter3D);
-            plotButton.addActionListener(new ActionListener()
-            {
-                @Override
-                public void actionPerformed(ActionEvent e)
-                {
-                    plotPopupMenu.show(plotButton, 0, plotButton.getHeight());
-                }
-            });
+            plotButton.addActionListener(e -> plotPopupMenu.show(plotButton, 0, plotButton.getHeight()));
             optionBar.add(plotButton);
 
             // Plot (END)
 
             // Formula
 
-            VarEditor<String> formulaEditor = formula.createVarViewer();
+            final VarEditor<String> formulaEditor = formula.createVarViewer();
             formulaEditor.setEnabled(true);
             optionBar.add((Component) formulaEditor.getEditorComponent());
 
@@ -813,7 +662,7 @@ public class WorkbookEditor extends SwingVarEditor<Workbook>
 
             // Use header
 
-            JCheckBox useHeaderOption = (JCheckBox) useHeader.createVarEditor(true).getEditorComponent();
+            final JCheckBox useHeaderOption = (JCheckBox) useHeader.createVarEditor(true).getEditorComponent();
             useHeaderOption.setText("Use first row as header");
             useHeaderOption.setFocusable(false);
             optionBar.add(useHeaderOption);
@@ -829,11 +678,11 @@ public class WorkbookEditor extends SwingVarEditor<Workbook>
             wbPanel.setName("" + book.hashCode());
         }
 
-        int nSheets = book.getNumberOfSheets();
+        final int nSheets = book.getNumberOfSheets();
 
         // remove unknown tabs (if any)
-        tabCheck: for (int i = 0; i < tabs.getTabCount(); i++)
-        {
+        tabCheck:
+        for (int i = 0; i < tabs.getTabCount(); i++) {
             for (int j = 0; j < nSheets; j++)
                 if (tabs.getTitleAt(i).equalsIgnoreCase(book.getSheetName(j)))
                     continue tabCheck;
@@ -841,24 +690,20 @@ public class WorkbookEditor extends SwingVarEditor<Workbook>
             tabs.remove(i--);
         }
 
-        for (int i = 0; i < nSheets; i++)
-        {
+        for (int i = 0; i < nSheets; i++) {
             Sheet sheet = book.getSheetAt(i);
 
             // check if a tab exists for this sheet
             int currentSheetIndex = -1;
 
-            for (int j = 0; j < tabs.getTabCount(); j++)
-            {
-                if (tabs.getTitleAt(j).equalsIgnoreCase(sheet.getSheetName()))
-                {
+            for (int j = 0; j < tabs.getTabCount(); j++) {
+                if (tabs.getTitleAt(j).equalsIgnoreCase(sheet.getSheetName())) {
                     currentSheetIndex = i;
                     break;
                 }
             }
 
-            if (currentSheetIndex == -1)
-            {
+            if (currentSheetIndex == -1) {
                 // create an empty tab to receive the table
                 tabs.addTab(sheet.getSheetName(), new JPanel());
                 currentSheetIndex = tabs.getTabCount() - 1;
@@ -872,18 +717,16 @@ public class WorkbookEditor extends SwingVarEditor<Workbook>
                 createTable(sheet);
         }
 
-        final List<Sheet> keys = new ArrayList<Sheet>();
-
         // remove old sheets from tables
-        keys.addAll(tables.keySet());
-        for (Sheet sheet : keys)
+        final List<Sheet> keys = new ArrayList<>(tables.keySet());
+        for (final Sheet sheet : keys)
             if (book.getSheetIndex(sheet) == -1)
                 tables.remove(sheet);
 
         // also remove from headers
         keys.clear();
         keys.addAll(headers.keySet());
-        for (Sheet sheet : keys)
+        for (final Sheet sheet : keys)
             if (book.getSheetIndex(sheet) == -1)
                 headers.remove(sheet);
 
@@ -892,26 +735,23 @@ public class WorkbookEditor extends SwingVarEditor<Workbook>
             tabs.addTab("+", new JPanel());
     }
 
-    private static void createSheet(Workbook book)
-    {
+    private static void createSheet(final Workbook book) {
         book.createSheet("Sheet " + (book.getNumberOfSheets() + 1));
     }
 
-    private void updateTable(Sheet sheet)
-    {
-        JXTable table = tables.get(sheet), header = headers.get(sheet);
+    private void updateTable(final Sheet sheet) {
+        final JXTable table = tables.get(sheet);
+        final JXTable header = headers.get(sheet);
 
-        SheetModel model = (SheetModel) table.getModel();
+        final SheetModel model = (SheetModel) table.getModel();
 
-        if (new IcySpreadSheet(sheet).getNumberOfColumns() != table.getColumnCount(true))
-        {
+        if (new IcySpreadSheet(sheet).getNumberOfColumns() != table.getColumnCount(true)) {
             model.fireTableStructureChanged();
         }
-        else if (model.useFirstDataRowAsHeader != useHeader.getValue())
-        {
+        else if (model.useFirstDataRowAsHeader != useHeader.getValue()) {
             model.useFirstDataRowAsHeader = useHeader.getValue();
             model.fireTableDataChanged();
-            for (TableColumn column : table.getColumns(true))
+            for (final TableColumn column : table.getColumns(true))
                 column.setHeaderValue(table.getModel().getColumnName(column.getModelIndex()));
             table.getTableHeader().repaint();
         }
@@ -921,9 +761,7 @@ public class WorkbookEditor extends SwingVarEditor<Workbook>
         table.tableChanged(new TableModelEvent(table.getModel()));
     }
 
-    @SuppressWarnings("serial")
-    private void createTable(final Sheet sheet)
-    {
+    private void createTable(final Sheet sheet) {
         final IcySpreadSheet icySheet = new IcySpreadSheet(sheet);
 
         final int sheetIndex = icySheet.getIndex();
@@ -931,17 +769,12 @@ public class WorkbookEditor extends SwingVarEditor<Workbook>
         final SheetModel tableModel = new SheetModel(icySheet, useHeader.getValue());
         final VarString sheetName = new VarString("sheet name", sheet.getSheetName());
 
-        final JXTable table = new JXTable(tableModel)
-        {
+        final JXTable table = new JXTable(tableModel) {
             @Override
-            public TableCellEditor getCellEditor(int row, int column)
-            {
-                DefaultCellEditor editor = new DefaultCellEditor(new JTextField())
-                {
+            public TableCellEditor getCellEditor(final int row, final int column) {
+                return new DefaultCellEditor(new JTextField()) {
                     @Override
-                    public Component getTableCellEditorComponent(JTable theTable, Object value, boolean isSelected,
-                            int theRow, int theColumn)
-                    {
+                    public Component getTableCellEditorComponent(final JTable theTable, final Object value, final boolean isSelected, int theRow, int theColumn) {
                         theRow = convertRowIndexToModel(theRow);
                         theColumn = convertColumnIndexToModel(theColumn);
 
@@ -953,29 +786,22 @@ public class WorkbookEditor extends SwingVarEditor<Workbook>
                         return super.getTableCellEditorComponent(theTable, contents, true, theRow, theColumn);
                     }
                 };
-                return editor;
             }
 
             @Override
-            public TableCellRenderer getCellRenderer(int row, int column)
-            {
-                return new DefaultTableCellRenderer()
-                {
+            public TableCellRenderer getCellRenderer(final int row, final int column) {
+                return new DefaultTableCellRenderer() {
                     @Override
-                    public Component getTableCellRendererComponent(JTable theTable, Object value, boolean isSelected,
-                            boolean hasFocus, int theRow, int theColumn)
-                    {
-
+                    public Component getTableCellRendererComponent(final JTable theTable, final Object value, final boolean isSelected, final boolean hasFocus, int theRow, int theColumn) {
                         theRow = convertRowIndexToModel(theRow);
                         theColumn = convertColumnIndexToModel(theColumn);
 
                         if (useHeader.getValue())
                             theRow++;
 
-                        Component component = super.getTableCellRendererComponent(theTable, value, isSelected, hasFocus,
-                                theRow, theColumn);
+                        final Component component = super.getTableCellRendererComponent(theTable, value, isSelected, hasFocus, theRow, theColumn);
 
-                        Color fillColor = icySheet.getFillColor(theRow, theColumn);
+                        final Color fillColor = icySheet.getFillColor(theRow, theColumn);
                         if (fillColor != null)
                             component.setBackground(fillColor);
 
@@ -985,38 +811,31 @@ public class WorkbookEditor extends SwingVarEditor<Workbook>
             }
         };
 
-        Comparator<Object> comparator = new Comparator<Object>()
-        {
-            @SuppressWarnings({"unchecked", "rawtypes"})
-            @Override
-            public int compare(Object a, Object b)
-            {
-                if (a == null)
-                    a = "";
-                if (b == null)
-                    b = "";
-
-                // compare what is comparable
-                if (a instanceof Comparable && b instanceof Comparable
-                        && (a.getClass().isAssignableFrom(b.getClass()) || b.getClass().isAssignableFrom(a.getClass())))
-                {
-                    return ((Comparable) a).compareTo(b);
-                }
+        final Comparator<Object> comparator = (a, b) -> {
+            if (a == null)
+                a = "";
+            if (b == null)
+                b = "";
+
+            // compare what is comparable
+            if (a instanceof Comparable && b instanceof Comparable
+                    && (a.getClass().isAssignableFrom(b.getClass()) || b.getClass().isAssignableFrom(a.getClass()))) {
+                @SuppressWarnings("unchecked") final int compare = ((Comparable<Object>) a).compareTo(b);
+                return compare;
+            }
 
-                // otherwise, one of them is perhaps a String
-                if (a instanceof String)
-                    return -1;
-                if (b instanceof String)
-                    return 1;
+            // otherwise, one of them is perhaps a String
+            if (a instanceof String)
+                return -1;
+            if (b instanceof String)
+                return 1;
 
-                // if none of the above, don't try comparing at all!
-                return 0;
-            }
+            // if none of the above, don't try comparing at all!
+            return 0;
         };
 
-        int nCol = table.getColumnCount();
-        for (int i = 0; i < nCol; i++)
-        {
+        final int nCol = table.getColumnCount();
+        for (int i = 0; i < nCol; i++) {
             table.getColumnExt(i).setComparator(comparator);
             table.setSortOrderCycle(SortOrder.DESCENDING, SortOrder.ASCENDING, SortOrder.UNSORTED);
         }
@@ -1027,52 +846,42 @@ public class WorkbookEditor extends SwingVarEditor<Workbook>
         table.setColumnControlVisible(true);
         table.setColumnControl(new PersistentColumnControlButton(table));
 
-        JScrollPane scrollPane = new JScrollPane(table, JScrollPane.VERTICAL_SCROLLBAR_ALWAYS,
-                JScrollPane.HORIZONTAL_SCROLLBAR_AS_NEEDED);
+        final JScrollPane scrollPane = new JScrollPane(table, JScrollPane.VERTICAL_SCROLLBAR_ALWAYS, JScrollPane.HORIZONTAL_SCROLLBAR_AS_NEEDED);
 
         // Create the row header (first column with line numbers)
         // code adapted and largely inspired from:
         // http://stackoverflow.com/questions/6711877/jtable-use-row-numbers
 
-        final AbstractTableModel headerModel = new AbstractTableModel()
-        {
+        final AbstractTableModel headerModel = new AbstractTableModel() {
             @Override
-            public int getColumnCount()
-            {
+            public int getColumnCount() {
                 return 1;
             }
 
             @Override
-            public Object getValueAt(int row, int column)
-            {
+            public Object getValueAt(final int row, final int column) {
                 return row + 1;
             }
 
             @Override
-            public int getRowCount()
-            {
+            public int getRowCount() {
                 return tableModel.getRowCount();
             }
         };
 
-        JXTable headerTable = new JXTable(headerModel)
-        {
+        final JXTable headerTable = new JXTable(headerModel) {
             @Override
-            public TableCellRenderer getCellRenderer(int row, int column)
-            {
-                return new TableCellRenderer()
-                {
+            public TableCellRenderer getCellRenderer(final int row, final int column) {
+                return new TableCellRenderer() {
                     private final TableCellRenderer headerRenderer = table.getTableHeader().getDefaultRenderer();
 
                     Font headerFont = null;
 
                     @Override
-                    public Component getTableCellRendererComponent(JTable theTable, Object value, boolean isSelected,
-                            boolean hasFocus, int theRow, int theColumn)
-                    {
+                    public Component getTableCellRendererComponent(final JTable theTable, final Object value, boolean isSelected, final boolean hasFocus, final int theRow, final int theColumn) {
                         isSelected = table.getSelectionModel().isSelectedIndex(theRow);
 
-                        Component c = headerRenderer.getTableCellRendererComponent(theTable, value, isSelected,
+                        final Component c = headerRenderer.getTableCellRendererComponent(theTable, value, isSelected,
                                 hasFocus, -1, theColumn);
 
                         if (headerFont == null)
@@ -1094,14 +903,7 @@ public class WorkbookEditor extends SwingVarEditor<Workbook>
 
         // changes to the table should affect the header...
 
-        table.getRowSorter().addRowSorterListener(new RowSorterListener()
-        {
-            @Override
-            public void sorterChanged(RowSorterEvent e)
-            {
-                headerModel.fireTableDataChanged();
-            }
-        });
+        table.getRowSorter().addRowSorterListener(e -> headerModel.fireTableDataChanged());
 
         // ... and clicking on the header should select the table line
         // headerTable.getSelectionModel().addListSelectionListener(new ListSelectionListener()
@@ -1137,71 +939,66 @@ public class WorkbookEditor extends SwingVarEditor<Workbook>
 
         final JLabel sheetNameLabel = new JLabel(sheetName.getValue());
 
-        class Listener implements ListSelectionListener, TableColumnModelListener
-        {
+        class Listener implements ListSelectionListener, TableColumnModelListener {
             @Override
-            public void valueChanged(ListSelectionEvent e)
-            {
+            public void valueChanged(final ListSelectionEvent e) {
                 if (e.getValueIsAdjusting())
                     return;
 
                 if (table.getSelectedRow() == -1)
                     return;
-                int row = table.convertRowIndexToModel(table.getSelectedRow());
-                int column = table.convertColumnIndexToModel(table.getSelectedColumn());
+                final int row = table.convertRowIndexToModel(table.getSelectedRow());
+                final int column = table.convertColumnIndexToModel(table.getSelectedColumn());
                 updateFormulaField(tableModel, row, column);
             }
 
             @Override
-            public void columnSelectionChanged(ListSelectionEvent e)
-            {
+            public void columnSelectionChanged(final ListSelectionEvent e) {
                 valueChanged(e);
             }
 
             @Override
-            public void columnRemoved(TableColumnModelEvent e)
-            {
+            public void columnRemoved(final TableColumnModelEvent e) {
             }
 
             @Override
-            public void columnMoved(TableColumnModelEvent e)
-            {
+            public void columnMoved(final TableColumnModelEvent e) {
             }
 
             @Override
-            public void columnMarginChanged(ChangeEvent e)
-            {
+            public void columnMarginChanged(final ChangeEvent e) {
             }
 
             @Override
-            public void columnAdded(TableColumnModelEvent e)
-            {
+            public void columnAdded(final TableColumnModelEvent e) {
             }
         }
 
-        Listener l = new Listener();
+        final Listener l = new Listener();
         table.getSelectionModel().addListSelectionListener(l);
         table.getColumnModel().addColumnModelListener(l);
 
-        if (!readOnly.getValue())
-        {
+        if (!readOnly.getValue()) {
             // handle sheet name changing
 
             sheetNameLabel.setRequestFocusEnabled(false);
 
-            sheetNameLabel.addMouseListener(new MouseAdapter()
-            {
+            sheetNameLabel.addMouseListener(new MouseAdapter() {
                 @Override
-                public void mouseClicked(MouseEvent e)
-                {
-                    if (e.getClickCount() == 1)
-                    {
+                public void mouseClicked(final MouseEvent e) {
+                    if (e.getClickCount() == 1) {
                         tabs.setSelectedIndex(sheetIndex);
                     }
-                    else
-                    {
-                        Object answer = JOptionPane.showInputDialog(sheetNameLabel, null, "Rename this sheet to...",
-                                JOptionPane.QUESTION_MESSAGE, null, null, sheetName.getValue());
+                    else {
+                        final Object answer = JOptionPane.showInputDialog(
+                                sheetNameLabel,
+                                null,
+                                "Rename this sheet to...",
+                                JOptionPane.QUESTION_MESSAGE,
+                                null,
+                                null,
+                                sheetName.getValue()
+                        );
 
                         if (answer != null)
                             sheetName.setValue(answer.toString());
@@ -1209,19 +1006,15 @@ public class WorkbookEditor extends SwingVarEditor<Workbook>
                 }
             });
 
-            sheetName.addListener(new VarListener<String>()
-            {
+            sheetName.addListener(new VarListener<>() {
                 @Override
-                public void valueChanged(Var<String> source, String oldValue, String newValue)
-                {
+                public void valueChanged(final Var<String> source, final String oldValue, final String newValue) {
                     variable.getValue().setSheetName(sheetIndex, newValue);
                     sheetNameLabel.setText(newValue);
                 }
 
                 @Override
-                public void referenceChanged(Var<String> source, Var<? extends String> oldReference,
-                        Var<? extends String> newReference)
-                {
+                public void referenceChanged(final Var<String> source, final Var<? extends String> oldReference, final Var<? extends String> newReference) {
                 }
             });
         }
@@ -1230,10 +1023,8 @@ public class WorkbookEditor extends SwingVarEditor<Workbook>
         tabs.setTitleAt(sheetIndex, sheet.getSheetName());
     }
 
-    private void updateFormulaField(SheetModel model, int row, int col)
-    {
-        if (col == -1)
-        {
+    private void updateFormulaField(final SheetModel model, int row, final int col) {
+        if (col == -1) {
             formula.setValue("");
             return;
         }
@@ -1243,61 +1034,49 @@ public class WorkbookEditor extends SwingVarEditor<Workbook>
 
         String value = model.sheet.getFormula(row, col);
 
-        if (!value.isEmpty())
-        {
+        if (!value.isEmpty()) {
             formula.setValue(" Formula: =" + value);
         }
-        else
-        {
+        else {
             value = "" + model.sheet.getValue(row, col);
 
-            if (!value.isEmpty())
-            {
+            if (!value.isEmpty()) {
                 formula.setValue(" Value: " + value);
             }
-            else
-            {
+            else {
                 formula.setValue("");
             }
         }
     }
 
-    @SuppressWarnings("serial")
-    private class SheetModel extends AbstractTableModel
-    {
+    private class SheetModel extends AbstractTableModel {
         final int MAX_NB_ROWS = 65536;
 
         final int MAX_NB_COLS = 256;
 
-        private boolean useFirstDataRowAsHeader = false;
+        private boolean useFirstDataRowAsHeader;
 
         final IcySpreadSheet sheet;
 
-        public SheetModel(IcySpreadSheet sheet, boolean useFirstRowAsHeader)
-        {
+        public SheetModel(final IcySpreadSheet sheet, final boolean useFirstRowAsHeader) {
             this.sheet = sheet;
             this.useFirstDataRowAsHeader = useFirstRowAsHeader;
         }
 
         @Override
-        public void setValueAt(Object aValue, int rowIndex, int columnIndex)
-        {
-            if (aValue instanceof String)
-            {
-                String text = (String) aValue;
-
-                if (text.isEmpty())
-                {
+        public void setValueAt(final Object aValue, final int rowIndex, final int columnIndex) {
+            if (aValue instanceof String) {
+                final String text = (String) aValue;
+
+                if (text.isEmpty()) {
                     sheet.deleteCell(rowIndex, columnIndex);
                 }
                 else if (text.startsWith("="))
-                    try
-                    {
+                    try {
                         // Parse a formula first
                         sheet.setFormula(rowIndex, columnIndex, text);
                     }
-                    catch (FormulaParseException e1)
-                    {
+                    catch (final FormulaParseException e1) {
                         sheet.setValue(rowIndex, columnIndex, text);
                     }
                 else
@@ -1310,8 +1089,7 @@ public class WorkbookEditor extends SwingVarEditor<Workbook>
         }
 
         @Override
-        public Object getValueAt(int rowIndex, int columnIndex)
-        {
+        public Object getValueAt(int rowIndex, final int columnIndex) {
             if (useFirstDataRowAsHeader)
                 rowIndex++;
 
@@ -1319,19 +1097,17 @@ public class WorkbookEditor extends SwingVarEditor<Workbook>
         }
 
         @Override
-        public int getRowCount()
-        {
+        public int getRowCount() {
             if (!readOnly.getValue())
                 return MAX_NB_ROWS;
 
-            int nbRows = sheet.getNumberOfRows();
+            final int nbRows = sheet.getNumberOfRows();
 
             return useFirstDataRowAsHeader ? nbRows - 1 : nbRows;
         }
 
         @Override
-        public String getColumnName(int columnIndex)
-        {
+        public String getColumnName(final int columnIndex) {
             if (useFirstDataRowAsHeader)
                 return "" + getValueAt(-1, columnIndex);
 
@@ -1339,8 +1115,7 @@ public class WorkbookEditor extends SwingVarEditor<Workbook>
         }
 
         @Override
-        public int getColumnCount()
-        {
+        public int getColumnCount() {
             if (!readOnly.getValue())
                 return MAX_NB_COLS;
 
@@ -1348,8 +1123,7 @@ public class WorkbookEditor extends SwingVarEditor<Workbook>
         }
 
         @Override
-        public boolean isCellEditable(int rowIndex, int columnIndex)
-        {
+        public boolean isCellEditable(final int rowIndex, final int columnIndex) {
             return !readOnly.getValue();
         }
     }
diff --git a/src/main/java/plugins/adufour/vars/lang/VarWorkbook.java b/src/main/java/plugins/adufour/vars/lang/VarWorkbook.java
index bf91aed71797be50853bb9eba51f272e3f9a31f8..7f76ccff3db231c814018e0fab9ca43e36cc12ac 100644
--- a/src/main/java/plugins/adufour/vars/lang/VarWorkbook.java
+++ b/src/main/java/plugins/adufour/vars/lang/VarWorkbook.java
@@ -1,79 +1,78 @@
-package plugins.adufour.vars.lang;
+/*
+ * Copyright (c) 2010-2023. Institut Pasteur.
+ *
+ * This file is part of Icy.
+ * Icy is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Icy is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Icy. If not, see <https://www.gnu.org/licenses/>.
+ */
 
-import java.io.File;
-import java.io.FileOutputStream;
-import java.io.IOException;
-
-import javax.annotation.processing.FilerException;
+package plugins.adufour.vars.lang;
 
-import org.apache.poi.openxml4j.exceptions.InvalidFormatException;
 import org.apache.poi.ss.usermodel.Workbook;
 import org.apache.poi.ss.usermodel.WorkbookFactory;
 import org.apache.poi.xssf.usermodel.XSSFWorkbook;
-
 import plugins.adufour.vars.gui.VarEditor;
 import plugins.adufour.vars.gui.swing.WorkbookEditor;
 import plugins.adufour.vars.util.VarException;
 import plugins.adufour.workbooks.Workbooks;
 
-public class VarWorkbook extends Var<Workbook>
-{
+import javax.annotation.processing.FilerException;
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.IOException;
+
+public class VarWorkbook extends Var<Workbook> {
     /**
      * Creates a new variable with the workbook read from the specified file
-     * 
-     * @param name
-     *        the name of the workbook
-     * @param workbook
-     *        the workbook to work with
+     *
+     * @param name     the name of the workbook
+     * @param workbook the workbook to work with
      */
-    public VarWorkbook(String name, Workbook workbook)
-    {
+    public VarWorkbook(final String name, final Workbook workbook) {
         super(name, Workbook.class, workbook, null);
     }
 
     /**
      * Creates a new variable with the workbook read from the specified file
-     * 
-     * @param name
-     *        the name of the workbook
-     * @param file
-     *        the file to read the workbook from
-     * @throws InvalidFormatException
-     *         if input file format is incorrect
-     * @throws IOException
-     *         if input file is not found
+     *
+     * @param name the name of the workbook
+     * @param file the file to read the workbook from
+     * @throws IOException if input file is not found
      */
-    public VarWorkbook(String name, File file) throws InvalidFormatException, IOException
-    {
+    public VarWorkbook(final String name, final File file) throws IOException {
         this(name, WorkbookFactory.create(file));
     }
 
     /**
      * Creates a new variable with a new empty workbook
-     * 
-     * @param name
-     *        the name of the workbook
-     * @param firstSheetName
-     *        the name of the first sheet
+     *
+     * @param name           the name of the workbook
+     * @param firstSheetName the name of the first sheet
      */
-    public VarWorkbook(String name, String firstSheetName)
-    {
+    public VarWorkbook(final String name, final String firstSheetName) {
         this(name, Workbooks.createEmptyWorkbook());
 
         getValue().createSheet(firstSheetName);
     }
 
     @Override
-    public VarEditor<Workbook> createVarEditor()
-    {
-        WorkbookEditor editor = new WorkbookEditor(this);
-        return editor;
+    public VarEditor<Workbook> createVarEditor() {
+        return new WorkbookEditor(this);
     }
 
     @Override
-    public VarEditor<Workbook> createVarViewer()
-    {
-        WorkbookEditor editor = new WorkbookEditor(this);
+    public VarEditor<Workbook> createVarViewer() {
+        final WorkbookEditor editor = new WorkbookEditor(this);
         editor.setReadOnly(true);
         editor.setOpenButtonVisible(false);
         return editor;
@@ -81,29 +80,24 @@ public class VarWorkbook extends Var<Workbook>
 
     /**
      * Save the workbook to disk
-     * 
-     * @param folder
-     *        the folder on disk where the workbook should be saved (must exist)
-     * @param workbookName
-     *        the name of the workbook (without extension)
-     * @throws VarException
-     *         if the workbook is <code>null</code>
-     * @throws IOException
-     *         if the file cannot be accessed
+     *
+     * @param folder       the folder on disk where the workbook should be saved (must exist)
+     * @param workbookName the name of the workbook (without extension)
+     * @throws VarException if the workbook is <code>null</code>
+     * @throws IOException  if the file cannot be accessed
      */
-    public void saveToDisk(File folder, String workbookName) throws VarException, IOException
-    {
+    public void saveToDisk(final File folder, final String workbookName) throws VarException, IOException {
         if (!folder.isDirectory())
             throw new FilerException(folder + "is not a valid folder");
 
-        Workbook wb = getValue(true);
+        final Workbook wb = getValue(true);
 
         String filename = folder.getPath() + File.separator + workbookName + ".xls";
 
         if (wb instanceof XSSFWorkbook)
             filename = filename + "x";
 
-        FileOutputStream out = new FileOutputStream(filename);
+        final FileOutputStream out = new FileOutputStream(filename);
         wb.write(out);
         out.close();
     }
diff --git a/src/main/java/plugins/adufour/workbooks/IcySpreadSheet.java b/src/main/java/plugins/adufour/workbooks/IcySpreadSheet.java
index c6b6d596a87f436ed41aadb36181df8f28cf07ba..8495c691f9d56b304798b5ae330fbe60e3af79de 100644
--- a/src/main/java/plugins/adufour/workbooks/IcySpreadSheet.java
+++ b/src/main/java/plugins/adufour/workbooks/IcySpreadSheet.java
@@ -1,63 +1,69 @@
-package plugins.adufour.workbooks;
+/*
+ * Copyright (c) 2010-2023. Institut Pasteur.
+ *
+ * This file is part of Icy.
+ * Icy is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Icy is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Icy. If not, see <https://www.gnu.org/licenses/>.
+ */
 
-import java.awt.Color;
-import java.lang.reflect.Array;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.HashMap;
-import java.util.Iterator;
-import java.util.Map;
+package plugins.adufour.workbooks;
 
 import org.apache.poi.hssf.usermodel.HSSFPalette;
 import org.apache.poi.hssf.usermodel.HSSFWorkbook;
 import org.apache.poi.hssf.util.HSSFColor;
 import org.apache.poi.ss.formula.FormulaParseException;
-import org.apache.poi.ss.usermodel.Cell;
-import org.apache.poi.ss.usermodel.CellStyle;
-import org.apache.poi.ss.usermodel.FillPatternType;
-import org.apache.poi.ss.usermodel.FormulaEvaluator;
-import org.apache.poi.ss.usermodel.Row;
-import org.apache.poi.ss.usermodel.Sheet;
-import org.apache.poi.ss.usermodel.Workbook;
+import org.apache.poi.ss.usermodel.*;
+import org.apache.poi.xssf.usermodel.DefaultIndexedColorMap;
 import org.apache.poi.xssf.usermodel.XSSFCellStyle;
 import org.apache.poi.xssf.usermodel.XSSFColor;
 import org.apache.poi.xssf.usermodel.XSSFWorkbook;
 
+import java.awt.Color;
+import java.lang.reflect.Array;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.Map;
+
 /**
  * Results table for Icy. This class relies on the Apache POI library, and acts as a high-level
  * wrapper for the {@link Sheet} class
- * 
+ *
  * @author Alexandre Dufour
  */
-public class IcySpreadSheet
-{
+public class IcySpreadSheet {
     private final Sheet sheet;
 
     private final FormulaEvaluator evaluator;
 
     private final Map<Color, CellStyle> colorStyleMap;
 
-    public IcySpreadSheet(Sheet sheet)
-    {
+    public IcySpreadSheet(final Sheet sheet) {
         this.sheet = sheet;
         this.evaluator = sheet.getWorkbook().getCreationHelper().createFormulaEvaluator();
-        this.colorStyleMap = new HashMap<Color, CellStyle>();
+        this.colorStyleMap = new HashMap<>();
     }
 
     /**
-     * @param sourceColumn
-     *        the index of the row to copy (NB: the first row is at index 0)
-     * @param targetColumn
-     *        the index of the row where the source row will be pasted (NB: the first row is at
-     *        index 0)
+     * @param sourceColumn the index of the row to copy (NB: the first row is at index 0)
+     * @param targetColumn the index of the row where the source row will be pasted (NB: the first row is at
+     *                     index 0)
      */
-    public void copyColumn(int sourceColumn, int targetColumn)
-    {
-        Row source = sheet.getRow(sourceColumn);
-        Row target = sheet.getRow(targetColumn);
+    public void copyColumn(final int sourceColumn, final int targetColumn) {
+        final Row source = sheet.getRow(sourceColumn);
+        final Row target = sheet.getRow(targetColumn);
 
-        if (source == null)
-        {
+        if (source == null) {
             if (target != null)
                 sheet.removeRow(target);
             return;
@@ -66,34 +72,29 @@ public class IcySpreadSheet
         if (target == null)
             sheet.createRow(targetColumn);
 
-        int nCells = source.getLastCellNum();
+        final int nCells = source.getLastCellNum();
 
-        for (int i = 0; i < nCells; i++)
-        {
-            Cell sourceCell = source.getCell(i, Row.MissingCellPolicy.RETURN_BLANK_AS_NULL);
+        for (int i = 0; i < nCells; i++) {
+            final Cell sourceCell = source.getCell(i, Row.MissingCellPolicy.RETURN_BLANK_AS_NULL);
 
-            if (sourceCell != null)
-            {
-                Cell targetCell = target.getCell(i, Row.MissingCellPolicy.CREATE_NULL_AS_BLANK);
+            if (sourceCell != null) {
+                assert target != null;
+                final Cell targetCell = target.getCell(i, Row.MissingCellPolicy.CREATE_NULL_AS_BLANK);
                 Workbooks.copyCell(sourceCell, targetCell);
             }
         }
     }
 
     /**
-     * @param sourceRow
-     *        the index of the row to copy (NB: the first row is at index 0)
-     * @param targetRow
-     *        the index of the row where the source row will be pasted (NB: the first row is at
-     *        index 0)
+     * @param sourceRow the index of the row to copy (NB: the first row is at index 0)
+     * @param targetRow the index of the row where the source row will be pasted (NB: the first row is at
+     *                  index 0)
      */
-    public void copyRow(int sourceRow, int targetRow)
-    {
-        Row source = sheet.getRow(sourceRow);
-        Row target = getOrCreateRow(targetRow);
+    public void copyRow(final int sourceRow, final int targetRow) {
+        final Row source = sheet.getRow(sourceRow);
+        final Row target = getOrCreateRow(targetRow);
 
-        if (source == null)
-        {
+        if (source == null) {
             if (target != null)
                 sheet.removeRow(target);
             return;
@@ -102,15 +103,14 @@ public class IcySpreadSheet
         if (target == null)
             sheet.createRow(targetRow);
 
-        int nCells = source.getLastCellNum();
+        final int nCells = source.getLastCellNum();
 
-        for (int i = 0; i < nCells; i++)
-        {
-            Cell sourceCell = source.getCell(i, Row.MissingCellPolicy.RETURN_BLANK_AS_NULL);
+        for (int i = 0; i < nCells; i++) {
+            final Cell sourceCell = source.getCell(i, Row.MissingCellPolicy.RETURN_BLANK_AS_NULL);
 
-            if (sourceCell != null)
-            {
-                Cell targetCell = target.getCell(i, Row.MissingCellPolicy.CREATE_NULL_AS_BLANK);
+            if (sourceCell != null) {
+                assert target != null;
+                final Cell targetCell = target.getCell(i, Row.MissingCellPolicy.CREATE_NULL_AS_BLANK);
                 Workbooks.copyCell(sourceCell, targetCell);
             }
         }
@@ -118,21 +118,17 @@ public class IcySpreadSheet
 
     /**
      * Deletes the cell at the specified row and column (NB: the first row or column index is 0).
-     * 
-     * @param rowIndex
-     *        the row index of the cell to delete (starting at 0)
-     * @param columnIndex
-     *        the column index of the cell to delete (starting at 0)
+     *
+     * @param rowIndex    the row index of the cell to delete (starting at 0)
+     * @param columnIndex the column index of the cell to delete (starting at 0)
      */
-    public void deleteCell(int rowIndex, int columnIndex)
-    {
-        Row row = sheet.getRow(rowIndex);
+    public void deleteCell(final int rowIndex, final int columnIndex) {
+        final Row row = sheet.getRow(rowIndex);
         if (row == null)
             return;
 
-        Cell cell = row.getCell(columnIndex);
-        if (cell != null)
-        {
+        final Cell cell = row.getCell(columnIndex);
+        if (cell != null) {
             row.removeCell(cell);
             evaluator.notifyDeleteCell(cell);
         }
@@ -140,35 +136,30 @@ public class IcySpreadSheet
 
     /**
      * Deletes the column at the specified index (NB: the first column is at index 0).
-     * 
-     * @param columnIndex
-     *        the index of the column to remove (starting at 0)
-     * @param shiftData
-     *        set to <code>true</code> to shift all other columns up, or <code>false</code> to
-     *        leave the column empty
+     *
+     * @param columnIndex the index of the column to remove (starting at 0)
+     * @param shiftData   set to <code>true</code> to shift all other columns up, or <code>false</code> to
+     *                    leave the column empty
      */
-    public void deleteColumn(int columnIndex, boolean shiftData)
-    {
-        int lastRow = sheet.getLastRowNum();
+    public void deleteColumn(final int columnIndex, final boolean shiftData) {
+        final int lastRow = sheet.getLastRowNum();
 
-        for (int r = 0; r <= lastRow; r++)
-        {
-            Row row = sheet.getRow(r);
+        for (int r = 0; r <= lastRow; r++) {
+            final Row row = sheet.getRow(r);
             if (row == null)
                 continue;
 
-            int lastColumn = row.getLastCellNum() - 1;
+            final int lastColumn = row.getLastCellNum() - 1;
 
             if (columnIndex > lastColumn)
                 continue;
 
-            Cell cell = row.getCell(columnIndex);
+            final Cell cell = row.getCell(columnIndex);
 
             if (cell != null)
                 row.removeCell(cell);
 
-            if (shiftData && columnIndex < lastColumn)
-            {
+            if (shiftData && columnIndex < lastColumn) {
                 for (int i = columnIndex; i < lastColumn; i++)
                     Workbooks.copyCell(row.getCell(i + 1), row.getCell(i, Row.MissingCellPolicy.CREATE_NULL_AS_BLANK));
                 row.removeCell(row.getCell(lastColumn));
@@ -178,28 +169,24 @@ public class IcySpreadSheet
 
     /**
      * Deletes the row at the specified index (NB: the first row is at index 0).
-     * 
-     * @param rowIndex
-     *        the index of the row to remove (starting at 0)
-     * @param shiftData
-     *        set to <code>true</code> to shift all other lines up, or <code>false</code> to
-     *        leave the line empty
+     *
+     * @param rowIndex  the index of the row to remove (starting at 0)
+     * @param shiftData set to <code>true</code> to shift all other lines up, or <code>false</code> to
+     *                  leave the line empty
      */
-    public void deleteRow(int rowIndex, boolean shiftData)
-    {
-        int lastRow = sheet.getLastRowNum();
+    public void deleteRow(final int rowIndex, final boolean shiftData) {
+        final int lastRow = sheet.getLastRowNum();
 
         // don't do anything if the column does not exist
         if (rowIndex >= lastRow)
             return;
 
-        Row rowToRemove = sheet.getRow(rowIndex);
+        final Row rowToRemove = sheet.getRow(rowIndex);
 
         if (rowToRemove != null)
             sheet.removeRow(rowToRemove);
 
-        if (shiftData && rowIndex < lastRow)
-        {
+        if (shiftData && rowIndex < lastRow) {
             for (int i = rowIndex + 1; i <= lastRow; i++)
                 copyRow(i + 1, i);
 
@@ -208,35 +195,26 @@ public class IcySpreadSheet
     }
 
     /**
-     * @param row
-     *        row index
-     * @param column
-     *        column index
+     * @param row    row index
+     * @param column column index
      * @return the background color of the specified cell
      */
-    public Color getFillColor(int row, int column)
-    {
-        Cell cell = getOrCreateRow(row).getCell(column, Row.MissingCellPolicy.CREATE_NULL_AS_BLANK);
-
-        org.apache.poi.ss.usermodel.Color color = cell.getCellStyle().getFillForegroundColorColor();
-        if (color instanceof HSSFColor)
-        {
-            short[] rgb = ((HSSFColor) color).getTriplet();
-            if ((rgb != null) && (rgb.length >= 3))
-            {
-                if (rgb[0] != 0 || rgb[1] != 0 || rgb[2] != 0)
-                {
+    public Color getFillColor(final int row, final int column) {
+        final Cell cell = getOrCreateRow(row).getCell(column, Row.MissingCellPolicy.CREATE_NULL_AS_BLANK);
+
+        final org.apache.poi.ss.usermodel.Color color = cell.getCellStyle().getFillForegroundColorColor();
+        if (color instanceof HSSFColor) {
+            final short[] rgb = ((HSSFColor) color).getTriplet();
+            if ((rgb != null) && (rgb.length >= 3)) {
+                if (rgb[0] != 0 || rgb[1] != 0 || rgb[2] != 0) {
                     return new Color(rgb[0], rgb[1], rgb[2]);
                 }
             }
         }
-        else if (color instanceof XSSFColor)
-        {
-            byte[] rgb = ((XSSFColor) color).getRGB();
-            if ((rgb != null) && (rgb.length >= 3))
-            {
-                if (rgb[0] != 0 || rgb[1] != 0 || rgb[2] != 0)
-                {
+        else if (color instanceof XSSFColor) {
+            final byte[] rgb = ((XSSFColor) color).getRGB();
+            if ((rgb != null) && (rgb.length >= 3)) {
+                if (rgb[0] != 0 || rgb[1] != 0 || rgb[2] != 0) {
                     return new Color(rgb[0] & 0xff, rgb[1] & 0xff, rgb[2] & 0xff);
                 }
             }
@@ -246,100 +224,87 @@ public class IcySpreadSheet
     }
 
     /**
-     * @param rowIndex
-     *        the 0-based row index of the cell
-     * @param columnIndex
-     *        the 0-based column index of the cell
+     * @param rowIndex    the 0-based row index of the cell
+     * @param columnIndex the 0-based column index of the cell
      * @return the cell formula at the specified location (or an empty string if the cell does not
-     *         hold a formula)
+     * hold a formula)
      */
-    public String getFormula(int rowIndex, int columnIndex)
-    {
-        Row row = sheet.getRow(rowIndex);
+    public String getFormula(final int rowIndex, final int columnIndex) {
+        final Row row = sheet.getRow(rowIndex);
         if (row == null)
             return "";
 
-        Cell cell = row.getCell(columnIndex, Row.MissingCellPolicy.RETURN_BLANK_AS_NULL);
+        final Cell cell = row.getCell(columnIndex, Row.MissingCellPolicy.RETURN_BLANK_AS_NULL);
         if (cell == null)
             return "";
 
-        return cell.getCellType() == Cell.CELL_TYPE_FORMULA ? cell.getCellFormula() : "";
+        return cell.getCellType() == CellType.FORMULA ? cell.getCellFormula() : "";
     }
 
     /**
-     * @param rowIndex
-     *        the 0-based row index of the cell
-     * @param columnIndex
-     *        the 0-based column index of the cell
+     * @param rowIndex    the 0-based row index of the cell
+     * @param columnIndex the 0-based column index of the cell
      * @return the cell at the specified location (or an empty string if the cell is empty)
      */
-    public Object getValue(int rowIndex, int columnIndex)
-    {
-        Row row = sheet.getRow(rowIndex);
+    public Object getValue(final int rowIndex, final int columnIndex) {
+        final Row row = sheet.getRow(rowIndex);
         if (row == null)
             return "";
 
-        Cell cell = row.getCell(columnIndex, Row.MissingCellPolicy.RETURN_BLANK_AS_NULL);
+        final Cell cell = row.getCell(columnIndex, Row.MissingCellPolicy.RETURN_BLANK_AS_NULL);
         if (cell == null)
             return "";
 
-        if (cell.getCellType() == Cell.CELL_TYPE_STRING)
+        if (cell.getCellType() == CellType.STRING)
             return cell.getStringCellValue();
 
-        if (cell.getCellType() == Cell.CELL_TYPE_BOOLEAN)
+        if (cell.getCellType() == CellType.BOOLEAN)
             return cell.getBooleanCellValue();
 
         return evaluator.evaluate(cell).getNumberValue();
     }
 
     /**
-     * @param rowIndex
-     *        the 0-based row index
+     * @param rowIndex the 0-based row index
      * @return
      */
-    private Row getOrCreateRow(int rowIndex)
-    {
-        Row row = sheet.getRow(rowIndex);
+    private Row getOrCreateRow(final int rowIndex) {
+        final Row row = sheet.getRow(rowIndex);
         return row != null ? row : sheet.createRow(rowIndex);
     }
 
     /**
      * @return the index of this sheet within its workbook (NB: the first index is 0)
      */
-    public int getIndex()
-    {
+    public int getIndex() {
         return sheet.getWorkbook().getSheetIndex(sheet);
     }
 
     /**
      * @return the name of this sheet
      */
-    public String getName()
-    {
+    public String getName() {
         return sheet.getSheetName();
     }
 
     /**
      * @return The number of rows in this table. Note that this number indicates the index of the
-     *         last row, but does not necessarily indicate that all other rows contain data
+     * last row, but does not necessarily indicate that all other rows contain data
      */
-    public int getNumberOfRows()
-    {
+    public int getNumberOfRows() {
         return sheet.getLastRowNum() + 1;
     }
 
     /**
      * @return The number of columns in this table. Note that this number indicates the index of the
-     *         last known column, but does not necessarily indicate that all other columns contain
-     *         data, or that all rows use that many columns
+     * last known column, but does not necessarily indicate that all other columns contain
+     * data, or that all rows use that many columns
      */
-    public int getNumberOfColumns()
-    {
+    public int getNumberOfColumns() {
         int nCols = 0;
-        int lastRow = sheet.getLastRowNum();
-        for (int i = 0; i <= lastRow; i++)
-        {
-            Row row = sheet.getRow(i);
+        final int lastRow = sheet.getLastRowNum();
+        for (int i = 0; i <= lastRow; i++) {
+            final Row row = sheet.getRow(i);
             if (row != null)
                 nCols = Math.max(nCols, row.getLastCellNum());
         }
@@ -349,48 +314,38 @@ public class IcySpreadSheet
     /**
      * @return the underlying {@link Sheet} implementation backing this object.
      */
-    public Sheet getSheet()
-    {
+    public Sheet getSheet() {
         return sheet;
     }
 
     /**
      * Sets the fill color of the specified cell
-     * 
-     * @param row
-     *        row index
-     * @param column
-     *        column index
-     * @param color
-     *        the color to assign
+     *
+     * @param row    row index
+     * @param column column index
+     * @param color  the color to assign
      */
-    public void setFillColor(int row, int column, Color color)
-    {
-        Cell cell = getOrCreateRow(row).getCell(column, Row.MissingCellPolicy.CREATE_NULL_AS_BLANK);
+    public void setFillColor(final int row, final int column, final Color color) {
+        final Cell cell = getOrCreateRow(row).getCell(column, Row.MissingCellPolicy.CREATE_NULL_AS_BLANK);
 
         final Workbook book = sheet.getWorkbook();
         // try to find cell style if we already created it
         CellStyle style = colorStyleMap.get(color);
 
-        try
-        {
+        try {
             // not found ?
-            if (style == null)
-            {
+            if (style == null) {
                 // create it
                 style = book.createCellStyle();
 
                 // apply color
-                if (book instanceof HSSFWorkbook)
-                {
+                if (book instanceof HSSFWorkbook) {
                     final HSSFPalette palette = ((HSSFWorkbook) book).getCustomPalette();
-                    final short colorIndex = palette.findSimilarColor(color.getRed(), color.getGreen(), color.getBlue())
-                            .getIndex();
+                    final short colorIndex = palette.findSimilarColor(color.getRed(), color.getGreen(), color.getBlue()).getIndex();
                     style.setFillForegroundColor(colorIndex);
                 }
-                else if (book instanceof XSSFWorkbook)
-                {
-                    ((XSSFCellStyle) style).setFillForegroundColor(new XSSFColor(color));
+                else if (book instanceof XSSFWorkbook) {
+                    ((XSSFCellStyle) style).setFillForegroundColor(new XSSFColor(color, new DefaultIndexedColorMap()));
                 }
 
                 style.setFillPattern(FillPatternType.SOLID_FOREGROUND);
@@ -402,8 +357,7 @@ public class IcySpreadSheet
             // set style to cell
             cell.setCellStyle(style);
         }
-        catch (Exception e)
-        {
+        catch (final Exception e) {
             // just ignore any other possible error as
             // java.lang.IllegalStateException: The maximum number of Cell Styles was exceeded.
         }
@@ -413,19 +367,14 @@ public class IcySpreadSheet
      * Sets the formula for the specified cell. The formula follows the standard Excel-compatible
      * syntax with alphanumeric references to other cells (e.g. "=A1*A2"). <br>
      * NOTE: this method is not responsible for checking the formula for potential syntax errors.
-     * 
-     * @param row
-     *        row index
-     * @param column
-     *        column index
-     * @param formula
-     *        the formula
-     * @throws FormulaParseException
-     *         if the formula has errors
+     *
+     * @param row     row index
+     * @param column  column index
+     * @param formula the formula
+     * @throws FormulaParseException if the formula has errors
      */
-    public void setFormula(int row, int column, String formula) throws FormulaParseException
-    {
-        Cell cell = getOrCreateRow(row).getCell(column, Row.MissingCellPolicy.CREATE_NULL_AS_BLANK);
+    public void setFormula(final int row, final int column, String formula) throws FormulaParseException {
+        final Cell cell = getOrCreateRow(row).getCell(column, Row.MissingCellPolicy.CREATE_NULL_AS_BLANK);
 
         if (formula.startsWith("="))
             formula = formula.substring(1);
@@ -445,62 +394,49 @@ public class IcySpreadSheet
      * Other unsupported objects will be replaced by their String representation (via
      * {@link Object#toString()})<br>
      * NOTE: to assign a formula to this cell, use {@link #setFormula(int, int, String)}.
-     * 
-     * @param row
-     *        the index of the row containing the cell (NB: the first row is at index 0)
-     * @param column
-     *        the index of the column containing the cell (NB: the first column is at index 0)
-     * @param value
-     *        the value to assign to the cell. NB: the type of cell will be automatically
-     *        guessed from the provided value, and if no standard format is found (number,
-     *        boolean, text), its String representation will be used
+     *
+     * @param row    the index of the row containing the cell (NB: the first row is at index 0)
+     * @param column the index of the column containing the cell (NB: the first column is at index 0)
+     * @param value  the value to assign to the cell. NB: the type of cell will be automatically
+     *               guessed from the provided value, and if no standard format is found (number,
+     *               boolean, text), its String representation will be used
      */
-    public void setValue(int row, int column, Object value)
-    {
-        if (value == null)
-        {
+    public void setValue(final int row, final int column, Object value) {
+        if (value == null) {
             deleteCell(row, column);
             return;
         }
 
-        Cell cell = getOrCreateRow(row).getCell(column, Row.MissingCellPolicy.CREATE_NULL_AS_BLANK);
+        final Cell cell = getOrCreateRow(row).getCell(column, Row.MissingCellPolicy.CREATE_NULL_AS_BLANK);
 
         // what is the value like?
 
-        if (value instanceof String)
-        {
-            String text = (String) value;
+        if (value instanceof String) {
+            final String text = (String) value;
 
-            try
-            {
+            try {
                 value = Double.parseDouble(text);
             }
-            catch (NumberFormatException numberE)
-            {
+            catch (final NumberFormatException numberE) {
                 // Parse boolean values manually (because Boolean.parseBoolean() never fails)
-                if (text.equalsIgnoreCase("true"))
-                {
+                if (text.equalsIgnoreCase("true")) {
                     value = true;
                 }
-                else if (text.equalsIgnoreCase("false"))
-                {
+                else if (text.equalsIgnoreCase("false")) {
                     value = false;
                 }
             }
         }
 
         // a number?
-        if (Number.class.isAssignableFrom(value.getClass()))
-        {
+        if (Number.class.isAssignableFrom(value.getClass())) {
             cell.setCellValue(((Number) value).doubleValue());
         }
-        else if (value instanceof Boolean)
-        {
+        else if (value instanceof Boolean) {
             cell.setCellValue((Boolean) value);
         }
         // if not, default to a String representation
-        else
-        {
+        else {
             cell.setCellValue(value.toString());
         }
 
@@ -509,48 +445,38 @@ public class IcySpreadSheet
 
     /**
      * Sets an entire column of values from a list of values
-     * 
-     * @param columnIndex
-     *        the index of the target column (Note: the first column is at index 0)
-     * @param columnValues
-     *        an array of values to add, line by line. NB: numbers and string will be recognized
-     *        as such, any other item will be converted to string using
-     *        {@link Object#toString()}, while <code>null</code> values will result in an empty
-     *        cell
+     *
+     * @param columnIndex  the index of the target column (Note: the first column is at index 0)
+     * @param columnValues an array of values to add, line by line. NB: numbers and string will be recognized
+     *                     as such, any other item will be converted to string using
+     *                     {@link Object#toString()}, while <code>null</code> values will result in an empty
+     *                     cell
      */
-    public void setColumn(int columnIndex, Object... columnValues)
-    {
+    public void setColumn(final int columnIndex, final Object... columnValues) {
         setColumn(columnIndex, null, columnValues);
     }
 
     /**
      * Sets an entire column of values from a list of values
-     * 
-     * @param columnHeader
-     *        a header text placed in an extra row before the data (or <code>null</code> if not
-     *        needed)
-     * @param columnIndex
-     *        the index of the target column (Note: the first column is at index 0)
-     * @param columnValues
-     *        an array of values to add, line by line. NB: numbers and string will be recognized
-     *        as such, any other item will be converted to string using
-     *        {@link Object#toString()}, while <code>null</code> values will result in an empty
-     *        cell
+     *
+     * @param columnHeader a header text placed in an extra row before the data (or <code>null</code> if not
+     *                     needed)
+     * @param columnIndex  the index of the target column (Note: the first column is at index 0)
+     * @param columnValues an array of values to add, line by line. NB: numbers and string will be recognized
+     *                     as such, any other item will be converted to string using
+     *                     {@link Object#toString()}, while <code>null</code> values will result in an empty
+     *                     cell
      */
-    public void setColumn(int columnIndex, String columnHeader, Object... columnValues)
-    {
+    public void setColumn(final int columnIndex, final String columnHeader, final Object... columnValues) {
         int rowIndex = 0;
-        if (columnHeader != null)
-        {
-            Row currentRow = getOrCreateRow(rowIndex);
+        if (columnHeader != null) {
+            final Row currentRow = getOrCreateRow(rowIndex);
             currentRow.getCell(columnIndex, Row.MissingCellPolicy.CREATE_NULL_AS_BLANK).setCellValue(columnHeader);
             rowIndex = 1;
         }
 
-        for (Object obj : columnValues)
-        {
-            if (obj == null)
-            {
+        for (final Object obj : columnValues) {
+            if (obj == null) {
                 rowIndex++;
                 continue;
             }
@@ -561,27 +487,17 @@ public class IcySpreadSheet
 
     /**
      * Insert a new empty column at the specified index, shifting all columns to the right
-     * 
-     * @param columnIndex
-     *        the index where the new column is to be inserted (NB: the first column index is 0)
+     *
+     * @param columnIndex the index where the new column is to be inserted (NB: the first column index is 0)
      */
-    public void insertColumn(int columnIndex)
-    {
+    public void insertColumn(final int columnIndex) {
         // As painfully as it might (not) sound, there is no built-in function for this!
-        Iterable<Row> iterable = new Iterable<Row>()
-        {
-            @Override
-            public Iterator<Row> iterator()
-            {
-                return sheet.rowIterator();
-            }
-        };
+        final Iterable<Row> iterable = sheet::rowIterator;
 
-        for (Row row : iterable)
-            for (int i = row.getPhysicalNumberOfCells() - 1; i >= columnIndex; i--)
-            {
-                Cell oldCell = row.getCell(i);
-                Cell newCell = row.createCell(i + 1, oldCell.getCellType());
+        for (final Row row : iterable)
+            for (int i = row.getPhysicalNumberOfCells() - 1; i >= columnIndex; i--) {
+                final Cell oldCell = row.getCell(i);
+                final Cell newCell = row.createCell(i + 1, oldCell.getCellType());
                 Workbooks.copyCell(oldCell, newCell);
             }
     }
@@ -589,33 +505,27 @@ public class IcySpreadSheet
     /**
      * Convenience method that sets an entire row of values at the specified location in a given
      * workbook
-     * 
-     * @param rowIndex
-     *        the index of the row to fill (Note: the first column is at index 0)
-     * @param values
-     *        the values to add, separated by commas, or a single array containing the values to
-     *        add.<br>
-     *        NB: numbers and string will be recognized as such, any other item will be
-     *        converted to string using {@link Object#toString()}, while <code>null</code>
-     *        values will result in an empty cell
+     *
+     * @param rowIndex the index of the row to fill (Note: the first column is at index 0)
+     * @param values   the values to add, separated by commas, or a single array containing the values to
+     *                 add.<br>
+     *                 NB: numbers and string will be recognized as such, any other item will be
+     *                 converted to string using {@link Object#toString()}, while <code>null</code>
+     *                 values will result in an empty cell
      */
-    @SuppressWarnings({"rawtypes", "unchecked"})
-    public void setRow(int rowIndex, Object... values)
-    {
-        Iterable<?> list = null;
+    public void setRow(final int rowIndex, final Object... values) {
+        final Iterable<?> list;
 
         // special case: rowValues could contain a single array
-        if (values.length == 1 && values[0].getClass().isArray())
-        {
-            Object array = values[0];
-            int n = Array.getLength(array);
-            ArrayList arrayList = new ArrayList(n);
+        if (values.length == 1 && values[0].getClass().isArray()) {
+            final Object array = values[0];
+            final int n = Array.getLength(array);
+            final ArrayList<Object> arrayList = new ArrayList<>(n);
             for (int i = 0; i < n; i++)
                 arrayList.add(Array.get(array, i));
             list = arrayList;
         }
-        else
-        {
+        else {
             list = Arrays.asList(values);
         }
 
@@ -624,25 +534,21 @@ public class IcySpreadSheet
 
     /**
      * Sets an entire row of values at the specified (0-based) row index
-     * 
-     * @param header
-     *        a header text placed in the first column, before the data (or <code>null</code> if
-     *        not needed)
-     * @param rowIndex
-     *        the index of the target row (Note: the first row is at index 0)
-     * @param rowValues
-     *        an array of values to add, column by column. NB: numbers and string will be
-     *        recognized as such, any other item will be converted to string using
-     *        {@link Object#toString()}, while <code>null</code> values will result in an empty
-     *        cell
+     *
+     * @param header    a header text placed in the first column, before the data (or <code>null</code> if
+     *                  not needed)
+     * @param rowIndex  the index of the target row (Note: the first row is at index 0)
+     * @param rowValues an array of values to add, column by column. NB: numbers and string will be
+     *                  recognized as such, any other item will be converted to string using
+     *                  {@link Object#toString()}, while <code>null</code> values will result in an empty
+     *                  cell
      */
-    public void setRow(int rowIndex, String header, Iterable<?> rowValues)
-    {
+    public void setRow(final int rowIndex, final String header, final Iterable<?> rowValues) {
         int colIndex = 0;
         if (header != null)
             setValue(rowIndex, colIndex++, header);
 
-        for (Object obj : rowValues)
+        for (final Object obj : rowValues)
             if (obj != null)
                 setValue(rowIndex, colIndex++, obj);
     }
@@ -650,46 +556,39 @@ public class IcySpreadSheet
     /**
      * Removes all rows in this sheet
      */
-    public void removeRows()
-    {
+    public void removeRows() {
         removeRows(0);
     }
 
     /**
      * Removes all rows in this sheet starting at the specified (0-based) row index
-     * 
-     * @param startRowIndex
-     *        the (0-based) index of the first row to remove
+     *
+     * @param startRowIndex the (0-based) index of the first row to remove
      */
-    public void removeRows(int startRowIndex)
-    {
-        for (int i = startRowIndex; i <= sheet.getLastRowNum(); i++)
-        {
-            Row row = sheet.getRow(i);
+    public void removeRows(final int startRowIndex) {
+        for (int i = startRowIndex; i <= sheet.getLastRowNum(); i++) {
+            final Row row = sheet.getRow(i);
             if (row != null)
                 sheet.removeRow(row);
         }
     }
 
     /**
-     * @param columnIndex
-     *        the column to search
+     * @param columnIndex the column to search
      * @return All values in the column corresponding to a number (empty cells and other cell
-     *         formats are discarded)
+     * formats are discarded)
      */
-    public double[] getColumnValues(int columnIndex)
-    {
-        ArrayList<Double> values = new ArrayList<Double>(sheet.getLastRowNum() + 1);
-        for (int i = 0; i <= sheet.getLastRowNum(); i++)
-        {
-            Object val = getValue(i, columnIndex);
+    public double[] getColumnValues(final int columnIndex) {
+        final ArrayList<Double> values = new ArrayList<>(sheet.getLastRowNum() + 1);
+        for (int i = 0; i <= sheet.getLastRowNum(); i++) {
+            final Object val = getValue(i, columnIndex);
             if (val instanceof Number)
                 values.add(((Number) val).doubleValue());
         }
         if (values.isEmpty())
             return null;
 
-        double[] result = new double[values.size()];
+        final double[] result = new double[values.size()];
         for (int i = 0; i < result.length; i++)
             result[i] = values.get(i);
         return result;
diff --git a/src/main/java/plugins/adufour/workbooks/Workbooks.java b/src/main/java/plugins/adufour/workbooks/Workbooks.java
index 1ce22ea74c60efa84f8600215fc042d6df984571..096be83d4df9cf0447e224a49672e0ef97b41f98 100644
--- a/src/main/java/plugins/adufour/workbooks/Workbooks.java
+++ b/src/main/java/plugins/adufour/workbooks/Workbooks.java
@@ -1,26 +1,31 @@
-package plugins.adufour.workbooks;
-
-import java.awt.Color;
-import java.io.File;
-import java.util.ArrayList;
-import java.util.Collection;
-import java.util.List;
+/*
+ * Copyright (c) 2010-2023. Institut Pasteur.
+ *
+ * This file is part of Icy.
+ * Icy is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Icy is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Icy. If not, see <https://www.gnu.org/licenses/>.
+ */
 
-import javax.swing.BoxLayout;
+package plugins.adufour.workbooks;
 
+import icy.plugin.abstract_.PluginActionable;
+import icy.plugin.interface_.PluginThreaded;
+import icy.system.thread.ThreadUtil;
 import org.apache.poi.hssf.usermodel.HSSFWorkbook;
-import org.apache.poi.ss.usermodel.Cell;
-import org.apache.poi.ss.usermodel.CellStyle;
 import org.apache.poi.ss.usermodel.Font;
-import org.apache.poi.ss.usermodel.Row;
-import org.apache.poi.ss.usermodel.Sheet;
-import org.apache.poi.ss.usermodel.Workbook;
+import org.apache.poi.ss.usermodel.*;
 import org.apache.poi.ss.util.WorkbookUtil;
 import org.apache.poi.xssf.usermodel.XSSFWorkbook;
-
-import icy.plugin.abstract_.PluginActionable;
-import icy.plugin.interface_.PluginThreaded;
-import icy.system.thread.ThreadUtil;
 import plugins.adufour.blocks.tools.io.FileToWorkbook;
 import plugins.adufour.blocks.tools.io.WorkbookToFile;
 import plugins.adufour.blocks.tools.io.WorkbookToFile.MergePolicy;
@@ -28,46 +33,51 @@ import plugins.adufour.ezplug.EzDialog;
 import plugins.adufour.vars.gui.swing.WorkbookEditor;
 import plugins.adufour.vars.lang.VarWorkbook;
 
+import javax.swing.*;
+import java.awt.Color;
+import java.io.File;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.List;
+
 /**
  * Main class loaded by Icy to provide workbook manipulation and editing facilities
- * 
+ *
  * @author Alexandre Dufour
  */
-public class Workbooks extends PluginActionable implements PluginThreaded
-{
+public class Workbooks extends PluginActionable implements PluginThreaded {
     /**
      * List of supported workbook formats
-     * 
+     *
      * @author Alexandre Dufour
      */
-    public enum WorkbookFormat
-    {
-        /** Legacy format (compatible with Excel &lt;= 2004). Limited to 256 columns and 65536 rows */
+    public enum WorkbookFormat {
+        /**
+         * Legacy format (compatible with Excel &lt;= 2004). Limited to 256 columns and 65536 rows
+         */
         XLS,
 
-        /** Recommended format (compatible with Excel &gt;= 2007) */
+        /**
+         * Recommended format (compatible with Excel &gt;= 2007)
+         */
         XLSX;
 
-        Workbook createEmptyWorkbook()
-        {
-            switch (this)
-            {
+        Workbook createEmptyWorkbook() {
+            switch (this) {
                 case XLS:
                     return new HSSFWorkbook();
                 case XLSX:
                     return new XSSFWorkbook();
                 default:
-                    throw new UnsupportedOperationException("Unknown format: " + toString());
+                    throw new UnsupportedOperationException("Unknown format: " + this);
             }
         }
 
-        public String getExtension()
-        {
+        public String getExtension() {
             return '.' + name().toLowerCase();
         }
 
-        public static WorkbookFormat getFormat(Workbook workbook)
-        {
+        public static WorkbookFormat getFormat(final Workbook workbook) {
             if (workbook instanceof HSSFWorkbook)
                 return XLS;
             if (workbook instanceof XSSFWorkbook)
@@ -77,35 +87,30 @@ public class Workbooks extends PluginActionable implements PluginThreaded
         }
     }
 
-    private final String defaultTitle = "Icy Workbooks v." + getDescriptor().getVersion().getMajor() + "."
-            + getDescriptor().getVersion().getMinor();
+    private final String defaultTitle = "Icy Workbooks v." + getDescriptor().getVersion().getMajor() + "." + getDescriptor().getVersion().getMinor();
 
     @Override
-    public void run()
-    {
+    public void run() {
         show(createEmptyWorkbook(), defaultTitle, true);
     }
 
     /**
      * @return A new empty workbook using the new XLSX format.
      */
-    public static Workbook createEmptyWorkbook()
-    {
+    public static Workbook createEmptyWorkbook() {
         return createEmptyWorkbook(WorkbookFormat.XLSX);
     }
 
     /**
      * Creates a new (empty) workbook with the specified format
-     * 
-     * @param format
-     *        the format of the workbook to create (see {@link WorkbookFormat})
+     *
+     * @param format the format of the workbook to create (see {@link WorkbookFormat})
      * @return a new (empty) workbook
      * @see WorkbookFormat
      * @see WorkbookFormat#XLS
      */
-    public static Workbook createEmptyWorkbook(WorkbookFormat format)
-    {
-        Workbook workbook = format.createEmptyWorkbook();
+    public static Workbook createEmptyWorkbook(final WorkbookFormat format) {
+        final Workbook workbook = format.createEmptyWorkbook();
         workbook.setMissingCellPolicy(Row.MissingCellPolicy.CREATE_NULL_AS_BLANK);
         return workbook;
     }
@@ -121,13 +126,11 @@ public class Workbooks extends PluginActionable implements PluginThreaded
      * item3 (tab) item4</code><br>
      * (the same convention is followed by
      * {@link WorkbookToFile#saveAsText(Workbook, String, MergePolicy)}
-     * 
-     * @param filePath
-     *        the path of the file to open
+     *
+     * @param filePath the path of the file to open
      * @return the workbook read from input file
      */
-    public static Workbook openWorkbook(String filePath)
-    {
+    public static Workbook openWorkbook(final String filePath) {
         return openWorkbook(new File(filePath));
     }
 
@@ -142,23 +145,19 @@ public class Workbooks extends PluginActionable implements PluginThreaded
      * item3 (tab) item4</code><br>
      * (the same convention is followed by
      * {@link WorkbookToFile#saveAsText(Workbook, String, MergePolicy)}
-     * 
-     * @param file
-     *        the file to open
+     *
+     * @param file the file to open
      * @return the workbook read from input file
      */
-    public static Workbook openWorkbook(File file)
-    {
+    public static Workbook openWorkbook(final File file) {
         return FileToWorkbook.readWorkbook(file);
     }
 
     /**
-     * @param wb
-     *        input {@link Workbook}
+     * @param wb input {@link Workbook}
      * @return The format of this workbook (see the {@link WorkbookFormat} enumeration)
      */
-    public static WorkbookFormat getFormat(Workbook wb)
-    {
+    public static WorkbookFormat getFormat(final Workbook wb) {
         return WorkbookFormat.getFormat(wb);
     }
 
@@ -168,18 +167,15 @@ public class Workbooks extends PluginActionable implements PluginThreaded
      * NB: If the provided sheet name contains invalid characters, they are automatically replaced
      * in order to comply with the workbook format (similarly to the
      * {@link #containsSheet(Workbook, String)} method)
-     * 
-     * @param workbook
-     *        the workbook where the sheet should be fetched (or created)
-     * @param sheetName
-     *        the name of the sheet to fetch or create. Note that the final sheet name may be
-     *        different from the provided name, for instance if the name contains special
-     *        characters
+     *
+     * @param workbook  the workbook where the sheet should be fetched (or created)
+     * @param sheetName the name of the sheet to fetch or create. Note that the final sheet name may be
+     *                  different from the provided name, for instance if the name contains special
+     *                  characters
      * @return the sheet with the specified name, wrapped into a {@link IcySpreadSheet} object for
-     *         simplified manipulation
+     * simplified manipulation
      */
-    public static IcySpreadSheet getSheet(Workbook workbook, String sheetName)
-    {
+    public static IcySpreadSheet getSheet(final Workbook workbook, String sheetName) {
         Sheet sheet = workbook.getSheet(sheetName);
         if (sheet != null)
             return new IcySpreadSheet(sheet);
@@ -191,14 +187,12 @@ public class Workbooks extends PluginActionable implements PluginThreaded
     }
 
     /**
-     * @param workbook
-     *        input {@link Workbook}
+     * @param workbook input {@link Workbook}
      * @return a collection of sheets contained in this workbook
      */
-    public static Collection<IcySpreadSheet> getSheets(Workbook workbook)
-    {
-        int nSheets = workbook.getNumberOfSheets();
-        final List<IcySpreadSheet> sheets = new ArrayList<IcySpreadSheet>(nSheets);
+    public static Collection<IcySpreadSheet> getSheets(final Workbook workbook) {
+        final int nSheets = workbook.getNumberOfSheets();
+        final List<IcySpreadSheet> sheets = new ArrayList<>(nSheets);
         for (int i = 0; i < nSheets; i++)
             sheets.add(new IcySpreadSheet(workbook.getSheetAt(i)));
         return sheets;
@@ -207,31 +201,27 @@ public class Workbooks extends PluginActionable implements PluginThreaded
     /**
      * Copies the type, value and comment of <code>srcCell</code> into <code>dstCell</code>. Note
      * that this is not a perfect clone, as the cell style is not copied
-     * 
-     * @param srcCell
-     *        source cell
-     * @param dstCell
-     *        destination cell
+     *
+     * @param srcCell source cell
+     * @param dstCell destination cell
      */
-    public static void copyCell(Cell srcCell, Cell dstCell)
-    {
+    public static void copyCell(final Cell srcCell, final Cell dstCell) {
         dstCell.setCellComment(srcCell.getCellComment());
-        dstCell.setCellType(srcCell.getCellType());
-        switch (srcCell.getCellType())
-        {
-            case Cell.CELL_TYPE_STRING:
+        //dstCell.setCellType(srcCell.getCellType());
+        switch (srcCell.getCellType()) {
+            case STRING:
                 dstCell.setCellValue(srcCell.getStringCellValue());
                 break;
-            case Cell.CELL_TYPE_NUMERIC:
+            case NUMERIC:
                 dstCell.setCellValue(srcCell.getNumericCellValue());
                 break;
-            case Cell.CELL_TYPE_BOOLEAN:
+            case BOOLEAN:
                 dstCell.setCellValue(srcCell.getBooleanCellValue());
                 break;
-            case Cell.CELL_TYPE_FORMULA:
+            case FORMULA:
                 dstCell.setCellFormula(srcCell.getCellFormula());
                 break;
-            case Cell.CELL_TYPE_ERROR:
+            case ERROR:
                 dstCell.setCellErrorValue(srcCell.getErrorCellValue());
                 break;
             default:
@@ -240,41 +230,35 @@ public class Workbooks extends PluginActionable implements PluginThreaded
 
     /**
      * Copies the {@link CellStyle} of <code>srcStyle</code> into <code>dstStyle</code>.
-     * 
-     * @param srcStyle
-     *        source style
-     * @param dstStyle
-     *        destination style
+     *
+     * @param srcStyle source style
+     * @param dstStyle destination style
      */
-    public static void copyStyle(CellStyle srcStyle, CellStyle dstStyle)
-    {
-        dstStyle.setAlignment(srcStyle.getAlignmentEnum());
-        dstStyle.setBorderBottom(srcStyle.getBorderBottomEnum());
-        dstStyle.setBorderLeft(srcStyle.getBorderLeftEnum());
-        dstStyle.setBorderRight(srcStyle.getBorderRightEnum());
-        dstStyle.setBorderTop(srcStyle.getBorderTopEnum());
+    public static void copyStyle(final CellStyle srcStyle, final CellStyle dstStyle) {
+        dstStyle.setAlignment(srcStyle.getAlignment());
+        dstStyle.setBorderBottom(srcStyle.getBorderBottom());
+        dstStyle.setBorderLeft(srcStyle.getBorderLeft());
+        dstStyle.setBorderRight(srcStyle.getBorderRight());
+        dstStyle.setBorderTop(srcStyle.getBorderTop());
         dstStyle.setFillBackgroundColor(srcStyle.getFillBackgroundColor());
         dstStyle.setFillForegroundColor(srcStyle.getFillForegroundColor());
-        dstStyle.setFillPattern(srcStyle.getFillPatternEnum());
+        dstStyle.setFillPattern(srcStyle.getFillPattern());
         // dstStyle.setDataFormat(this.transform(srcStyle.getDataFormat()));
         // dstStyle.setFont(this.transform(srcStyle.getFont(this.workbookOld)));
         dstStyle.setHidden(srcStyle.getHidden());
         dstStyle.setIndention(srcStyle.getIndention());
         dstStyle.setLocked(srcStyle.getLocked());
-        dstStyle.setVerticalAlignment(srcStyle.getVerticalAlignmentEnum());
+        dstStyle.setVerticalAlignment(srcStyle.getVerticalAlignment());
         dstStyle.setWrapText(srcStyle.getWrapText());
     }
 
     /**
      * Copies the {@link Font} of <code>srcFont</code> into <code>dstFont</code>.
-     * 
-     * @param srcFont
-     *        source font
-     * @param dstFont
-     *        destination font
+     *
+     * @param srcFont source font
+     * @param dstFont destination font
      */
-    public static void copyFont(Font srcFont, Font dstFont)
-    {
+    public static void copyFont(final Font srcFont, final Font dstFont) {
         dstFont.setBold(srcFont.getBold());
         dstFont.setCharSet(srcFont.getCharSet());
         dstFont.setColor(srcFont.getColor());
@@ -291,76 +275,60 @@ public class Workbooks extends PluginActionable implements PluginThreaded
      * NB: If the provided sheet name contains invalid characters, they are automatically replaced
      * in order to comply with the workbook format (similarly to the
      * {@link #getSheet(Workbook, String)} method)
-     * 
-     * @param workbook
-     *        the workbook where the sheet should be searched for
-     * @param sheetName
-     *        the name of the sheet to search for
+     *
+     * @param workbook  the workbook where the sheet should be searched for
+     * @param sheetName the name of the sheet to search for
      * @return <code>true</code> if the sheet exists, <code>false</code> otherwise
      */
-    public static boolean containsSheet(Workbook workbook, String sheetName)
-    {
+    public static boolean containsSheet(final Workbook workbook, String sheetName) {
         sheetName = WorkbookUtil.createSafeSheetName(sheetName);
         return workbook.getSheet(sheetName) != null;
     }
 
     /**
      * Shows the specified workbook on screen in an editor window
-     * 
-     * @param workbook
-     *        the workbook to show
-     * @param windowTitle
-     *        window title
+     *
+     * @param workbook    the workbook to show
+     * @param windowTitle window title
      */
-    public static void show(Workbook workbook, String windowTitle)
-    {
+    public static void show(final Workbook workbook, final String windowTitle) {
         show(workbook, windowTitle, false);
     }
 
     /**
      * Shows the specified workbook on screen in an editor window
-     * 
-     * @param workbook
-     *        the workbook to show
-     * @param windowTitle
-     *        window title
-     * @param editable
-     *        <code>true</code> if the user can edit the workbook, <code>false</code> otherwise
+     *
+     * @param workbook    the workbook to show
+     * @param windowTitle window title
+     * @param editable    <code>true</code> if the user can edit the workbook, <code>false</code> otherwise
      */
-    public static void show(final Workbook workbook, final String windowTitle, final boolean editable)
-    {
+    public static void show(final Workbook workbook, final String windowTitle, final boolean editable) {
         final VarWorkbook wb = new VarWorkbook(windowTitle, workbook);
 
-        ThreadUtil.invokeLater(new Runnable()
-        {
-            @Override
-            public void run()
-            {
-                final EzDialog dialog = new EzDialog(windowTitle);
+        ThreadUtil.invokeLater(() -> {
+            final EzDialog dialog = new EzDialog(windowTitle);
 
-                dialog.setLayout(new BoxLayout(dialog.getContentPane(), BoxLayout.Y_AXIS));
+            dialog.setLayout(new BoxLayout(dialog.getContentPane(), BoxLayout.Y_AXIS));
 
-                WorkbookEditor editor = new WorkbookEditor(wb);
-                editor.setReadOnly(!editable);
-                editor.setEnabled(true);
-                dialog.add(editor.getEditorComponent());
+            final WorkbookEditor editor = new WorkbookEditor(wb);
+            editor.setReadOnly(!editable);
+            editor.setEnabled(true);
+            dialog.add(editor.getEditorComponent());
 
-                dialog.addToDesktopPane();
-                dialog.setVisible(true);
-            }
+            dialog.addToDesktopPane();
+            dialog.setVisible(true);
         });
     }
 
     /**
      * A test to make sure the plug-in works as intended. Also useful as a sample code
      */
-    public static void test()
-    {
+    public static void test() {
         // Create an empty workbook
-        Workbook wb = Workbooks.createEmptyWorkbook();
+        final Workbook wb = Workbooks.createEmptyWorkbook();
 
         // Get a (possibly new) sheet
-        IcySpreadSheet sheet = Workbooks.getSheet(wb, "Test");
+        final IcySpreadSheet sheet = Workbooks.getSheet(wb, "Test");
 
         // Set the header row (all at once, easier to write!)
         sheet.setRow(0, "Col 0", "Col 1", "Some other column"); // etc.