use of qupath.lib.plugins.workflow.DefaultScriptableWorkflowStep in project qupath by qupath.
the class DragDropImportListener method handleFileDropImpl.
private void handleFileDropImpl(final QuPathViewer viewer, final List<File> list) throws IOException {
// Shouldn't occur... but keeps FindBugs happy to check
if (list == null) {
logger.warn("No files given!");
return;
}
// Check if we have only jar files
int nJars = 0;
for (File file : list) {
if (file.getName().toLowerCase().endsWith(".jar"))
nJars++;
}
if (nJars == list.size()) {
if (qupath.canInstallExtensions())
qupath.installExtensions(list);
else
Dialogs.showErrorMessage("Install extensions", "Sorry, extensions can only be installed when QuPath is run as a standalone application.");
return;
}
// Try to get a hierarchy for importing ROIs
ImageData<BufferedImage> imageData = viewer == null ? null : viewer.getImageData();
PathObjectHierarchy hierarchy = imageData == null ? null : imageData.getHierarchy();
// Some consumers can only handle one file
boolean singleFile = list.size() == 1;
// Gather together the extensions - if this has length one, we know all the files have the same extension
Set<String> allExtensions = list.stream().map(f -> GeneralTools.getExtension(f).orElse("")).collect(Collectors.toSet());
// If we have a zipped file, create a set that includes the files within the zip image
// This helps us determine whether or not a zip file contains an image or objects, for example
Set<String> allUnzippedExtensions = allExtensions;
if (allExtensions.contains(".zip")) {
allUnzippedExtensions = list.stream().flatMap(f -> {
try {
return PathIO.unzippedExtensions(f.toPath()).stream();
} catch (IOException e) {
logger.debug(e.getLocalizedMessage(), e);
return Arrays.stream(new String[0]);
}
}).collect(Collectors.toSet());
}
// Extract the first (and possibly only) file
File file = list.get(0);
String fileName = file.getName().toLowerCase();
// Check if this is a hierarchy file
if (singleFile && (fileName.endsWith(PathPrefs.getSerializationExtension()))) {
// If we have a different path, open as a new image
if (viewer == null) {
Dialogs.showErrorMessage("Load data", "Please drag the file onto a specific viewer to open!");
return;
}
try {
// Check if we should be importing objects or opening the file
if (imageData != null) {
var dialog = new Dialog<ButtonType>();
var btOpen = new ButtonType("Open image");
var btImport = new ButtonType("Import objects");
dialog.getDialogPane().getButtonTypes().setAll(btOpen, btImport, ButtonType.CANCEL);
dialog.setTitle("Open data");
dialog.setHeaderText("What do you want to do with the data file?");
dialog.setContentText("You can\n" + " 1. Open the image in the current viewer\n" + " 2. Import objects and add them to the current image");
// dialog.setHeaderText("What do you want to do?");
var choice = dialog.showAndWait().orElse(ButtonType.CANCEL);
if (choice == ButtonType.CANCEL)
return;
if (choice == btImport) {
var pathObjects = PathIO.readObjects(file);
hierarchy.addPathObjects(pathObjects);
return;
}
}
qupath.openSavedData(viewer, file, false, true);
} catch (Exception e) {
Dialogs.showErrorMessage("Load data", e);
}
return;
}
// Check if this is a directory - if so, look for a single project file
if (singleFile && file.isDirectory()) {
// Identify all files in the directory, and also all potential project files
File[] filesInDirectory = file.listFiles(f -> !f.isHidden());
List<File> projectFiles = Arrays.stream(filesInDirectory).filter(f -> f.isFile() && f.getAbsolutePath().toLowerCase().endsWith(ProjectIO.getProjectExtension())).collect(Collectors.toList());
if (projectFiles.size() == 1) {
file = projectFiles.get(0);
logger.warn("Selecting project file {}", file);
} else if (projectFiles.size() > 1) {
// Prompt to select which project file to open
logger.debug("Multiple project files found in directory {}", file);
String[] fileNames = projectFiles.stream().map(f -> f.getName()).toArray(n -> new String[n]);
String selectedName = Dialogs.showChoiceDialog("Select project", "Select project to open", fileNames, fileNames[0]);
if (selectedName == null)
return;
file = new File(file, selectedName);
} else if (filesInDirectory.length == 0) {
// If we have an empty directory, offer to set it as a project
if (Dialogs.showYesNoDialog("Create project", "Create project for empty directory?")) {
Project<BufferedImage> project = Projects.createProject(file, BufferedImage.class);
qupath.setProject(project);
if (!project.isEmpty())
project.syncChanges();
return;
} else
// Can't do anything else with an empty folder
return;
}
}
// Check if this is a project
if (singleFile && (fileName.endsWith(ProjectIO.getProjectExtension()))) {
try {
Project<BufferedImage> project = ProjectIO.loadProject(file, BufferedImage.class);
qupath.setProject(project);
} catch (Exception e) {
// Dialogs.showErrorMessage("Project error", e);
logger.error("Could not open as project file: {}, opening in the Script Editor instead", e);
qupath.getScriptEditor().showScript(file);
}
return;
}
// Check if it is an object file in GeoJSON format (.geojson)
if (PathIO.getObjectFileExtensions(false).containsAll(allUnzippedExtensions)) {
if (imageData == null || hierarchy == null) {
qupath.getScriptEditor().showScript(file);
logger.info("Opening the dragged file in the Script Editor as there is no currently opened image in the viewer");
// Dialogs.showErrorMessage("Open object file", "Please open an image first to import objects!");
return;
}
List<PathObject> pathObjects = new ArrayList<>();
List<WorkflowStep> steps = new ArrayList<>();
for (var tempFile : list) {
try {
var tempObjects = PathIO.readObjects(tempFile);
if (tempObjects.isEmpty()) {
logger.warn("No objects found in {}, opening the dragged file in the Script Editor instead", tempFile.getAbsolutePath());
qupath.getScriptEditor().showScript(file);
return;
}
pathObjects.addAll(tempObjects);
// Add step to workflow
Map<String, String> map = new HashMap<>();
map.put("path", file.getPath());
String method = "Import objects";
String methodString = String.format("%s(%s%s%s)", "importObjectsFromFile", "\"", GeneralTools.escapeFilePath(tempFile.getPath()), "\"");
steps.add(new DefaultScriptableWorkflowStep(method, map, methodString));
} catch (IOException | IllegalArgumentException e) {
Dialogs.showErrorNotification("Object import", e.getLocalizedMessage());
return;
}
}
// Ask confirmation to user
int nObjects = pathObjects.size();
String message = nObjects == 1 ? "Add object to the hierarchy?" : String.format("Add %d objects to the hierarchy?", nObjects);
var confirm = Dialogs.showConfirmDialog("Add to hierarchy", message);
if (!confirm)
return;
// Add objects to hierarchy
hierarchy.addPathObjects(pathObjects);
imageData.getHistoryWorkflow().addSteps(steps);
return;
}
// Check if this is TMA dearraying data file
if (singleFile && (fileName.endsWith(TMADataIO.TMA_DEARRAYING_DATA_EXTENSION))) {
if (hierarchy == null)
Dialogs.showErrorMessage("TMA grid import", "Please open an image first before importing a dearrayed TMA grid!");
else {
TMAGrid tmaGrid = TMADataIO.importDearrayedTMAData(file);
if (tmaGrid != null) {
if (hierarchy.isEmpty() || Dialogs.showYesNoDialog("TMA grid import", "Set TMA grid for existing hierarchy?"))
hierarchy.setTMAGrid(tmaGrid);
} else
Dialogs.showErrorMessage("TMA grid import", "Could not parse TMA grid from " + file.getName());
}
return;
}
// Open file with an extension supported by the Script Editor
ScriptEditor scriptEditor = qupath.getScriptEditor();
if (scriptEditor instanceof DefaultScriptEditor && ((DefaultScriptEditor) scriptEditor).supportsFile(file)) {
scriptEditor.showScript(file);
return;
}
// Check handlers
for (DropHandler<File> handler : dropHandlers) {
if (handler.handleDrop(viewer, list))
return;
}
// Assume we have images
if (singleFile && file.isFile()) {
// Try to open as an image, if the extension is known
if (viewer == null) {
Dialogs.showErrorMessage("Open image", "Please drag the file only a specific viewer to open!");
return;
}
qupath.openImage(viewer, file.getAbsolutePath(), true, true);
return;
} else if (qupath.getProject() != null) {
// Try importing multiple images to a project
String[] potentialFiles = list.stream().filter(f -> f.isFile()).map(f -> f.getAbsolutePath()).toArray(String[]::new);
if (potentialFiles.length > 0) {
ProjectCommands.promptToImportImages(qupath, potentialFiles);
return;
}
}
if (qupath.getProject() == null) {
if (list.size() > 1) {
Dialogs.showErrorMessage("Drag & drop", "Could not handle multiple file drop - if you want to handle multiple images, you need to create a project first");
return;
}
}
if (list.size() > 1)
Dialogs.showErrorMessage("Drag & drop", "Sorry, I couldn't figure out what to do with these files - try opening one at a time");
else
Dialogs.showErrorMessage("Drag & drop", "Sorry, I couldn't figure out what to do with " + list.get(0).getName());
}
Aggregations