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;
}
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);
}
}
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;
}
Aggregations