From f484943e44d1a66e6f4e88db08d140485df25878 Mon Sep 17 00:00:00 2001 From: Valentin Date: Tue, 16 May 2023 22:53:16 +0200 Subject: [PATCH] delete columns, fix adding columns bug, add export --- build.gradle | 4 + .../ComparisonTableDataExtractor.java | 54 +++++ .../ComparisonTableController.java | 200 ++++++++++++------ .../persistency/Export/ExcelExporter.java | 53 +++++ src/main/resources/bundles/Lang_en.properties | 2 + src/main/resources/bundles/Lang_fr.properties | 2 + .../views/Comparison/ComparisonView.fxml | 15 +- 7 files changed, 259 insertions(+), 71 deletions(-) create mode 100644 src/main/java/components/comparison/ComparisonTableDataExtractor.java create mode 100644 src/main/java/persistency/Export/ExcelExporter.java diff --git a/build.gradle b/build.gradle index 27a1e494..09df8e39 100644 --- a/build.gradle +++ b/build.gradle @@ -26,6 +26,10 @@ dependencies { // Use JUnit test framework testImplementation 'junit:junit:4.12' + + // Apache POI + implementation 'org.apache.poi:poi:5.2.0' + implementation 'org.apache.poi:poi-ooxml:5.2.0' } javafx { diff --git a/src/main/java/components/comparison/ComparisonTableDataExtractor.java b/src/main/java/components/comparison/ComparisonTableDataExtractor.java new file mode 100644 index 00000000..0bbaa23e --- /dev/null +++ b/src/main/java/components/comparison/ComparisonTableDataExtractor.java @@ -0,0 +1,54 @@ +package components.comparison; + +import javafx.scene.Node; +import javafx.scene.control.TableColumn; +import javafx.scene.control.TableView; +import javafx.scene.layout.VBox; + +import java.util.ArrayList; +import java.util.List; + +public class ComparisonTableDataExtractor { + public List>> extractContainerData(VBox container) { + List>> containerData = new ArrayList<>(); + + // Iterate over the TableView instances in the VBox container + for (Node tableView : container.getChildren()) { + //check if the node is a TableView + if (tableView.getClass() == TableView.class) { + List> tableData = extractTableData((TableView) tableView); + containerData.add(tableData); + } + } + + return containerData; + } + + private List> extractTableData(TableView tableView) { + List> tableData = new ArrayList<>(); + + // Extract column headers + List columnHeaders = new ArrayList<>(); + for (TableColumn column : tableView.getColumns()) { + columnHeaders.add(column.getText()); + } + tableData.add(columnHeaders); + + + // Iterate over the rows in the table + for (int row = 0; row < tableView.getItems().size(); row++) { + List rowData = new ArrayList<>(); + + // Iterate over the columns in each row + for (TableColumn column : tableView.getColumns()) { + Object cellValue = column.getCellData(row); + String cellData = cellValue != null ? cellValue.toString() : ""; + rowData.add(cellData); + } + + tableData.add(rowData); + } + + return tableData; + } +} diff --git a/src/main/java/components/comparison/controllers/ComparisonTableController.java b/src/main/java/components/comparison/controllers/ComparisonTableController.java index 4bbdd69f..0b45a39c 100644 --- a/src/main/java/components/comparison/controllers/ComparisonTableController.java +++ b/src/main/java/components/comparison/controllers/ComparisonTableController.java @@ -1,10 +1,7 @@ package components.comparison.controllers; import application.configuration.Configuration; -import components.comparison.ComparisonTable; -import components.comparison.ComparisonView; -import components.comparison.block; -import components.comparison.line; +import components.comparison.*; import javafx.application.Platform; import javafx.beans.property.SimpleStringProperty; import javafx.beans.property.StringProperty; @@ -15,30 +12,36 @@ import javafx.geometry.Orientation; import javafx.scene.Node; import javafx.scene.control.*; +import javafx.scene.input.ContextMenuEvent; import javafx.scene.layout.VBox; +import javafx.stage.FileChooser; import javafx.stage.Stage; import persistency.newSaveSystem.SConcreteCategory; import persistency.newSaveSystem.SMoment; //import javax.swing.event.ChangeListener; +import java.io.File; import java.io.IOException; import java.net.URL; import java.util.*; import java.util.concurrent.atomic.AtomicBoolean; +import persistency.Export.*; +import utils.GlobalVariables; public class ComparisonTableController implements Initializable { @FXML private VBox table; + private ComparisonTable comparisonTable; private ObservableList selectionInterviews; private ArrayList columnsWidth = new ArrayList<>(); + private Stage comparisonStage; public ComparisonTableController(ObservableList selectionInterviews) { this.table = new VBox(); this.selectionInterviews = selectionInterviews; initialize(null, null); - } @Override @@ -46,7 +49,7 @@ public void initialize(URL url, ResourceBundle resourceBundle) { fillTable(this.selectionInterviews); Platform.runLater(this::bindScroll); Platform.runLater(this::setColumnsSizesToBiggest); - Platform.runLater(this::updateColumnsSizes); + //Platform.runLater(this::updateColumnsSizes); } @@ -55,14 +58,13 @@ public void initialize(URL url, ResourceBundle resourceBundle) { //remplit la table avec les données public void fillTable(ObservableList selectionInterviews) { try { - ComparisonTable ct = new ComparisonTable(selectionInterviews); + this.comparisonTable = new ComparisonTable(selectionInterviews); //create table for each interview, we will fill them then - for (block b : ct.getBlocks()){ + for (block b : this.comparisonTable.getBlocks()){ TableView> tv = new TableView<>(); tv.setPrefWidth(1000); tv.setId(b.getTitle()); - addColumn(tv); //allow to add empty columns hideScroll(tv); this.table.getChildren().add(tv); @@ -74,7 +76,9 @@ public void fillTable(ObservableList selectionInterviews) { fillLines(b, tv); //add empty columns at the end if it's shorter than the bigger interview - addEmptyColumns(tv, ct.getMaxTableLength()); + addToBalance(tv, this.comparisonTable.getMaxTableLength()); + setListener(tv); //allow to display the context menu + updateColumnsSizes(); int numRows = tv.getItems().size(); tv.setFixedCellSize(24); @@ -151,88 +155,127 @@ public void fillLines(block b, TableView> tv) { } public void displayTable() throws IOException { - Stage comparisonStage = new Stage(); - comparisonStage.setTitle(Configuration.langBundle.getString("comparison_table")); + this.comparisonStage = new Stage(); + this.comparisonStage.setTitle(Configuration.langBundle.getString("comparison_table")); ComparisonView comparisonView = new ComparisonView(this.selectionInterviews); - comparisonView.start(comparisonStage); + comparisonView.start(this.comparisonStage); } ///////////////////////////// CONTEXT MENU ///////////////////////////// - public void addColumn(TableView> tv) {// Create the pop-up menu - // Set the pop-up menu to show on a right-click event on the table header - tv.setOnContextMenuRequested(event -> { - double x = event.getX(); - int columnIndex = -1; - double width = 0; - for (TableColumn column : tv.getColumns()) { - width += column.getWidth(); - if (width > x) { - columnIndex = tv.getColumns().indexOf(column); - break; - } - } + public void setContextMenu(TableView> tv, int columnIndex, ContextMenuEvent event) { + // Create the pop-up menu + ContextMenu contextMenu = new ContextMenu(); + MenuItem addColumnBeforeItem = new MenuItem("Add Column Before"); + MenuItem addColumnAfterItem = new MenuItem("Add Column After"); + MenuItem deleteColumnItem = new MenuItem("Delete Column"); + contextMenu.getItems().addAll(addColumnBeforeItem, addColumnAfterItem, deleteColumnItem); + + // Set action listeners for the menu items + addColumnBeforeItem.setOnAction(addColumnBeforeEvent -> { + this.addColumn(columnIndex, tv); + }); - if (columnIndex >= 0) { - int finalColumnIndex = columnIndex; - // Create the pop-up menu - ContextMenu contextMenu = new ContextMenu(); - MenuItem addColumnBeforeItem = new MenuItem("Add Column Before"); - MenuItem addColumnAfterItem = new MenuItem("Add Column After"); - contextMenu.getItems().addAll(addColumnBeforeItem, addColumnAfterItem); - - // Set action listeners for the menu items - addColumnBeforeItem.setOnAction(addColumnBeforeEvent -> { - // Handle "Add Column Before" action here - tv.getColumns().add(finalColumnIndex, new TableColumn<>(" ")); - tv.getColumns().get(finalColumnIndex).setSortable(false); - //then add columns at the end of the other tables for balance - for (TableView tableView : getTables()){ - if (tableView != tv){ - tableView.getColumns().add(new TableColumn<>(" ")); - tv.getColumns().get(tv.getColumns().size() - 1).setSortable(false); - } - } - setColumnsSizesToBiggest(); - updateColumnsSizes(); - }); + addColumnAfterItem.setOnAction(addColumnAfterEvent -> { + this.addColumn(columnIndex + 1, tv); + }); - addColumnAfterItem.setOnAction(addColumnAfterEvent -> { - // Handle "Add Column After" action here - tv.getColumns().add(finalColumnIndex + 1, new TableColumn<>(" ")); - tv.getColumns().get(finalColumnIndex).setSortable(false); - //then add columns at the end of the other tables for balance - for (TableView tableView : getTables()){ - if (tableView != tv){ - tableView.getColumns().add(new TableColumn<>(" ")); - tv.getColumns().get(tv.getColumns().size() - 1).setSortable(false); - } - } - setColumnsSizesToBiggest(); - updateColumnsSizes(); + deleteColumnItem.setOnAction(deleteColumnEvent -> { + this.deleteColumn(columnIndex, tv); + }); - }); + contextMenu.show(tv, event.getScreenX(), event.getScreenY()); + } + public void setListener(TableView> tv) {// Create the pop-up menu + // Set the pop-up menu to show on a right-click event on the table header + for (TableColumn column : tv.getColumns()) { + column.setGraphic(new Label(column.getText())); + column.setContextMenu(new ContextMenu()); + column.getGraphic().setOnContextMenuRequested(event -> { + int columnIndex = tv.getColumns().indexOf(column); + setContextMenu(tv, columnIndex, event); + }); + } + } + public void setListener(TableColumn, StringProperty> tc){ + tc.setGraphic(new Label(tc.getText())); + tc.setContextMenu(new ContextMenu()); + tc.getGraphic().setOnContextMenuRequested(event -> { + int columnIndex = tc.getTableView().getColumns().indexOf(tc); + setContextMenu(tc.getTableView(), columnIndex, event); + }); + } - contextMenu.show(tv, event.getScreenX(), event.getScreenY()); + public void addColumn(int idx, TableView> tv){ + // Handle "Add Column After" action here + TableColumn, StringProperty> tc = new TableColumn<>(" "); + tv.getColumns().add(idx, tc); + tv.getColumns().get(idx).setSortable(false); + setListener(tc); + //then add columns at the end of the other tables for balance + for (TableView> tableView : getTables()){ + if (tableView != tv){ + TableColumn, StringProperty> column = new TableColumn<>(" "); + tableView.getColumns().add(column); + tv.getColumns().get(tv.getColumns().size() - 1).setSortable(false); + setListener(column); } - }); + } + setColumnsSizesToBiggest(); + updateColumnsSizes(); + } + + public void deleteColumn(int idx, TableView> tv){ + //delete column on right click + System.out.println(tv.getColumns().get(idx).getText()); + tv.getColumns().remove(idx); + List easy_balance = new ArrayList<>(); + //check if the last column of other tables is empty + for (TableView tableView : getTables()){ + if (tableView != tv){ + if (tableView.getColumns().get(tableView.getColumns().size() - 1).getText().equals(" ")){ + easy_balance.add(false); + System.out.println("false"); + } else { + easy_balance.add(true); + System.out.println("true"); + } + } + } + if (easy_balance.contains(true)){ + tv.getColumns().add(new TableColumn<>(" ")); + } + else { + delToBalance(tv); + } + setColumnsSizesToBiggest(); } - public void addEmptyColumns(TableView> tv, int length){ + + public void addToBalance(TableView> tv, int length){ int actualLength = tv.getColumns().size(); length += 2; //add 2 because we have the interview name and the legend; if (actualLength < length){ for (int i = 0; i < length - actualLength; i++){ - tv.getColumns().add(new TableColumn<>(" ")); + TableColumn, StringProperty> tc = new TableColumn<>(" "); + tv.getColumns().add(tc); + setListener(tc); + } + } + } + public void delToBalance(TableView> tv){ + for (TableView tableView : getTables()){ + if (tableView != tv) { + tableView.getColumns().remove(tableView.getColumns().size() - 1); } } } - public List> getTables(){ - List> tableViews = new ArrayList<>(); + public List>> getTables(){ + List>> tableViews = new ArrayList<>(); for (Node node : this.table.getChildren()) { if (node instanceof TableView) { - tableViews.add((TableView) node); + tableViews.add((TableView>) node); } } return tableViews; @@ -354,5 +397,22 @@ else if(newVal.doubleValue() < oldVal.doubleValue()){ } } + public void exportToExcel(){ + ComparisonTableDataExtractor extractor = new ComparisonTableDataExtractor(); + List>> containerData = extractor.extractContainerData(this.table); + + String path = Configuration.getProjectsPath()[0]; + FileChooser fileChooser = new FileChooser(); + fileChooser.setInitialDirectory(new File(path).getParentFile()); + fileChooser.setInitialFileName(GlobalVariables.getGlobalVariables().getCurrentProjectPath()); + fileChooser.setTitle(Configuration.langBundle.getString("export_to_excel")); + FileChooser.ExtensionFilter extFilter = new FileChooser.ExtensionFilter("XLSX files (*.xlsx)", "*.xlsx"); + fileChooser.getExtensionFilters().add(extFilter); + File saveFile = fileChooser.showSaveDialog(this.comparisonStage); + if(saveFile != null) { + ExcelExporter.exportToExcel(containerData, saveFile.getAbsolutePath()); + } + } + } diff --git a/src/main/java/persistency/Export/ExcelExporter.java b/src/main/java/persistency/Export/ExcelExporter.java new file mode 100644 index 00000000..2e26b585 --- /dev/null +++ b/src/main/java/persistency/Export/ExcelExporter.java @@ -0,0 +1,53 @@ +package persistency.Export; + +import org.apache.poi.ss.usermodel.*; +import org.apache.poi.xssf.usermodel.XSSFWorkbook; + +import java.io.FileOutputStream; +import java.io.IOException; +import java.util.List; + +public class ExcelExporter { + public static void exportToExcel(List>> tableData, String filePath) { + try (Workbook workbook = new XSSFWorkbook()) { + Sheet sheet = workbook.createSheet("Comparison Data"); + + CellStyle headerStyle = createHeaderStyle(workbook); + + int rowNum = 0; + for (List> table : tableData) { + boolean headerRow = true; + for (List rowData : table) { + Row row = sheet.createRow(rowNum++); + int colNum = 0; + for (String cellData : rowData) { + Cell cell = row.createCell(colNum++); + cell.setCellValue(cellData); + if (headerRow) { // Apply style to the header row + cell.setCellStyle(headerStyle); + } + } + headerRow = false; + } + } + + // Write the workbook data to a file + try (FileOutputStream outputStream = new FileOutputStream(filePath)) { + workbook.write(outputStream); + System.out.println("Table data exported to Excel successfully!"); + } + } catch (IOException e) { + e.printStackTrace(); + } + } + + private static CellStyle createHeaderStyle(Workbook workbook) { + CellStyle style = workbook.createCellStyle(); + style.setFillForegroundColor(IndexedColors.GREY_50_PERCENT.getIndex()); + style.setFillPattern(FillPatternType.SOLID_FOREGROUND); + Font font = workbook.createFont(); + font.setColor(IndexedColors.WHITE.getIndex()); + style.setFont(font); + return style; + } +} diff --git a/src/main/resources/bundles/Lang_en.properties b/src/main/resources/bundles/Lang_en.properties index af6a5fa7..77efa939 100644 --- a/src/main/resources/bundles/Lang_en.properties +++ b/src/main/resources/bundles/Lang_en.properties @@ -22,6 +22,8 @@ enter_project_name = Enter the Name of the Project empty_schema_tree_view = Empty Schema error = Error +export = Export +export_to_excel = Export Project To Excel export_to_csv = Export Project To CSV export_success = Export Succeeded! export_failure = Export failed. diff --git a/src/main/resources/bundles/Lang_fr.properties b/src/main/resources/bundles/Lang_fr.properties index ff9ef96c..20616f14 100644 --- a/src/main/resources/bundles/Lang_fr.properties +++ b/src/main/resources/bundles/Lang_fr.properties @@ -20,6 +20,8 @@ edit_interview = Modifier l'interview enter_project_name = Entrez le nom du projet empty_schema_tree_view = Schéma vide error = Erreur +export = Exporter +export_to_excel = Exporter le projet en Excel export_to_csv = Exporter le projet en CSV export_success = Export réussi! export_failure = L'export a echoué. diff --git a/src/main/resources/views/Comparison/ComparisonView.fxml b/src/main/resources/views/Comparison/ComparisonView.fxml index 11d4bed0..2ed59f8f 100644 --- a/src/main/resources/views/Comparison/ComparisonView.fxml +++ b/src/main/resources/views/Comparison/ComparisonView.fxml @@ -1,10 +1,23 @@ + - + + + + + +