Search in sources :

Example 1 with MeasurementExporter

use of qupath.lib.gui.tools.MeasurementExporter in project qupath by qupath.

the class MeasurementExportCommand method createAndShowDialog.

private void createAndShowDialog() {
    project = qupath.getProject();
    if (project == null) {
        Dialogs.showNoProjectError("Export measurements");
        return;
    }
    BorderPane mainPane = new BorderPane();
    BorderPane imageEntryPane = new BorderPane();
    GridPane optionPane = new GridPane();
    optionPane.setHgap(5.0);
    optionPane.setVgap(5.0);
    // TOP PANE (SELECT PROJECT ENTRY FOR EXPORT)
    project = qupath.getProject();
    pathObjectCombo = new ComboBox<>();
    separatorCombo = new ComboBox<>();
    includeCombo = new CheckComboBox<String>();
    String sameImageWarning = "A selected image is open in the viewer!\nData should be saved before exporting.";
    var listSelectionView = ProjectDialogs.createImageChoicePane(qupath, project.getImageList(), previousImages, sameImageWarning);
    // BOTTOM PANE (OPTIONS)
    int row = 0;
    Label pathOutputLabel = new Label("Output file");
    var btnChooseFile = new Button("Choose");
    btnChooseFile.setOnAction(e -> {
        String extSelected = separatorCombo.getSelectionModel().getSelectedItem();
        String ext = extSelected.equals("Tab (.tsv)") ? ".tsv" : ".csv";
        String extDesc = ext.equals(".tsv") ? "TSV (Tab delimited)" : "CSV (Comma delimited)";
        File pathOut = Dialogs.promptToSaveFile("Output file", Projects.getBaseDirectory(project), "measurements" + ext, extDesc, ext);
        if (pathOut != null) {
            if (pathOut.isDirectory())
                pathOut = new File(pathOut.getAbsolutePath() + File.separator + "measurements" + ext);
            outputText.setText(pathOut.getAbsolutePath());
        }
    });
    pathOutputLabel.setLabelFor(outputText);
    PaneTools.addGridRow(optionPane, row++, 0, "Choose output file", pathOutputLabel, outputText, outputText, btnChooseFile, btnChooseFile);
    outputText.setMaxWidth(Double.MAX_VALUE);
    btnChooseFile.setMaxWidth(Double.MAX_VALUE);
    Label pathObjectLabel = new Label("Export type");
    pathObjectLabel.setLabelFor(pathObjectCombo);
    pathObjectCombo.getItems().setAll("Image", "Annotations", "Detections", "Cells", "TMA cores");
    pathObjectCombo.getSelectionModel().selectFirst();
    pathObjectCombo.valueProperty().addListener((v, o, n) -> {
        if (n != null)
            setType(n);
    });
    PaneTools.addGridRow(optionPane, row++, 0, "Choose the export type", pathObjectLabel, pathObjectCombo, pathObjectCombo, pathObjectCombo, pathObjectCombo);
    Label separatorLabel = new Label("Separator");
    separatorLabel.setLabelFor(separatorCombo);
    separatorCombo.getItems().setAll("Tab (.tsv)", "Comma (.csv)", "Semicolon (.csv)");
    separatorCombo.getSelectionModel().selectFirst();
    PaneTools.addGridRow(optionPane, row++, 0, "Choose a value separator", separatorLabel, separatorCombo, separatorCombo, separatorCombo, separatorCombo);
    Label includeLabel = new Label("Columns to include (Optional)");
    includeLabel.setLabelFor(includeCombo);
    GuiTools.installSelectAllOrNoneMenu(includeCombo);
    Button btnPopulateColumns = new Button("Populate\t");
    ProgressIndicator progressIndicator = new ProgressIndicator();
    progressIndicator.setPrefSize(20, 20);
    progressIndicator.setMinSize(20, 20);
    progressIndicator.setOpacity(0);
    Button btnResetColumns = new Button("Reset");
    PaneTools.addGridRow(optionPane, row++, 0, "Choose the specific column(s) to include (default: all)", includeLabel, includeCombo, btnPopulateColumns, progressIndicator, btnResetColumns);
    btnPopulateColumns.setOnAction(e -> {
        includeCombo.setDisable(true);
        Set<String> allColumnsForCombo = Collections.synchronizedSet(new LinkedHashSet<>());
        setType(pathObjectCombo.getSelectionModel().getSelectedItem());
        for (int i = 0; i < ProjectDialogs.getTargetItems(listSelectionView).size(); i++) {
            ProjectImageEntry<BufferedImage> entry = ProjectDialogs.getTargetItems(listSelectionView).get(i);
            int updatedEntries = i;
            executor.submit(() -> {
                try {
                    progressIndicator.setOpacity(100);
                    ImageData<?> imageData = entry.readImageData();
                    ObservableMeasurementTableData model = new ObservableMeasurementTableData();
                    model.setImageData(imageData, imageData == null ? Collections.emptyList() : imageData.getHierarchy().getObjects(null, type));
                    allColumnsForCombo.addAll(model.getAllNames());
                    imageData.getServer().close();
                    if (updatedEntries == ProjectDialogs.getTargetItems(listSelectionView).size() - 1) {
                        Platform.runLater(() -> {
                            allColumnsForCombo.removeIf(n -> n == null);
                            includeCombo.getItems().setAll(allColumnsForCombo);
                            includeCombo.getCheckModel().clearChecks();
                            includeCombo.setDisable(false);
                        });
                        progressIndicator.setOpacity(0);
                    }
                } catch (Exception ex) {
                    logger.warn("Error loading columns for entry " + entry.getImageName() + ": " + ex.getLocalizedMessage());
                }
            });
        }
        btnResetColumns.fire();
    });
    btnPopulateColumns.disableProperty().addListener((v, o, n) -> {
        if (n != null && n == true)
            includeCombo.setDisable(true);
    });
    var targetItemBinding = Bindings.size(listSelectionView.getTargetItems()).isEqualTo(0);
    btnPopulateColumns.disableProperty().bind(targetItemBinding);
    btnResetColumns.disableProperty().bind(targetItemBinding);
    btnResetColumns.setOnAction(e -> includeCombo.getCheckModel().clearChecks());
    // Add listener to separatorCombo
    separatorCombo.getSelectionModel().selectedItemProperty().addListener((v, o, n) -> {
        if (outputText == null || n == null)
            return;
        String currentOut = outputText.getText();
        if (n.equals("Tab (.tsv)") && currentOut.endsWith(".csv"))
            outputText.setText(currentOut.replace(".csv", ".tsv"));
        else if ((n.equals("Comma (.csv)") || n.equals("Semicolon (.csv)")) && currentOut.endsWith(".tsv"))
            outputText.setText(currentOut.replace(".tsv", ".csv"));
    });
    PaneTools.getContentsOfType(optionPane, Label.class, false).forEach(e -> e.setMinWidth(160));
    PaneTools.setToExpandGridPaneWidth(outputText, pathObjectCombo, separatorCombo, includeCombo);
    btnPopulateColumns.setMinWidth(100);
    btnResetColumns.setMinWidth(75);
    dialog = Dialogs.builder().title("Export measurements").buttons(btnExport, ButtonType.CANCEL).content(mainPane).build();
    dialog.getDialogPane().setPrefSize(600, 400);
    imageEntryPane.setCenter(listSelectionView);
    // Set the disabledProperty according to (1) targetItems.size() > 0 and (2) outputText.isEmpty()
    var emptyOutputTextBinding = outputText.textProperty().isEqualTo("");
    dialog.getDialogPane().lookupButton(btnExport).disableProperty().bind(Bindings.or(emptyOutputTextBinding, targetItemBinding));
    mainPane.setTop(imageEntryPane);
    mainPane.setBottom(optionPane);
    Optional<ButtonType> result = dialog.showAndWait();
    if (!result.isPresent() || result.get() != btnExport || result.get() == ButtonType.CANCEL)
        return;
    String curExt = Files.getFileExtension(outputText.getText());
    if (curExt.equals("") || (!curExt.equals("csv") && !curExt.equals("tsv"))) {
        curExt = curExt.length() > 1 ? "." + curExt : curExt;
        String extSelected = separatorCombo.getSelectionModel().getSelectedItem();
        String ext = extSelected.equals("Tab (.tsv)") ? ".tsv" : ".csv";
        outputText.setText(outputText.getText().substring(0, outputText.getText().length() - curExt.length()) + ext);
    }
    if (new File(outputText.getText()).getParent() == null) {
        String ext = Files.getFileExtension(outputText.getText()).equals("tsv") ? ".tsv" : ".csv";
        String extDesc = ext.equals(".tsv") ? "TSV (Tab delimited)" : "CSV (Comma delimited)";
        File pathOut = Dialogs.promptToSaveFile("Output file", Projects.getBaseDirectory(project), outputText.getText(), extDesc, ext);
        if (pathOut == null)
            return;
        else
            outputText.setText(pathOut.getAbsolutePath());
    }
    var checkedItems = includeCombo.getCheckModel().getCheckedItems();
    String[] include = checkedItems.stream().collect(Collectors.toList()).toArray(new String[checkedItems.size()]);
    String separator = defSep;
    switch(separatorCombo.getSelectionModel().getSelectedItem()) {
        case "Tab (.tsv)":
            separator = "\t";
            break;
        case "Comma (.csv)":
            separator = ",";
            break;
        case "Semicolon (.csv)":
            separator = ";";
            break;
    }
    ;
    MeasurementExporter exporter;
    exporter = new MeasurementExporter().imageList(ProjectDialogs.getTargetItems(listSelectionView)).separator(separator).includeOnlyColumns(include).exportType(type);
    ExportTask worker = new ExportTask(exporter, outputText.getText());
    ProgressDialog progress = new ProgressDialog(worker);
    progress.setWidth(600);
    progress.initOwner(qupath.getStage());
    progress.setTitle("Export measurements...");
    progress.getDialogPane().setHeaderText("Export measurements");
    progress.getDialogPane().setGraphic(null);
    progress.getDialogPane().getButtonTypes().add(ButtonType.CANCEL);
    progress.getDialogPane().lookupButton(ButtonType.CANCEL).addEventFilter(ActionEvent.ACTION, e -> {
        if (Dialogs.showYesNoDialog("Cancel export", "Are you sure you want to stop the export after the current image?")) {
            worker.quietCancel();
            progress.setHeaderText("Cancelling...");
            // worker.cancel(false);
            progress.getDialogPane().lookupButton(ButtonType.CANCEL).setDisable(true);
        }
        e.consume();
    });
    // Create & run task
    runningTask.set(qupath.createSingleThreadExecutor(this).submit(worker));
    progress.show();
}
Also used : BorderPane(javafx.scene.layout.BorderPane) GridPane(javafx.scene.layout.GridPane) Label(javafx.scene.control.Label) ProgressDialog(org.controlsfx.dialog.ProgressDialog) BufferedImage(java.awt.image.BufferedImage) FileNotFoundException(java.io.FileNotFoundException) ObservableMeasurementTableData(qupath.lib.gui.measure.ObservableMeasurementTableData) Button(javafx.scene.control.Button) ProgressIndicator(javafx.scene.control.ProgressIndicator) MeasurementExporter(qupath.lib.gui.tools.MeasurementExporter) File(java.io.File) ButtonType(javafx.scene.control.ButtonType)

Aggregations

BufferedImage (java.awt.image.BufferedImage)1 File (java.io.File)1 FileNotFoundException (java.io.FileNotFoundException)1 Button (javafx.scene.control.Button)1 ButtonType (javafx.scene.control.ButtonType)1 Label (javafx.scene.control.Label)1 ProgressIndicator (javafx.scene.control.ProgressIndicator)1 BorderPane (javafx.scene.layout.BorderPane)1 GridPane (javafx.scene.layout.GridPane)1 ProgressDialog (org.controlsfx.dialog.ProgressDialog)1 ObservableMeasurementTableData (qupath.lib.gui.measure.ObservableMeasurementTableData)1 MeasurementExporter (qupath.lib.gui.tools.MeasurementExporter)1