qpdata files corresponding to OMERO (and other) images cannot be opened directly
## Bug report

**Describe the bug**
.qpdata files corresponding to OMERO images cannot be opened directly, but rather *only* via a project.

**To Reproduce**
Steps to reproduce the behavior:
1. Open an image hosted via OMERO (e.g. through IDR) *without* using a QuPath project
2. Draw an annotation and save a .qpdata file
3. Restart QuPath (or open another image) and then try opening the .qpdata file... this gives a NPE

**Expected behavior**
Images can be reloaded from .qpdata files, without necessarily occurring inside projects.

**Desktop (please complete the following information):**
 - QuPath v0.2.2 and earlier

**Additional context**
This happens because
1. .qpdata files store only the basic file path / URI (since that's what they did in v0.1.2), and *not* the full information needed to build the server
2. the path alone isn't parsed [here](https://github.com/qupath/qupath/blob/master/qupath-extension-omero/src/main/java/qupath/lib/images/servers/omero/OmeroWebImageServerBuilder.java#L264)

I think the 'best' solution is to store the JSON representation of the `ServerBuilder` inside the `.qpdata` file. Although this is redundant when inside a project, it is needed elsewhere. However, backwards compatibility should be maintained so that older .qpdata files can be read.

For the same reasons, other more complex servers cannot be reconstructed from `.qpdata` files alone, e.g. rotated servers. This makes it *essential* to use a project in many cases.

An alternative (short-term) approach *to resolve the OMERO problem only* would be to update the `getURIs(URI, String...)` method to parse the path. That would work around issues in v0.2 for OMERO, but doesn't resolve the bigger problem.
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 030f24ec..f04bc681 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -7,8 +7,10 @@ List of bugs fixed:
 * Maximum memory setting is sometimes ignored (https://github.com/qupath/qupath/issues/582)
   * Note that memory can no longer be specified to be less than 1 GB
 * 'Locked status cannot be set' exception when adding pixel classifier measurements to full image (https://github.com/qupath/qupath/issues/595)
+* 'Too many open files' exceptions caused by streams not being closed (https://github.com/qupath/qupath/issues/594)
 * LabeledImageServer ignores updated pixel sizes (https://github.com/qupath/qupath/issues/591)
-* Improve reliability of cell expansion code, currently used with StarDist (https://github.com/qupath/qupath/issues/587)
+* Support adding an individual .qpdata file to an existing project (https://github.com/qupath/qupath/issues/592)
+* Improve reliability of cell expansion code, currently used only with StarDist (https://github.com/qupath/qupath/issues/587)
 
 
 ## Version 0.2.2
diff --git a/qupath-core/src/main/java/qupath/lib/projects/DefaultProject.java b/qupath-core/src/main/java/qupath/lib/projects/DefaultProject.java
index b411cb6f..445d9944 100644
--- a/qupath-core/src/main/java/qupath/lib/projects/DefaultProject.java
+++ b/qupath-core/src/main/java/qupath/lib/projects/DefaultProject.java
@@ -43,6 +43,7 @@ import java.util.List;
 import java.util.Map;
 import java.util.UUID;
 import java.util.Map.Entry;
+import java.util.Objects;
 import java.util.concurrent.atomic.AtomicLong;
 import java.util.stream.Collectors;
 
@@ -764,6 +765,15 @@ class DefaultProject implements Project<BufferedImage> {
 			if (Files.exists(pathData))
 				Files.move(pathData, pathBackup, StandardCopyOption.REPLACE_EXISTING);
 			
+			// Set the entry property, if needed
+			// This handles cases where an ImageData is being moved to become part of this project, 
+			// so that it can be recognized later in calls to Project.getEntry(entry)
+			String id = getFullProjectEntryID();
+			if (!Objects.equals(id, imageData.getProperty(IMAGE_ID))) {
+				logger.warn("Updating ID property to {}", id);
+				imageData.setProperty(IMAGE_ID, id);
+			}
+			
 			// Write to a temp file first
 			long timestamp = 0L;
 			try (var stream = Files.newOutputStream(pathData)) {
diff --git a/qupath-gui-fx/src/main/java/qupath/lib/gui/panes/ProjectBrowser.java b/qupath-gui-fx/src/main/java/qupath/lib/gui/panes/ProjectBrowser.java
index a0aca04e..8caee1fa 100644
--- a/qupath-gui-fx/src/main/java/qupath/lib/gui/panes/ProjectBrowser.java
+++ b/qupath-gui-fx/src/main/java/qupath/lib/gui/panes/ProjectBrowser.java
@@ -734,9 +734,21 @@ public class ProjectBrowser implements ChangeListener<ImageData<BufferedImage>>
 
 		var entry = ProjectCommands.addSingleImageToProject(project, imageData.getServer(), null);
 		if (entry != null) {
+			boolean expanded = tree.getRoot() != null && tree.getRoot().isExpanded();
 			tree.setRoot(model.getRootFX());
 			setSelectedEntry(tree, tree.getRoot(), project.getEntry(imageData));
 			syncProject(project);
+			if (expanded)
+				tree.getRoot().setExpanded(true);
+			// Copy the ImageData to the current entry
+			if (!entry.hasImageData()) {
+				try {
+					logger.info("Copying ImageData to {}", entry);
+					entry.saveImageData(imageData);
+				} catch (IOException e) {
+					logger.error("Unable to save ImageData: " + e.getLocalizedMessage(), e);
+				}
+			}
 		}
 	}
 
['qupath-gui-fx/src/main/java/qupath/lib/gui/panes/ProjectBrowser.java', 'qupath-core/src/main/java/qupath/lib/projects/DefaultProject.java', 'CHANGELOG.md']