+ * Built from the QuPath extension template - an extension to control a microscope through a Python interface
*/
class QP_scope implements QuPathExtension {
@@ -53,9 +48,15 @@ class QP_scope implements QuPathExtension {
}
private void addMenuItem(QuPathGUI qupath) {
+ def logger = LoggerFactory.getLogger(QuPathGUI.class)
+ //Check for dependencies and QuPath version
+ logger.info("QuPath Version")
+ logger.info(getQuPathVersion().toString())
+ //TODO how to check if version is supported?
+
def menu = qupath.getMenu("Extensions>${name}", true)
def fileNameStitching = new MenuItem("Start qp_scope")
- // TODO tooltip "Coordinates are expected to be in the format ImageName[xCoordinateInMicrons, yCoordinateInMicrons].tif"
+ // TODO tooltip
fileNameStitching.setOnAction(e -> {
//TODO check preferences for all necessary entries
diff --git a/src/main/groovy/qupath/ext/qp_scope/functions/QP_scope_GUI.groovy b/src/main/groovy/qupath/ext/qp_scope/functions/QP_scope_GUI.groovy
index 20555af..4d0b39a 100644
--- a/src/main/groovy/qupath/ext/qp_scope/functions/QP_scope_GUI.groovy
+++ b/src/main/groovy/qupath/ext/qp_scope/functions/QP_scope_GUI.groovy
@@ -10,11 +10,14 @@ import javafx.stage.Modality
import qupath.ext.qp_scope.utilities.utilityFunctions
import qupath.lib.gui.dialogs.Dialogs
import groovy.io.FileType
-import java.awt.image.BufferedImage
-import qupath.lib.images.servers.ImageServerProvider
+import qupath.lib.projects.Project
+import qupath.lib.gui.QuPathGUI
+import qupath.lib.scripting.QP
+import qupath.lib.gui.scripting.QPEx
+import qupath.ext.basicstitching.BasicStitchingExtension
-class QP_scope_GUI {
+public class QP_scope_GUI {
// Existing text fields
static TextField x1Field = new TextField("");
@@ -35,7 +38,7 @@ class QP_scope_GUI {
def dlg = new Dialog();
dlg.initModality(Modality.APPLICATION_MODAL);
dlg.setTitle("qp_scope");
- dlg.setHeaderText("Enter details:");
+ dlg.setHeaderText("Enter details (LOOK MA! " + BasicStitchingExtension.class.getName() + "!):");
// Set the content
dlg.getDialogPane().setContent(createContent());
@@ -75,14 +78,28 @@ class QP_scope_GUI {
if ([sampleLabel, x1, y1, x2, y2, virtualEnvPath, pythonScriptPath].any { it == null || it.isEmpty() }) {
Dialogs.showWarningNotification("Warning!", "Incomplete data entered.");
} else {
- Object project = utilityFunctions.createProjectFolder(projectsFolderPath,sampleLabel, preferences.firstScanType)
+ Project currentQuPathProject= utilityFunctions.createProjectFolder(projectsFolderPath, sampleLabel, preferences.firstScanType)
+
utilityFunctions.runPythonCommand(virtualEnvPath, pythonScriptPath, projectsFolderPath, sampleLabel, x1, y1, x2, y2);
//TODO figure out how to call stitching function in other plugin
+
utilityFunctions.showAlertDialog("Wait and complete stitching in other version of QuPath")
- String stitchedImagePathStr = projectsFolderPath + File.separator + sampleLabel + File.separator + "SlideImages" + File.separator + preferences.firstScanType + sampleLabel;
+ String stitchedImagePathStr = projectsFolderPath + File.separator + sampleLabel + File.separator + "SlideImages" + File.separator + preferences.firstScanType + sampleLabel + ".ome.tif";
File stitchedImagePath = new File(stitchedImagePathStr);
- utilityFunctions.addImageToProject(stitchedImagePath, project)
+ utilityFunctions.addImageToProject(stitchedImagePath, currentQuPathProject)
+
+ //open the newly created project
+ //https://qupath.github.io/javadoc/docs/qupath/lib/gui/QuPathGUI.html#setProject(qupath.lib.projects.Project)
+ def qupathGUI = QPEx.getQuPath()
+
+ qupathGUI.setProject(currentQuPathProject)
+ //Find the existing images - there should only be one since the project was just created
+ def firstImage = currentQuPathProject.getImageList()[0]
+
+ //Open the first image
+ //https://qupath.github.io/javadoc/docs/qupath/lib/gui/QuPathGUI.html#openImageEntry(qupath.lib.projects.ProjectImageEntry)
+ qupathGUI.openImageEntry(firstImage)
//}
}
@@ -118,5 +135,4 @@ class QP_scope_GUI {
pane.add(control, 1, rowIndex);
}
-
}
diff --git a/src/main/groovy/qupath/ext/qp_scope/utilities/utilityFunctions.groovy b/src/main/groovy/qupath/ext/qp_scope/utilities/utilityFunctions.groovy
index ae1fc99..43b7c38 100644
--- a/src/main/groovy/qupath/ext/qp_scope/utilities/utilityFunctions.groovy
+++ b/src/main/groovy/qupath/ext/qp_scope/utilities/utilityFunctions.groovy
@@ -2,8 +2,9 @@ package qupath.ext.qp_scope.utilities
import org.slf4j.LoggerFactory
import qupath.lib.gui.QuPathGUI
+import qupath.lib.gui.dialogs.Dialogs
import qupath.lib.images.servers.ImageServerProvider
-
+import qupath.lib.projects.ProjectIO
import java.awt.image.BufferedImage
import qupath.lib.projects.Projects;
import java.io.File
@@ -30,20 +31,26 @@ class utilityFunctions {
}
static boolean addImageToProject(File stitchedImagePath, Project project){
+ def logger = LoggerFactory.getLogger(QuPathGUI.class)
- def imagePath = stitchedImagePath.getCanonicalPath()
+ def imagePath = stitchedImagePath.toURI().toString()
+ //logger.info(imagePath)
- def support = ImageServerProvider.getPreferredUriImageSupport(BufferedImage.class, imagePath, "")
- println(support)
+ def support = ImageServerProvider.getPreferredUriImageSupport(BufferedImage.class, imagePath)
+ //logger.info(support as String)
def builder = support.builders.get(0)
// Make sure we don't have null
if (builder == null) {
- print "Image not supported: " + imagePath
+ logger.warn("Image not supported: " + imagePath)
return false
}
// Add the image as entry to the project
- print "Adding: " + imagePath
+ logger.info("Adding: " + imagePath)
+ if (project == null) {
+ logger.warn("Project is null, there must have been a problem creating the project")
+ return false
+ }
Object entry = project.addImage(builder)
// Set a particular image type
@@ -63,6 +70,8 @@ class utilityFunctions {
}
static Project createProjectFolder(String projectsFolderPath, String sampleLabel, String scanType) {
+ //TODO check if a project is open! It probably should not be?
+
// Ensure that the projectsFolderPath exists, if it does not, create it.
File projectsFolder = new File(projectsFolderPath)
if (!projectsFolder.exists()) {
@@ -76,15 +85,28 @@ class utilityFunctions {
}
// Check for a .qpproj file in the sampleLabel folder
- File[] qpprojFiles = sampleLabelFolder.listFiles({ File f -> f.name.endsWith('.qpproj') } as FilenameFilter)
- //Create a QuPath project in the sampleLabelFolder, within the projects folder
+ File[] qpprojFiles = sampleLabelFolder.listFiles({ dir, name -> name.endsWith('.qpproj') } as FilenameFilter)
+ //Create a QuPath project in the sampleLabelFolder, within the projects folder, provided there are no existing .qpproj files
Project project = null
if (qpprojFiles == null || qpprojFiles.length == 0) {
project = Projects.createProject(sampleLabelFolder, BufferedImage.class)
+ }else{
+ //WARNING: This assumes there will be only one file ending in .qpproj
+ // this should USUALLY be a safe assumption
+ if (qpprojFiles.length > 1){
+ Dialogs.showWarningNotification("Warning!", "Multiple Project files found, may cause unexpected behavior!")
+ }
+
+ project = ProjectIO.loadProject(qpprojFiles[0], BufferedImage.class)
}
+ if (project == null) {
+ Dialogs.showWarningNotification("Warning!", "Project is null!")
+ }
// Within projectsFolderPath, check for a folder with the name "SlideImages", if it does not exist, create it
- File slideImagesFolder = new File(projectsFolder, sampleLabelFolder, "SlideImages")
+ String slideImagesFolderPathStr = projectsFolderPath + File.separator + sampleLabel + File.separator + "SlideImages" ;
+ File slideImagesFolder = new File(slideImagesFolderPathStr);
+
if (!slideImagesFolder.exists()) {
slideImagesFolder.mkdirs()
}
@@ -94,6 +116,7 @@ class utilityFunctions {
if (!scanTypeFolder.exists()) {
scanTypeFolder.mkdirs()
}
+
return project
}
@@ -143,6 +166,7 @@ class utilityFunctions {
//TODO add code to access Preferences fields
//If preferences are null or missing, throw an error and close
//Open to discussion whether scan types should be included here or typed every time, or some other option
- return [installation: "C:\\ImageAnalysis\\python", environment: "C:\\Anaconda\\envs\\paquo", projects: "C:\\ImageAnalysis\\slides", firstScanType: "4x_bf_", secondScanType:"20x_bf"]
+ //TODO fix the installation to be a folder with an expected .py file target? Or keep as .py file target?
+ return [installation: "C:\\ImageAnalysis\\python\\py_dummydoc.py", environment: "C:\\Anaconda\\envs\\paquo", projects: "C:\\ImageAnalysis\\slides", firstScanType: "4x_bf_", secondScanType:"20x_bf"]
}
}
\ No newline at end of file