Search in sources :

Example 1 with Workflow

use of qupath.lib.plugins.workflow.Workflow in project qupath by qupath.

the class PathIO method readImageDataSerialized.

@SuppressWarnings("unchecked")
private static <T> ImageData<T> readImageDataSerialized(final InputStream stream, ImageData<T> imageData, ImageServer<T> server, Class<T> cls) throws IOException {
    long startTime = System.currentTimeMillis();
    Locale locale = Locale.getDefault(Category.FORMAT);
    boolean localeChanged = false;
    try (ObjectInputStream inStream = new ObjectInputStream(new BufferedInputStream(stream))) {
        ServerBuilder<T> serverBuilder = null;
        PathObjectHierarchy hierarchy = null;
        ImageData.ImageType imageType = null;
        ColorDeconvolutionStains stains = null;
        Workflow workflow = null;
        Map<String, Object> propertyMap = null;
        String firstLine = inStream.readUTF();
        // int versionNumber = -1;
        if (!firstLine.startsWith("Data file version")) {
            logger.error("Input stream does not contain valid QuPath data!");
        }
        // else {
        // // Could try to parse version number... although frankly, at this time, we don't really care...
        // try {
        // versionNumber = NumberFormat.getInstance(Locale.US).parse(firstLine.substring("Data file version".length()).trim()).intValue();
        // } catch (Exception e) {
        // logger.warn("Unable to parse version number from {}", firstLine);
        // }
        // }
        String serverString = (String) inStream.readObject();
        // Don't log warnings if we are provided with a server
        serverBuilder = extractServerBuilder(serverString, server == null);
        while (true) {
            // logger.debug("Starting read: " + inStream.available());
            try {
                // Try to read a relevant object from the stream
                Object input = inStream.readObject();
                logger.debug("Read: {}", input);
                // If we have a Locale, then set it
                if (input instanceof Locale) {
                    if (input != locale) {
                        Locale.setDefault(Category.FORMAT, (Locale) input);
                        localeChanged = true;
                    }
                } else if (input instanceof PathObjectHierarchy)
                    hierarchy = (PathObjectHierarchy) input;
                else if (input instanceof ImageData.ImageType)
                    imageType = (ImageData.ImageType) input;
                else if (input instanceof String && "EOF".equals(input)) {
                    // else if ("EOF".equals(input)) {
                    break;
                // }
                } else if (input instanceof ColorDeconvolutionStains)
                    stains = (ColorDeconvolutionStains) input;
                else if (input instanceof Workflow)
                    workflow = (Workflow) input;
                else if (input instanceof Map)
                    propertyMap = (Map<String, Object>) input;
                else if (input == null) {
                    logger.debug("Null object will be skipped");
                } else
                    logger.warn("Unsupported object of class {} will be skipped: {}", input.getClass().getName(), input);
            } catch (ClassNotFoundException e) {
                logger.error("Unable to find class: " + e.getLocalizedMessage(), e);
            } catch (EOFException e) {
                // Try to recover from EOFExceptions - we may already have enough info
                logger.error("Reached end of file...");
                if (hierarchy == null)
                    logger.error(e.getLocalizedMessage(), e);
                break;
            }
        }
        // Create an entirely new ImageData if necessary
        var existingBuilder = imageData == null || imageData.getServer() == null ? null : imageData.getServer().getBuilder();
        if (imageData == null || !Objects.equals(serverBuilder, existingBuilder)) {
            // Create a new server if we need to
            if (server == null) {
                try {
                    server = serverBuilder.build();
                } catch (Exception e) {
                    logger.error(e.getLocalizedMessage());
                }
                ;
                if (server == null) {
                    logger.error("Warning: Unable to build server with " + serverBuilder);
                // throw new RuntimeException("Warning: Unable to create server for path " + serverPath);
                }
            }
            // TODO: Make this less clumsy... but for now we need to ensure we have a fully-initialized hierarchy (which deserialization alone doesn't achieve)
            PathObjectHierarchy hierarchy2 = new PathObjectHierarchy();
            hierarchy2.setHierarchy(hierarchy);
            hierarchy = hierarchy2;
            imageData = new ImageData<>(server, hierarchy, imageType);
        } else {
            if (imageType != null)
                imageData.setImageType(imageType);
            // Set the new hierarchy
            if (hierarchy != null)
                imageData.getHierarchy().setHierarchy(hierarchy);
        }
        // Set the other properties we have just read
        if (workflow != null) {
            imageData.getHistoryWorkflow().clear();
            imageData.getHistoryWorkflow().addSteps(workflow.getSteps());
        }
        if (stains != null) {
            imageData.setColorDeconvolutionStains(stains);
        }
        if (propertyMap != null) {
            for (Entry<String, Object> entry : propertyMap.entrySet()) imageData.setProperty(entry.getKey(), entry.getValue());
        }
        long endTime = System.currentTimeMillis();
        // if (hierarchy == null) {
        // logger.error(String.format("%s does not contain a valid QUPath object hierarchy!", file.getAbsolutePath()));
        // return null;
        // }
        logger.debug(String.format("Hierarchy with %d object(s) read in %.2f seconds", hierarchy.nObjects(), (endTime - startTime) / 1000.));
    } catch (ClassNotFoundException e1) {
        logger.warn("Class not found reading image data", e1);
    } finally {
        if (localeChanged)
            Locale.setDefault(Category.FORMAT, locale);
    }
    return imageData;
}
Also used : Locale(java.util.Locale) PathObjectHierarchy(qupath.lib.objects.hierarchy.PathObjectHierarchy) Workflow(qupath.lib.plugins.workflow.Workflow) EOFException(java.io.EOFException) FileNotFoundException(java.io.FileNotFoundException) IOException(java.io.IOException) BufferedInputStream(java.io.BufferedInputStream) ImageData(qupath.lib.images.ImageData) EOFException(java.io.EOFException) PathObject(qupath.lib.objects.PathObject) Map(java.util.Map) HashMap(java.util.HashMap) ObjectInputStream(java.io.ObjectInputStream) ColorDeconvolutionStains(qupath.lib.color.ColorDeconvolutionStains)

Example 2 with Workflow

use of qupath.lib.plugins.workflow.Workflow in project qupath by qupath.

the class WorkflowCommandLogView method changed.

@Override
public void changed(ObservableValue<? extends ImageData<BufferedImage>> source, ImageData<BufferedImage> imageDataOld, ImageData<BufferedImage> imageDataNew) {
    if (imageDataOld == imageDataNew)
        return;
    if (imageDataOld != null)
        imageDataOld.getHistoryWorkflow().removeWorkflowListener(this);
    if (imageDataNew != null) {
        imageDataNew.getHistoryWorkflow().addWorkflowListener(this);
        workflowProperty.set(imageDataNew.getHistoryWorkflow());
        list.getSelectionModel().clearSelection();
        Workflow workflow = imageDataNew.getHistoryWorkflow();
        list.getItems().setAll(workflow.getSteps());
        workflowUpdated(workflow);
    } else {
        workflowProperty.set(null);
        list.getItems().clear();
        workflowUpdated(null);
    }
}
Also used : Workflow(qupath.lib.plugins.workflow.Workflow)

Example 3 with Workflow

use of qupath.lib.plugins.workflow.Workflow in project qupath by qupath.

the class WorkflowCommandLogView method createPane.

protected BorderPane createPane() {
    BorderPane pane = new BorderPane();
    TableColumn<KeyValue<Object>, String> col1 = new TableColumn<>("Parameter");
    col1.setCellValueFactory(c -> c.getValue().keyProperty());
    TableColumn<KeyValue<Object>, Object> col2 = new TableColumn<>("Value");
    col2.setCellValueFactory(c -> c.getValue().valueProperty());
    col2.setCellFactory(t -> new ParameterTableCell<>());
    table.getColumns().add(col1);
    table.getColumns().add(col2);
    table.setColumnResizePolicy(TableView.CONSTRAINED_RESIZE_POLICY);
    SplitPane splitPane = new SplitPane();
    splitPane.setOrientation(Orientation.VERTICAL);
    splitPane.getItems().addAll(list, table);
    // Allow multiple selections for static model
    list.getSelectionModel().setSelectionMode(isStaticWorkflow ? SelectionMode.MULTIPLE : SelectionMode.SINGLE);
    list.getSelectionModel().selectedItemProperty().addListener((e, f, g) -> {
        WorkflowStep step = list.getSelectionModel().getSelectedItem();
        populateList(table.getItems(), step);
    });
    final ContextMenu contextMenu = new ContextMenu();
    MenuItem miCopyCommand = new MenuItem("Copy command" + (isStaticWorkflow ? "s" : ""));
    miCopyCommand.setOnAction(e -> {
        List<Integer> indices = list.getSelectionModel().getSelectedIndices();
        if (indices == null || indices.isEmpty())
            return;
        copyScriptToClipboard(indices);
    });
    miCopyCommand.disableProperty().bind(workflowProperty.isNull());
    contextMenu.getItems().setAll(miCopyCommand);
    if (isStaticWorkflow) {
        MenuItem miRemoveSelected = new MenuItem("Remove selected items");
        miRemoveSelected.setOnAction(e -> {
            var steps = getSelectedIndices();
            if (steps == null || steps.isEmpty())
                return;
            String message = steps.size() == 1 ? "Remove workflow step?" : "Remove " + steps.size() + " workflow steps?";
            if (!Dialogs.showYesNoDialog("Remove workflow steps", message))
                return;
            Collections.sort(steps);
            for (int i = steps.size() - 1; i >= 0; i--) getWorkflow().removeStep(steps.get(i));
        // workflow.removeSteps(steps);
        });
        miRemoveSelected.disableProperty().bind(workflowProperty.isNull());
        MenuItem miMoveUp = new MenuItem("Move up");
        miMoveUp.setOnAction(e -> {
            var indices = getSelectedIndices();
            if (indices == null || indices.isEmpty() || indices.get(0) <= 0)
                return;
            var workflow = getWorkflow();
            List<WorkflowStep> steps = new ArrayList<>(workflow.getSteps());
            WorkflowStep[] stepsRemoved = new WorkflowStep[indices.size()];
            workflow.removeSteps(steps);
            int[] newIndices = new int[indices.size()];
            for (int i = indices.size() - 1; i >= 0; i--) {
                int ind = indices.get(i);
                int indNew = ind - 1;
                newIndices[i] = indNew;
                stepsRemoved[i] = steps.remove(ind);
            }
            for (int i = 0; i < indices.size(); i++) {
                steps.add(newIndices[i], stepsRemoved[i]);
            }
            workflow.addSteps(steps);
            list.getSelectionModel().clearSelection();
            list.getSelectionModel().selectIndices(newIndices[0], newIndices);
        });
        miMoveUp.disableProperty().bind(workflowProperty.isNull());
        MenuItem miMoveDown = new MenuItem("Move down");
        miMoveDown.setOnAction(e -> {
            var indices = getSelectedIndices();
            var workflow = getWorkflow();
            if (indices == null || indices.isEmpty() || indices.get(indices.size() - 1) >= workflow.size() - 1)
                return;
            list.getSelectionModel().clearSelection();
            Collections.sort(indices);
            List<WorkflowStep> steps = new ArrayList<>(workflow.getSteps());
            WorkflowStep[] stepsRemoved = new WorkflowStep[indices.size()];
            workflow.removeSteps(steps);
            int[] newIndices = new int[indices.size()];
            for (int i = indices.size() - 1; i >= 0; i--) {
                int ind = indices.get(i);
                int indNew = ind + 1;
                newIndices[i] = indNew;
                stepsRemoved[i] = steps.remove(ind);
            }
            for (int i = 0; i < indices.size(); i++) {
                steps.add(newIndices[i], stepsRemoved[i]);
            }
            workflow.addSteps(steps);
            list.getSelectionModel().select(newIndices[0]);
            list.getSelectionModel().selectIndices(newIndices[0], newIndices);
        // int ind = list.getSelectionModel().getSelectedIndex();
        // if (ind < 0 || ind >= workflow.size()-1)
        // return;
        // List<WorkflowStep> steps = new ArrayList<>(workflow.getSteps());
        // WorkflowStep step = steps.remove(ind);
        // steps.add(ind+1, step);
        // workflow.removeSteps(steps);
        // workflow.addSteps(steps);
        // list.getSelectionModel().select(step);
        });
        miMoveDown.disableProperty().bind(workflowProperty.isNull());
        contextMenu.getItems().addAll(new SeparatorMenuItem(), miMoveUp, miMoveDown, new SeparatorMenuItem(), miRemoveSelected);
    }
    list.setCellFactory(new Callback<ListView<WorkflowStep>, ListCell<WorkflowStep>>() {

        @Override
        public ListCell<WorkflowStep> call(ListView<WorkflowStep> p) {
            ListCell<WorkflowStep> cell = new ListCell<>() {

                @Override
                protected void updateItem(WorkflowStep value, boolean bln) {
                    super.updateItem(value, bln);
                    if (value instanceof WorkflowStep)
                        setText(value.getName());
                    else if (value == null)
                        setText(null);
                    else
                        setText(value.toString());
                    setContextMenu(contextMenu);
                    setOnMouseClicked(e -> {
                        // Only handle double clicks
                        if (!e.isPopupTrigger() && e.getClickCount() == 2)
                            runWorkflowStepInteractively(qupath, value);
                    });
                    setOnKeyPressed(e -> {
                        if (copyCombination.match(e)) {
                            copyScriptToClipboard(getSelectedIndices());
                            e.consume();
                        }
                    });
                }
            };
            return cell;
        }
    });
    pane.setCenter(splitPane);
    Button btnCreateScript = new Button("Create script");
    btnCreateScript.setMaxWidth(Double.MAX_VALUE);
    btnCreateScript.setOnAction(e -> showScript());
    btnCreateScript.disableProperty().bind(workflowProperty.isNull());
    Button btnCreateWorkflow = null;
    if (!isStaticWorkflow) {
        btnCreateWorkflow = new Button("Create workflow");
        btnCreateWorkflow.setMaxWidth(Double.MAX_VALUE);
        btnCreateWorkflow.setOnAction(e -> {
            var workflow = getWorkflow();
            if (workflow == null)
                return;
            Stage stage = new Stage();
            stage.initOwner(qupath.getStage());
            stage.setTitle("Workflow");
            Workflow workflowNew = new Workflow();
            workflowNew.addSteps(workflow.getSteps());
            stage.setScene(new Scene(new WorkflowCommandLogView(qupath, workflowNew).getPane(), 400, 600));
            stage.show();
        });
        btnCreateWorkflow.disableProperty().bind(workflowProperty.isNull());
        pane.setBottom(PaneTools.createColumnGridControls(btnCreateWorkflow, btnCreateScript));
    } else
        pane.setBottom(btnCreateScript);
    // pane.setBottom(btnGenerateScript);
    return pane;
}
Also used : Button(javafx.scene.control.Button) ListCell(javafx.scene.control.ListCell) LoggerFactory(org.slf4j.LoggerFactory) KeyCombination(javafx.scene.input.KeyCombination) ParameterList(qupath.lib.plugins.parameters.ParameterList) ContextMenu(javafx.scene.control.ContextMenu) Map(java.util.Map) TableView(javafx.scene.control.TableView) QuPathGUI(qupath.lib.gui.QuPathGUI) Pane(javafx.scene.layout.Pane) Orientation(javafx.geometry.Orientation) SplitPane(javafx.scene.control.SplitPane) MenuItem(javafx.scene.control.MenuItem) BufferedImage(java.awt.image.BufferedImage) WorkflowStep(qupath.lib.plugins.workflow.WorkflowStep) Collectors(java.util.stream.Collectors) Objects(java.util.Objects) Platform(javafx.application.Platform) SeparatorMenuItem(javafx.scene.control.SeparatorMenuItem) List(java.util.List) Clipboard(javafx.scene.input.Clipboard) SimplePluginWorkflowStep(qupath.lib.plugins.workflow.SimplePluginWorkflowStep) Entry(java.util.Map.Entry) ObservableList(javafx.collections.ObservableList) ClipboardContent(javafx.scene.input.ClipboardContent) BorderPane(javafx.scene.layout.BorderPane) StringProperty(javafx.beans.property.StringProperty) Scene(javafx.scene.Scene) ListView(javafx.scene.control.ListView) WorkflowListener(qupath.lib.plugins.workflow.WorkflowListener) SimpleStringProperty(javafx.beans.property.SimpleStringProperty) ScriptEditor(qupath.lib.gui.scripting.ScriptEditor) PathPlugin(qupath.lib.plugins.PathPlugin) ArrayList(java.util.ArrayList) TableColumn(javafx.scene.control.TableColumn) Dialogs(qupath.lib.gui.dialogs.Dialogs) TableCell(javafx.scene.control.TableCell) Callback(javafx.util.Callback) Tooltip(javafx.scene.control.Tooltip) ImageData(qupath.lib.images.ImageData) KeyCode(javafx.scene.input.KeyCode) ObjectProperty(javafx.beans.property.ObjectProperty) Logger(org.slf4j.Logger) Workflow(qupath.lib.plugins.workflow.Workflow) KeyCodeCombination(javafx.scene.input.KeyCodeCombination) ScriptableWorkflowStep(qupath.lib.plugins.workflow.ScriptableWorkflowStep) SelectionMode(javafx.scene.control.SelectionMode) Stage(javafx.stage.Stage) SimpleObjectProperty(javafx.beans.property.SimpleObjectProperty) ObservableValue(javafx.beans.value.ObservableValue) ChangeListener(javafx.beans.value.ChangeListener) Collections(java.util.Collections) PaneTools(qupath.lib.gui.tools.PaneTools) BorderPane(javafx.scene.layout.BorderPane) WorkflowStep(qupath.lib.plugins.workflow.WorkflowStep) SimplePluginWorkflowStep(qupath.lib.plugins.workflow.SimplePluginWorkflowStep) ScriptableWorkflowStep(qupath.lib.plugins.workflow.ScriptableWorkflowStep) ListCell(javafx.scene.control.ListCell) ArrayList(java.util.ArrayList) ContextMenu(javafx.scene.control.ContextMenu) SplitPane(javafx.scene.control.SplitPane) ListView(javafx.scene.control.ListView) Button(javafx.scene.control.Button) Stage(javafx.stage.Stage) Workflow(qupath.lib.plugins.workflow.Workflow) MenuItem(javafx.scene.control.MenuItem) SeparatorMenuItem(javafx.scene.control.SeparatorMenuItem) SeparatorMenuItem(javafx.scene.control.SeparatorMenuItem) Scene(javafx.scene.Scene) TableColumn(javafx.scene.control.TableColumn)

Aggregations

Map (java.util.Map)2 Workflow (qupath.lib.plugins.workflow.Workflow)2 BufferedImage (java.awt.image.BufferedImage)1 BufferedInputStream (java.io.BufferedInputStream)1 EOFException (java.io.EOFException)1 FileNotFoundException (java.io.FileNotFoundException)1 IOException (java.io.IOException)1 ObjectInputStream (java.io.ObjectInputStream)1 ArrayList (java.util.ArrayList)1 Collections (java.util.Collections)1 HashMap (java.util.HashMap)1 List (java.util.List)1 Locale (java.util.Locale)1 Entry (java.util.Map.Entry)1 Objects (java.util.Objects)1 Collectors (java.util.stream.Collectors)1 Platform (javafx.application.Platform)1 ObjectProperty (javafx.beans.property.ObjectProperty)1 SimpleObjectProperty (javafx.beans.property.SimpleObjectProperty)1 SimpleStringProperty (javafx.beans.property.SimpleStringProperty)1