diff --git a/.github/.codecov.yml b/.github/.codecov.yml new file mode 100644 index 0000000..8391acb --- /dev/null +++ b/.github/.codecov.yml @@ -0,0 +1,9 @@ +coverage: + status: + project: + default: + target: 80% + patch: + default: + target: auto + threshold: 5% \ No newline at end of file diff --git a/build.gradle b/build.gradle index e954760..dfd70e9 100644 --- a/build.gradle +++ b/build.gradle @@ -45,6 +45,9 @@ dependencies { exclude group: 'org.hamcrest' } + // https://mvnrepository.com/artifact/nl.jqno.equalsverifier/equalsverifier + testImplementation 'nl.jqno.equalsverifier:equalsverifier:3.10.1' + // Hamcrest https://mvnrepository.com/artifact/org.hamcrest/hamcrest testImplementation 'org.hamcrest:hamcrest:2.2' diff --git a/src/main/java/com/github/mfl28/boundingboxeditor/controller/Controller.java b/src/main/java/com/github/mfl28/boundingboxeditor/controller/Controller.java index 7ad0c14..f9995a3 100644 --- a/src/main/java/com/github/mfl28/boundingboxeditor/controller/Controller.java +++ b/src/main/java/com/github/mfl28/boundingboxeditor/controller/Controller.java @@ -68,7 +68,6 @@ import java.nio.file.Paths; import java.util.*; import java.util.prefs.Preferences; -import java.util.stream.Collectors; import java.util.stream.Stream; /** @@ -533,7 +532,7 @@ public void onRegisterPreviousImageFileRequested() { } /** - * Handles the event of the user committing a object category name edit. Names of categories are allowed + * Handles the event of the user committing an object category name edit. Names of categories are allowed * to be changed by the user as long as the uniqueness of category-names is not violated, otherwise an error dialog * will be displayed and the edit will be reverted. * @@ -1260,7 +1259,7 @@ private List getImageFilesFromDirectory(File directory) throws IOException return imageFiles.map(file -> new File(file.toString())) .filter(File::isFile) .sorted(Comparator.comparing(File::getName)) - .collect(Collectors.toList()); + .toList(); } } diff --git a/src/main/java/com/github/mfl28/boundingboxeditor/model/Model.java b/src/main/java/com/github/mfl28/boundingboxeditor/model/Model.java index 691768f..f516a0a 100644 --- a/src/main/java/com/github/mfl28/boundingboxeditor/model/Model.java +++ b/src/main/java/com/github/mfl28/boundingboxeditor/model/Model.java @@ -315,10 +315,10 @@ public void updateFromImageAnnotationData(ImageAnnotationData imageAnnotationDat IOResult.OperationType operationType) { final Map updatedCategoryNameToBoundingShapeCountMap = createMergedCategoryToBoundingShapeCountMap( - imageAnnotationData.getCategoryNameToBoundingShapeCountMap()); - updateObjectCategoriesFromData(imageAnnotationData.getCategoryNameToCategoryMap()); + imageAnnotationData.categoryNameToBoundingShapeCountMap()); + updateObjectCategoriesFromData(imageAnnotationData.categoryNameToCategoryMap()); categoryToAssignedBoundingShapesCount.putAll(updatedCategoryNameToBoundingShapeCountMap); - updateImageAnnotations(imageAnnotationData.getImageAnnotations(), operationType); + updateImageAnnotations(imageAnnotationData.imageAnnotations(), operationType); } /** @@ -443,7 +443,7 @@ public boolean containsCategories() { } /** - * Returns the the currently set image-files as an unmodifiable list. + * Returns the currently set image-files as an unmodifiable list. * * @return the image-file list */ diff --git a/src/main/java/com/github/mfl28/boundingboxeditor/model/data/BoundingBoxData.java b/src/main/java/com/github/mfl28/boundingboxeditor/model/data/BoundingBoxData.java index bc0ce29..6e2bee8 100644 --- a/src/main/java/com/github/mfl28/boundingboxeditor/model/data/BoundingBoxData.java +++ b/src/main/java/com/github/mfl28/boundingboxeditor/model/data/BoundingBoxData.java @@ -36,7 +36,7 @@ * * @see BoundingShapeData#setParts(List) */ -public class BoundingBoxData extends BoundingShapeData { +public final class BoundingBoxData extends BoundingShapeData { @SerializedName("bndbox") private final Bounds relativeBoundsInImage; @@ -149,18 +149,21 @@ public boolean equals(Object o) { if(this == o) { return true; } - if(!(o instanceof BoundingBoxData)) { + if(!(o instanceof BoundingBoxData that)) { return false; } if(!super.equals(o)) { return false; } - BoundingBoxData that = (BoundingBoxData) o; if(relativeBoundsInImage == that.relativeBoundsInImage) { return true; } + if(relativeBoundsInImage == null || that.relativeBoundsInImage == null) { + return false; + } + return MathUtils.doubleAlmostEqual(relativeBoundsInImage.getMinX(), that.relativeBoundsInImage.getMinX()) && MathUtils.doubleAlmostEqual(relativeBoundsInImage.getMinY(), that.relativeBoundsInImage.getMinY()) && MathUtils.doubleAlmostEqual(relativeBoundsInImage.getMaxX(), that.relativeBoundsInImage.getMaxX()) && diff --git a/src/main/java/com/github/mfl28/boundingboxeditor/model/data/BoundingPolygonData.java b/src/main/java/com/github/mfl28/boundingboxeditor/model/data/BoundingPolygonData.java index ec42d03..a30a224 100644 --- a/src/main/java/com/github/mfl28/boundingboxeditor/model/data/BoundingPolygonData.java +++ b/src/main/java/com/github/mfl28/boundingboxeditor/model/data/BoundingPolygonData.java @@ -35,7 +35,7 @@ * * @see BoundingShapeData#setParts(List) */ -public class BoundingPolygonData extends BoundingShapeData { +public final class BoundingPolygonData extends BoundingShapeData { @SerializedName("polygon") private final List relativePointsInImage; @@ -97,7 +97,7 @@ public boolean equals(Object o) { return true; } - if(!(o instanceof BoundingPolygonData)) { + if(!(o instanceof BoundingPolygonData that)) { return false; } @@ -105,12 +105,14 @@ public boolean equals(Object o) { return false; } - BoundingPolygonData that = (BoundingPolygonData) o; - if(relativePointsInImage == that.relativePointsInImage) { return true; } + if((relativePointsInImage == null) || (that.relativePointsInImage == null)) { + return false; + } + if(relativePointsInImage.size() != that.relativePointsInImage.size()) { return false; } diff --git a/src/main/java/com/github/mfl28/boundingboxeditor/model/data/BoundingShapeData.java b/src/main/java/com/github/mfl28/boundingboxeditor/model/data/BoundingShapeData.java index 0e35c3a..b72a3a9 100644 --- a/src/main/java/com/github/mfl28/boundingboxeditor/model/data/BoundingShapeData.java +++ b/src/main/java/com/github/mfl28/boundingboxeditor/model/data/BoundingShapeData.java @@ -97,12 +97,10 @@ public boolean equals(Object o) { return true; } - if(!(o instanceof BoundingShapeData)) { + if(!(o instanceof BoundingShapeData that)) { return false; } - BoundingShapeData that = (BoundingShapeData) o; - return Objects.equals(category, that.category) && Objects.equals(tags, that.tags) && Objects.equals(parts, that.parts); diff --git a/src/main/java/com/github/mfl28/boundingboxeditor/model/data/ImageAnnotationData.java b/src/main/java/com/github/mfl28/boundingboxeditor/model/data/ImageAnnotationData.java index cd3d0f4..ce88c2f 100644 --- a/src/main/java/com/github/mfl28/boundingboxeditor/model/data/ImageAnnotationData.java +++ b/src/main/java/com/github/mfl28/boundingboxeditor/model/data/ImageAnnotationData.java @@ -25,54 +25,11 @@ /** * Holds {@link ImageAnnotation}s and shape count data. */ -public class ImageAnnotationData { - private final Collection imageAnnotations; - private final Map categoryNameToBoundingShapeCountMap; - private final Map categoryNameToCategoryMap; - - /** - * Creates a new image annotation data object. - * - * @param imageAnnotations the collection of {@link ImageAnnotation}s - * @param categoryNameToBoundingShapeCountMap a map that maps category names to the number of assigned shapes - * @param categoryNameToCategoryMap a map that maps category names to {@link ObjectCategory} objects - */ - public ImageAnnotationData(Collection imageAnnotations, - Map categoryNameToBoundingShapeCountMap, - Map categoryNameToCategoryMap) { - this.imageAnnotations = imageAnnotations; - this.categoryNameToBoundingShapeCountMap = categoryNameToBoundingShapeCountMap; - this.categoryNameToCategoryMap = categoryNameToCategoryMap; - } +public record ImageAnnotationData(Collection imageAnnotations, + Map categoryNameToBoundingShapeCountMap, + Map categoryNameToCategoryMap) { public static ImageAnnotationData empty() { return new ImageAnnotationData(Collections.emptyList(), Collections.emptyMap(), Collections.emptyMap()); } - - /** - * Returns the image annotations. - * - * @return the image annotations - */ - public Collection getImageAnnotations() { - return imageAnnotations; - } - - /** - * Returns the category to assigned shapes count map. - * - * @return the map - */ - public Map getCategoryNameToBoundingShapeCountMap() { - return categoryNameToBoundingShapeCountMap; - } - - /** - * Returns the category-name to category object map. - * - * @return the map - */ - public Map getCategoryNameToCategoryMap() { - return categoryNameToCategoryMap; - } } diff --git a/src/main/java/com/github/mfl28/boundingboxeditor/model/data/ImageMetaData.java b/src/main/java/com/github/mfl28/boundingboxeditor/model/data/ImageMetaData.java index b9c84ca..d296b16 100644 --- a/src/main/java/com/github/mfl28/boundingboxeditor/model/data/ImageMetaData.java +++ b/src/main/java/com/github/mfl28/boundingboxeditor/model/data/ImageMetaData.java @@ -32,7 +32,7 @@ /** * Holds metadata information about an image. */ -public class ImageMetaData { +public final class ImageMetaData { private static final List supportedImageFormats = List.of("jpeg", "bmp", "png"); private static final String NOT_AN_IMAGE_FILE_ERROR_MESSAGE = "Not an image file."; private static final String UNSUPPORTED_IMAGE_FORMAT_ERROR_MESSAGE = "Unsupported image file format."; @@ -67,7 +67,7 @@ public ImageMetaData(String fileName) { public static ImageMetaData fromFile(File imageFile) throws IOException { ImageDimensions imageDimensions = readImageDimensionsFromFile(imageFile); return new ImageMetaData(imageFile.getName(), imageFile.toPath().getParent().toFile().getName(), - imageDimensions.getWidth(), imageDimensions.getHeight(), imageDimensions.getDepth()); + imageDimensions.width(), imageDimensions.height(), imageDimensions.depth()); } /** @@ -126,8 +126,7 @@ public int hashCode() { @Override public boolean equals(Object obj) { - if(obj instanceof ImageMetaData) { - ImageMetaData other = (ImageMetaData) obj; + if(obj instanceof ImageMetaData other) { return Objects.equals(fileName, other.fileName) && Objects.equals(details, other.details); } return false; @@ -178,44 +177,30 @@ private static ImageDimensions readImageDimensionsFromFile(File imageFile) throw return new ImageDimensions(width, height, numComponents); } - private static class ImageMetaDataDetails { - private final String folderName; - @SerializedName("width") - private final double imageWidth; - @SerializedName("height") - private final double imageHeight; - @SerializedName("depth") - private final int imageDepth; - - ImageMetaDataDetails(String folderName, double imageWidth, double imageHeight, int imageDepth) { - this.folderName = folderName; - this.imageWidth = imageWidth; - this.imageHeight = imageHeight; - this.imageDepth = imageDepth; - } + private record ImageMetaDataDetails(String folderName, @SerializedName("width") double imageWidth, + @SerializedName("height") double imageHeight, + @SerializedName("depth") int imageDepth) { @Override - public int hashCode() { - return Objects.hash(imageWidth, imageHeight, imageDepth); - } - - @Override - public boolean equals(Object o) { - if(this == o) { - return true; + public int hashCode() { + return Objects.hash(imageWidth, imageHeight, imageDepth); } - if(!(o instanceof ImageMetaDataDetails)) { - return false; - } + @Override + public boolean equals(Object o) { + if(this == o) { + return true; + } - ImageMetaDataDetails that = (ImageMetaDataDetails) o; + if(!(o instanceof ImageMetaDataDetails that)) { + return false; + } - return Double.compare(that.imageWidth, imageWidth) == 0 && - Double.compare(that.imageHeight, imageHeight) == 0 && - imageDepth == that.imageDepth; + return Double.compare(that.imageWidth, imageWidth) == 0 && + Double.compare(that.imageHeight, imageHeight) == 0 && + imageDepth == that.imageDepth; + } } - } public static class NotAnImageFileException extends RuntimeException { private static final long serialVersionUID = 5256590447321177896L; @@ -233,27 +218,6 @@ public UnsupportedImageFileException(String errorMessage) { } } - private static class ImageDimensions { - private final double width; - private final double height; - private final int depth; - - ImageDimensions(double width, double height, int depth) { - this.width = width; - this.height = height; - this.depth = depth; - } - - double getWidth() { - return width; - } - - double getHeight() { - return height; - } - - int getDepth() { - return depth; - } + private record ImageDimensions(double width, double height, int depth) { } } diff --git a/src/main/java/com/github/mfl28/boundingboxeditor/model/data/ObjectCategory.java b/src/main/java/com/github/mfl28/boundingboxeditor/model/data/ObjectCategory.java index f798519..577c6a3 100644 --- a/src/main/java/com/github/mfl28/boundingboxeditor/model/data/ObjectCategory.java +++ b/src/main/java/com/github/mfl28/boundingboxeditor/model/data/ObjectCategory.java @@ -75,12 +75,11 @@ public boolean equals(Object other) { return true; } - if(!(other instanceof ObjectCategory)) { + if(!(other instanceof ObjectCategory otherCategory)) { return false; } - final ObjectCategory otherCategory = (ObjectCategory) other; - return otherCategory.getName().equals(this.getName()) && otherCategory.getColor().equals(this.getColor()); + return Objects.equals(otherCategory.getName(), this.getName()) && Objects.equals(otherCategory.getColor(), this.getColor()); } @Override diff --git a/src/main/java/com/github/mfl28/boundingboxeditor/model/io/BoundingBoxPredictor.java b/src/main/java/com/github/mfl28/boundingboxeditor/model/io/BoundingBoxPredictor.java index 3875e5b..ee5dee8 100644 --- a/src/main/java/com/github/mfl28/boundingboxeditor/model/io/BoundingBoxPredictor.java +++ b/src/main/java/com/github/mfl28/boundingboxeditor/model/io/BoundingBoxPredictor.java @@ -35,11 +35,10 @@ import java.util.HashMap; import java.util.List; import java.util.Map; -import java.util.stream.Collectors; public class BoundingBoxPredictor { private static final String DEFAULT_IMAGE_STREAM_FORMAT_NAME = "png"; - private static final String NON_EXISTANT_IMAGE_ERROR_MESSAGE = "Image file does not exist."; + private static final String NON_EXISTENT_IMAGE_ERROR_MESSAGE = "Image file does not exist."; private final BoundingBoxPredictorClient client; private final BoundingBoxPredictorConfig predictorConfig; private double predictedImageWidth; @@ -63,7 +62,7 @@ public BoundingBoxPredictionResult predict(File imageFile, ImageMetaData imageMe imageMetaData.getImageHeight())) { boundingBoxPredictions = client.predict(inputStream); } catch(FileNotFoundException e) { - errorInfoEntries.add(new IOErrorInfoEntry(imageFile.getName(), NON_EXISTANT_IMAGE_ERROR_MESSAGE)); + errorInfoEntries.add(new IOErrorInfoEntry(imageFile.getName(), NON_EXISTENT_IMAGE_ERROR_MESSAGE)); return new BoundingBoxPredictionResult( 0, errorInfoEntries, @@ -85,13 +84,12 @@ public BoundingBoxPredictionResult predict(File imageFile, ImageMetaData imageMe imageAnnotation.getBoundingShapeData() .addAll(boundingBoxPredictions.stream() - .filter(prediction -> - Double.compare(prediction.getScore(), - predictorConfig - .getMinimumScore()) >= - 0) - .map(predictionExtractor::extract) - .collect(Collectors.toList())); + .filter(prediction -> + Double.compare(prediction.score(), + predictorConfig + .getMinimumScore()) >= + 0) + .map(predictionExtractor::extract).toList()); return new BoundingBoxPredictionResult(1, errorInfoEntries, new ImageAnnotationData(List.of(imageAnnotation), categoryToCount, @@ -148,7 +146,7 @@ public PredictionExtractor( public BoundingBoxData extract(BoundingBoxPredictionEntry prediction) { final Map.Entry> boundingBoxCoordinatesEntry = - prediction.getCategoryToBoundingBoxes().entrySet().iterator().next(); + prediction.categoryToBoundingBoxes().entrySet().iterator().next(); final String predictedCategory = boundingBoxCoordinatesEntry.getKey(); diff --git a/src/main/java/com/github/mfl28/boundingboxeditor/model/io/BoundingBoxPredictorConfig.java b/src/main/java/com/github/mfl28/boundingboxeditor/model/io/BoundingBoxPredictorConfig.java index 9c819c0..78ce8d9 100644 --- a/src/main/java/com/github/mfl28/boundingboxeditor/model/io/BoundingBoxPredictorConfig.java +++ b/src/main/java/com/github/mfl28/boundingboxeditor/model/io/BoundingBoxPredictorConfig.java @@ -37,10 +37,6 @@ public void setMinimumScore(double minimumScore) { this.minimumScore.set(minimumScore); } - public DoubleProperty minimumScoreProperty() { - return minimumScore; - } - public boolean isInferenceEnabled() { return inferenceEnabled.get(); } @@ -61,10 +57,6 @@ public void setImageResizeWidth(int imageResizeWidth) { this.imageResizeWidth.set(imageResizeWidth); } - public IntegerProperty imageResizeWidthProperty() { - return imageResizeWidth; - } - public int getImageResizeHeight() { return imageResizeHeight.get(); } @@ -73,10 +65,6 @@ public void setImageResizeHeight(int imageResizeHeight) { this.imageResizeHeight.set(imageResizeHeight); } - public IntegerProperty imageResizeHeightProperty() { - return imageResizeHeight; - } - public boolean getImageResizeKeepRatio() { return imageResizeKeepRatio.get(); } @@ -85,10 +73,6 @@ public void setImageResizeKeepRatio(boolean imageResizeKeepRatio) { this.imageResizeKeepRatio.set(imageResizeKeepRatio); } - public BooleanProperty imageResizeKeepRatioProperty() { - return imageResizeKeepRatio; - } - public boolean isResizeImages() { return resizeImages.get(); } @@ -97,10 +81,6 @@ public void setResizeImages(boolean resizeImages) { this.resizeImages.set(resizeImages); } - public BooleanProperty resizeImagesProperty() { - return resizeImages; - } - public boolean isMergeCategories() { return mergeCategories.get(); } @@ -108,8 +88,4 @@ public boolean isMergeCategories() { public void setMergeCategories(boolean mergeCategories) { this.mergeCategories.set(mergeCategories); } - - public BooleanProperty mergeCategoriesProperty() { - return mergeCategories; - } } diff --git a/src/main/java/com/github/mfl28/boundingboxeditor/model/io/ImageAnnotationLoadStrategy.java b/src/main/java/com/github/mfl28/boundingboxeditor/model/io/ImageAnnotationLoadStrategy.java index 030c036..bc89ce3 100644 --- a/src/main/java/com/github/mfl28/boundingboxeditor/model/io/ImageAnnotationLoadStrategy.java +++ b/src/main/java/com/github/mfl28/boundingboxeditor/model/io/ImageAnnotationLoadStrategy.java @@ -52,7 +52,7 @@ static ImageAnnotationLoadStrategy createStrategy(Type type) { } /** - * Loads image-annotation files from the provided directory path into the + * Loads image-annotation files from the provided directory path into * the program. * * @param path the path of the directory containing the image-annotation files diff --git a/src/main/java/com/github/mfl28/boundingboxeditor/model/io/JSONLoadStrategy.java b/src/main/java/com/github/mfl28/boundingboxeditor/model/io/JSONLoadStrategy.java index 2665b9d..70bb305 100644 --- a/src/main/java/com/github/mfl28/boundingboxeditor/model/io/JSONLoadStrategy.java +++ b/src/main/java/com/github/mfl28/boundingboxeditor/model/io/JSONLoadStrategy.java @@ -38,7 +38,6 @@ import java.util.*; import java.util.concurrent.atomic.AtomicInteger; import java.util.concurrent.atomic.AtomicReference; -import java.util.stream.Collectors; import java.util.stream.StreamSupport; public class JSONLoadStrategy implements ImageAnnotationLoadStrategy { @@ -234,458 +233,382 @@ private static Optional parseObjectCategory(JsonDeserializationC ObjectCategory.class)); } - private static class BoundingShapeDataDeserializer implements JsonDeserializer { - private final List errorInfoEntries; - private final AtomicReference currentFileName; - private final String annotationFileName; - - public BoundingShapeDataDeserializer(List errorInfoEntries, - AtomicReference currentFileName, - String annotationFileName) { - this.errorInfoEntries = errorInfoEntries; - this.currentFileName = currentFileName; - this.annotationFileName = annotationFileName; - } + private record BoundingShapeDataDeserializer(List errorInfoEntries, + AtomicReference currentFileName, + String annotationFileName) implements JsonDeserializer { @Override - public BoundingShapeData deserialize(JsonElement json, java.lang.reflect.Type type, - JsonDeserializationContext context) { - final JsonObject jsonObject = json.getAsJsonObject(); - - BoundingShapeData boundingShapeData = null; - - if(jsonObject.has(BOUNDING_BOX_SERIALIZED_NAME)) { - boundingShapeData = context.deserialize(json, BoundingBoxData.class); - } else if(jsonObject.has(BOUNDING_POLYGON_SERIALIZED_NAME)) { - boundingShapeData = context.deserialize(json, BoundingPolygonData.class); - } else { - errorInfoEntries.add(new IOErrorInfoEntry(annotationFileName, - MISSING_BOUNDING_SHAPE_ERROR_MESSAGE + - currentFileName - .get() + ".")); - } + public BoundingShapeData deserialize(JsonElement json, java.lang.reflect.Type type, + JsonDeserializationContext context) { + final JsonObject jsonObject = json.getAsJsonObject(); + + BoundingShapeData boundingShapeData = null; + + if(jsonObject.has(BOUNDING_BOX_SERIALIZED_NAME)) { + boundingShapeData = context.deserialize(json, BoundingBoxData.class); + } else if(jsonObject.has(BOUNDING_POLYGON_SERIALIZED_NAME)) { + boundingShapeData = context.deserialize(json, BoundingPolygonData.class); + } else { + errorInfoEntries.add(new IOErrorInfoEntry(annotationFileName, + MISSING_BOUNDING_SHAPE_ERROR_MESSAGE + + currentFileName + .get() + ".")); + } - return boundingShapeData; + return boundingShapeData; + } } - } - private static class ObjectCategoryDeserializer implements JsonDeserializer { - private final List errorInfoEntries; - private final AtomicReference currentFileName; - private final String annotationFileName; - - public ObjectCategoryDeserializer(List errorInfoEntries, - AtomicReference currentFileName, - String annotationFileName) { - this.errorInfoEntries = errorInfoEntries; - this.currentFileName = currentFileName; - this.annotationFileName = annotationFileName; - } + private record ObjectCategoryDeserializer(List errorInfoEntries, + AtomicReference currentFileName, + String annotationFileName) implements JsonDeserializer { @Override - public ObjectCategory deserialize(JsonElement json, java.lang.reflect.Type type, - JsonDeserializationContext context) { - final JsonObject jsonObject = json.getAsJsonObject(); - - if(!jsonObject.has(OBJECT_CATEGORY_NAME_SERIALIZED_NAME)) { - errorInfoEntries - .add(new IOErrorInfoEntry(annotationFileName, - MISSING_CATEGORY_NAME_ERROR_MESSAGE + currentFileName.get() + - ".")); - return null; - } - - final String categoryName = jsonObject.get(OBJECT_CATEGORY_NAME_SERIALIZED_NAME).getAsString(); + public ObjectCategory deserialize(JsonElement json, java.lang.reflect.Type type, + JsonDeserializationContext context) { + final JsonObject jsonObject = json.getAsJsonObject(); - Color categoryColor; - - if(jsonObject.has(OBJECT_COLOR_SERIALIZED_NAME)) { - try { - categoryColor = Color.web(jsonObject.get(OBJECT_COLOR_SERIALIZED_NAME).getAsString()); - } catch(IllegalArgumentException | ClassCastException e) { + if(!jsonObject.has(OBJECT_CATEGORY_NAME_SERIALIZED_NAME)) { errorInfoEntries - .add(new IOErrorInfoEntry(annotationFileName, INVALID_COLOR_ERROR_MESSAGE + - IMAGE_ATTRIBUTION_MESSAGE_PART + currentFileName.get() + ".")); + .add(new IOErrorInfoEntry(annotationFileName, + MISSING_CATEGORY_NAME_ERROR_MESSAGE + currentFileName.get() + + ".")); return null; } - } else { - categoryColor = ColorUtils.createRandomColor(); - } - - return new ObjectCategory(categoryName, categoryColor); - } - } - private static class BoundsDeserializer implements JsonDeserializer { - private final List errorInfoEntries; - private final AtomicReference currentFileName; - private final String annotationFileName; + final String categoryName = jsonObject.get(OBJECT_CATEGORY_NAME_SERIALIZED_NAME).getAsString(); + + Color categoryColor; + + if(jsonObject.has(OBJECT_COLOR_SERIALIZED_NAME)) { + try { + categoryColor = Color.web(jsonObject.get(OBJECT_COLOR_SERIALIZED_NAME).getAsString()); + } catch(IllegalArgumentException | ClassCastException e) { + errorInfoEntries + .add(new IOErrorInfoEntry(annotationFileName, INVALID_COLOR_ERROR_MESSAGE + + IMAGE_ATTRIBUTION_MESSAGE_PART + currentFileName.get() + ".")); + return null; + } + } else { + categoryColor = ColorUtils.createRandomColor(); + } - public BoundsDeserializer(List errorInfoEntries, - AtomicReference currentFileName, String annotationFileName) { - this.errorInfoEntries = errorInfoEntries; - this.currentFileName = currentFileName; - this.annotationFileName = annotationFileName; + return new ObjectCategory(categoryName, categoryColor); + } } + private record BoundsDeserializer(List errorInfoEntries, AtomicReference currentFileName, + String annotationFileName) implements JsonDeserializer { + @Override - public Bounds deserialize(JsonElement json, java.lang.reflect.Type type, JsonDeserializationContext context) { - final JsonObject jsonObject = json.getAsJsonObject(); + public Bounds deserialize(JsonElement json, java.lang.reflect.Type type, JsonDeserializationContext context) { + final JsonObject jsonObject = json.getAsJsonObject(); - final Optional minX = parseCoordinateField(jsonObject, BOUNDS_MIN_X_SERIALIZED_NAME); + final Optional minX = parseCoordinateField(jsonObject, BOUNDS_MIN_X_SERIALIZED_NAME); - if(minX.isEmpty()) { - return null; - } + if(minX.isEmpty()) { + return null; + } - final Optional minY = parseCoordinateField(jsonObject, BOUNDS_MIN_Y_SERIALIZED_NAME); + final Optional minY = parseCoordinateField(jsonObject, BOUNDS_MIN_Y_SERIALIZED_NAME); - if(minY.isEmpty()) { - return null; - } + if(minY.isEmpty()) { + return null; + } - final Optional maxX = parseCoordinateField(jsonObject, BOUNDS_MAX_X_SERIALIZED_NAME); + final Optional maxX = parseCoordinateField(jsonObject, BOUNDS_MAX_X_SERIALIZED_NAME); - if(maxX.isEmpty()) { - return null; - } + if(maxX.isEmpty()) { + return null; + } - final Optional maxY = parseCoordinateField(jsonObject, BOUNDS_MAX_Y_SERIALIZED_NAME); + final Optional maxY = parseCoordinateField(jsonObject, BOUNDS_MAX_Y_SERIALIZED_NAME); + + if(maxY.isEmpty()) { + return null; + } - if(maxY.isEmpty()) { - return null; + return new BoundingBox(minX.get(), minY.get(), maxX.get() - minX.get(), maxY.get() - minY.get()); } - return new BoundingBox(minX.get(), minY.get(), maxX.get() - minX.get(), maxY.get() - minY.get()); - } + private Optional parseCoordinateField(JsonObject jsonObject, String name) { + if(!jsonObject.has(name)) { + errorInfoEntries + .add(new IOErrorInfoEntry(annotationFileName, + MISSING_MESSAGE_PART + name + + ELEMENT_LOCATION_ERROR_MESSAGE_PART + + BOUNDING_BOX_SERIALIZED_NAME + + IMAGE_ATTRIBUTION_MESSAGE_PART + + currentFileName.get() + ".")); + return Optional.empty(); + } - private Optional parseCoordinateField(JsonObject jsonObject, String name) { - if(!jsonObject.has(name)) { - errorInfoEntries - .add(new IOErrorInfoEntry(annotationFileName, - MISSING_MESSAGE_PART + name + - ELEMENT_LOCATION_ERROR_MESSAGE_PART + - BOUNDING_BOX_SERIALIZED_NAME + - IMAGE_ATTRIBUTION_MESSAGE_PART + - currentFileName.get() + ".")); - return Optional.empty(); - } + double value; - double value; + try { + value = jsonObject.get(name).getAsDouble(); + } catch(ClassCastException | NumberFormatException e) { + errorInfoEntries.add(new IOErrorInfoEntry(annotationFileName, + INVALID_COORDINATE_ERROR_MESSAGE + name + + ELEMENT_LOCATION_ERROR_MESSAGE_PART + + BOUNDING_BOX_SERIALIZED_NAME + + IMAGE_ATTRIBUTION_MESSAGE_PART + + currentFileName.get() + ".")); + return Optional.empty(); + } - try { - value = jsonObject.get(name).getAsDouble(); - } catch(ClassCastException | NumberFormatException e) { - errorInfoEntries.add(new IOErrorInfoEntry(annotationFileName, - INVALID_COORDINATE_ERROR_MESSAGE + name + - ELEMENT_LOCATION_ERROR_MESSAGE_PART + - BOUNDING_BOX_SERIALIZED_NAME + - IMAGE_ATTRIBUTION_MESSAGE_PART + - currentFileName.get() + ".")); - return Optional.empty(); - } + if(!MathUtils.isWithin(value, 0.0, 1.0)) { + errorInfoEntries.add(new IOErrorInfoEntry(annotationFileName, + INVALID_COORDINATE_ERROR_MESSAGE + name + + ELEMENT_LOCATION_ERROR_MESSAGE_PART + + BOUNDING_BOX_SERIALIZED_NAME + + IMAGE_ATTRIBUTION_MESSAGE_PART + + currentFileName.get() + ".")); + return Optional.empty(); + } - if(!MathUtils.isWithin(value, 0.0, 1.0)) { - errorInfoEntries.add(new IOErrorInfoEntry(annotationFileName, - INVALID_COORDINATE_ERROR_MESSAGE + name + - ELEMENT_LOCATION_ERROR_MESSAGE_PART + - BOUNDING_BOX_SERIALIZED_NAME + - IMAGE_ATTRIBUTION_MESSAGE_PART + - currentFileName.get() + ".")); - return Optional.empty(); + return Optional.of(value); } - - return Optional.of(value); } - } - private static class ImageMetaDataDeserializer implements JsonDeserializer { - private final List errorInfoEntries; - private final String annotationFileName; - private final AtomicReference currentFileName; - private final Set fileNamesToLoad; - - public ImageMetaDataDeserializer(List errorInfoEntries, - String annotationFileName, AtomicReference currentFileName, - Set fileNamesToLoad) { - this.errorInfoEntries = errorInfoEntries; - this.annotationFileName = annotationFileName; - this.currentFileName = currentFileName; - this.fileNamesToLoad = fileNamesToLoad; - } + private record ImageMetaDataDeserializer(List errorInfoEntries, String annotationFileName, + AtomicReference currentFileName, + Set fileNamesToLoad) implements JsonDeserializer { @Override - public ImageMetaData deserialize(JsonElement json, java.lang.reflect.Type type, - JsonDeserializationContext context) { - final JsonObject jsonObject = json.getAsJsonObject(); - - if(!jsonObject.has(IMAGE_FILE_NAME_SERIALIZED_NAME)) { - errorInfoEntries.add(new IOErrorInfoEntry(annotationFileName, - MISSING_IMAGE_FILE_NAME_ERROR_MESSAGE)); - return null; - } - - final String imageFileName = jsonObject.get(IMAGE_FILE_NAME_SERIALIZED_NAME).getAsString(); + public ImageMetaData deserialize(JsonElement json, java.lang.reflect.Type type, + JsonDeserializationContext context) { + final JsonObject jsonObject = json.getAsJsonObject(); - if(!fileNamesToLoad.contains(imageFileName)) { - errorInfoEntries.add(new IOErrorInfoEntry(annotationFileName, - "Image " + imageFileName + - " does not belong to currently loaded image files.")); - return null; - } + if(!jsonObject.has(IMAGE_FILE_NAME_SERIALIZED_NAME)) { + errorInfoEntries.add(new IOErrorInfoEntry(annotationFileName, + MISSING_IMAGE_FILE_NAME_ERROR_MESSAGE)); + return null; + } - currentFileName.set(imageFileName); + final String imageFileName = jsonObject.get(IMAGE_FILE_NAME_SERIALIZED_NAME).getAsString(); - return new ImageMetaData(imageFileName); - } - } + if(!fileNamesToLoad.contains(imageFileName)) { + errorInfoEntries.add(new IOErrorInfoEntry(annotationFileName, + "Image " + imageFileName + + " does not belong to currently loaded image files.")); + return null; + } - private static class ImageAnnotationDeserializer implements JsonDeserializer { - private final List errorInfoEntries; - private final String annotationFileName; + currentFileName.set(imageFileName); - public ImageAnnotationDeserializer(List errorInfoEntries, - String annotationFileName) { - this.errorInfoEntries = errorInfoEntries; - this.annotationFileName = annotationFileName; + return new ImageMetaData(imageFileName); + } } + private record ImageAnnotationDeserializer(List errorInfoEntries, + String annotationFileName) implements JsonDeserializer { + @Override - public ImageAnnotation deserialize(JsonElement json, java.lang.reflect.Type type, - JsonDeserializationContext context) { + public ImageAnnotation deserialize(JsonElement json, java.lang.reflect.Type type, + JsonDeserializationContext context) { - if(!json.getAsJsonObject().has(IMAGE_META_DATA_SERIALIZED_NAME)) { - errorInfoEntries.add(new IOErrorInfoEntry(annotationFileName, - MISSING_IMAGES_FIELD_ERROR_MESSAGE)); - return null; - } + if(!json.getAsJsonObject().has(IMAGE_META_DATA_SERIALIZED_NAME)) { + errorInfoEntries.add(new IOErrorInfoEntry(annotationFileName, + MISSING_IMAGES_FIELD_ERROR_MESSAGE)); + return null; + } - final ImageMetaData imageMetaData = - context.deserialize(json.getAsJsonObject().get(IMAGE_META_DATA_SERIALIZED_NAME), - ImageMetaData.class); + final ImageMetaData imageMetaData = + context.deserialize(json.getAsJsonObject().get(IMAGE_META_DATA_SERIALIZED_NAME), + ImageMetaData.class); - if(imageMetaData == null) { - return null; - } + if(imageMetaData == null) { + return null; + } - if(!json.getAsJsonObject().has(BOUNDING_SHAPE_DATA_SERIALIZED_NAME)) { - errorInfoEntries.add(new IOErrorInfoEntry(annotationFileName, - MISSING_OBJECTS_FIELD_ERROR_MESSAGE - + imageMetaData.getFileName() + ".")); - return null; - } + if(!json.getAsJsonObject().has(BOUNDING_SHAPE_DATA_SERIALIZED_NAME)) { + errorInfoEntries.add(new IOErrorInfoEntry(annotationFileName, + MISSING_OBJECTS_FIELD_ERROR_MESSAGE + + imageMetaData.getFileName() + ".")); + return null; + } - final java.lang.reflect.Type boundingShapeDataListType = new TypeToken>() { - }.getType(); - final List boundingShapeDataList = - context.deserialize(json.getAsJsonObject().get(BOUNDING_SHAPE_DATA_SERIALIZED_NAME), - boundingShapeDataListType); + final java.lang.reflect.Type boundingShapeDataListType = new TypeToken>() { + }.getType(); + final List boundingShapeDataList = + context.deserialize(json.getAsJsonObject().get(BOUNDING_SHAPE_DATA_SERIALIZED_NAME), + boundingShapeDataListType); - boundingShapeDataList.removeIf(Objects::isNull); + boundingShapeDataList.removeIf(Objects::isNull); - if(boundingShapeDataList.isEmpty()) { - return null; - } + if(boundingShapeDataList.isEmpty()) { + return null; + } - return new ImageAnnotation(imageMetaData, boundingShapeDataList); + return new ImageAnnotation(imageMetaData, boundingShapeDataList); + } } - } - private static class BoundingBoxDataDeserializer implements JsonDeserializer { - private final List errorInfoEntries; - private final AtomicReference currentFileName; - private final String annotationFileName; - private final Map nameToObjectCategoryMap; - private final Map boundingShapeCountPerCategory; - - public BoundingBoxDataDeserializer(List errorInfoEntries, - AtomicReference currentFileName, String annotationFileName, - Map nameToObjectCategoryMap, - Map boundingShapeCountPerCategory) { - this.errorInfoEntries = errorInfoEntries; - this.currentFileName = currentFileName; - this.annotationFileName = annotationFileName; - this.nameToObjectCategoryMap = nameToObjectCategoryMap; - this.boundingShapeCountPerCategory = boundingShapeCountPerCategory; - } + private record BoundingBoxDataDeserializer(List errorInfoEntries, + AtomicReference currentFileName, String annotationFileName, + Map nameToObjectCategoryMap, + Map boundingShapeCountPerCategory) implements JsonDeserializer { @Override - public BoundingBoxData deserialize(JsonElement json, java.lang.reflect.Type typeOfT, - JsonDeserializationContext context) { - final JsonObject jsonObject = json.getAsJsonObject(); - - final Optional parsedObjectCategory = - parseObjectCategory(context, jsonObject, errorInfoEntries, - BOUNDING_BOX_SERIALIZED_NAME, annotationFileName, - currentFileName.get()); - - if(parsedObjectCategory.isEmpty()) { - return null; - } + public BoundingBoxData deserialize(JsonElement json, java.lang.reflect.Type typeOfT, + JsonDeserializationContext context) { + final JsonObject jsonObject = json.getAsJsonObject(); - final Bounds bounds = - context.deserialize(json.getAsJsonObject().get(BOUNDING_BOX_SERIALIZED_NAME), Bounds.class); + final Optional parsedObjectCategory = + parseObjectCategory(context, jsonObject, errorInfoEntries, + BOUNDING_BOX_SERIALIZED_NAME, annotationFileName, + currentFileName.get()); - if(bounds == null) { - return null; - } + if(parsedObjectCategory.isEmpty()) { + return null; + } - final Optional> tags = parseBoundingShapeTags(context, jsonObject, errorInfoEntries, - BOUNDING_BOX_SERIALIZED_NAME, annotationFileName, - currentFileName.get()); + final Bounds bounds = + context.deserialize(json.getAsJsonObject().get(BOUNDING_BOX_SERIALIZED_NAME), Bounds.class); - if(tags.isEmpty()) { - return null; - } + if(bounds == null) { + return null; + } - final Optional> parts = parseBoundingShapeDataParts(context, jsonObject, - errorInfoEntries, - BOUNDING_BOX_SERIALIZED_NAME, - annotationFileName, - currentFileName.get()); + final Optional> tags = parseBoundingShapeTags(context, jsonObject, errorInfoEntries, + BOUNDING_BOX_SERIALIZED_NAME, annotationFileName, + currentFileName.get()); - if(parts.isEmpty()) { - return null; - } + if(tags.isEmpty()) { + return null; + } - final ObjectCategory objectCategory = - nameToObjectCategoryMap.computeIfAbsent(parsedObjectCategory.get().getName(), - key -> parsedObjectCategory.get()); + final Optional> parts = parseBoundingShapeDataParts(context, jsonObject, + errorInfoEntries, + BOUNDING_BOX_SERIALIZED_NAME, + annotationFileName, + currentFileName.get()); - boundingShapeCountPerCategory.merge(objectCategory.getName(), 1, Integer::sum); + if(parts.isEmpty()) { + return null; + } - final BoundingBoxData boundingBoxData = new BoundingBoxData(objectCategory, bounds, tags.get()); - boundingBoxData.setParts(parts.get()); + final ObjectCategory objectCategory = + nameToObjectCategoryMap.computeIfAbsent(parsedObjectCategory.get().getName(), + key -> parsedObjectCategory.get()); - return boundingBoxData; - } + boundingShapeCountPerCategory.merge(objectCategory.getName(), 1, Integer::sum); - } + final BoundingBoxData boundingBoxData = new BoundingBoxData(objectCategory, bounds, tags.get()); + boundingBoxData.setParts(parts.get()); - private static class BoundingPolygonDataDeserializer implements JsonDeserializer { - private final List errorInfoEntries; - private final AtomicReference currentFileName; - private final String annotationFileName; - private final Map nameToObjectCategoryMap; - private final Map boundingShapeCountPerCategory; + return boundingBoxData; + } - public BoundingPolygonDataDeserializer(List errorInfoEntries, - AtomicReference currentFileName, - String annotationFileName, - Map nameToObjectCategoryMap, - Map boundingShapeCountPerCategory) { - this.errorInfoEntries = errorInfoEntries; - this.currentFileName = currentFileName; - this.annotationFileName = annotationFileName; - this.nameToObjectCategoryMap = nameToObjectCategoryMap; - this.boundingShapeCountPerCategory = boundingShapeCountPerCategory; } + private record BoundingPolygonDataDeserializer(List errorInfoEntries, + AtomicReference currentFileName, String annotationFileName, + Map nameToObjectCategoryMap, + Map boundingShapeCountPerCategory) implements JsonDeserializer { + @Override - public BoundingPolygonData deserialize(JsonElement json, java.lang.reflect.Type typeOfT, - JsonDeserializationContext context) { - final JsonObject jsonObject = json.getAsJsonObject(); - - final Optional parsedObjectCategory = parseObjectCategory(context, jsonObject, - errorInfoEntries, - BOUNDING_POLYGON_SERIALIZED_NAME, - annotationFileName, - currentFileName.get()); - context.deserialize(json.getAsJsonObject().get(OBJECT_CATEGORY_SERIALIZED_NAME), - ObjectCategory.class); - - if(parsedObjectCategory.isEmpty()) { - return null; - } + public BoundingPolygonData deserialize(JsonElement json, java.lang.reflect.Type typeOfT, + JsonDeserializationContext context) { + final JsonObject jsonObject = json.getAsJsonObject(); - final java.lang.reflect.Type pointsType = new TypeToken>() { - }.getType(); - List points; + final Optional parsedObjectCategory = parseObjectCategory(context, jsonObject, + errorInfoEntries, + BOUNDING_POLYGON_SERIALIZED_NAME, + annotationFileName, + currentFileName.get()); + context.deserialize(json.getAsJsonObject().get(OBJECT_CATEGORY_SERIALIZED_NAME), + ObjectCategory.class); - try { - points = context.deserialize(json.getAsJsonObject().get(BOUNDING_POLYGON_SERIALIZED_NAME), pointsType); - } catch(JsonParseException | NumberFormatException e) { - errorInfoEntries.add(new IOErrorInfoEntry(annotationFileName, - INVALID_COORDINATES_ERROR_MESSAGE + - BOUNDING_POLYGON_SERIALIZED_NAME + - IMAGE_ATTRIBUTION_MESSAGE_PART + - currentFileName.get() + ".")); - return null; - } + if(parsedObjectCategory.isEmpty()) { + return null; + } - if(points == null || points.isEmpty() || points.size() % 2 != 0) { - errorInfoEntries.add(new IOErrorInfoEntry(annotationFileName, - INVALID_COORDINATE_NUMBER_ERROR_MESSAGE + - BOUNDING_POLYGON_SERIALIZED_NAME + - IMAGE_ATTRIBUTION_MESSAGE_PART + - currentFileName.get() + ".")); - return null; - } + final java.lang.reflect.Type pointsType = new TypeToken>() { + }.getType(); + List points; - if(!points.stream().allMatch(value -> MathUtils.isWithin(value, 0.0, 1.0))) { - errorInfoEntries.add(new IOErrorInfoEntry(annotationFileName, - INVALID_COORDINATES_ERROR_MESSAGE + - BOUNDING_POLYGON_SERIALIZED_NAME + - IMAGE_ATTRIBUTION_MESSAGE_PART + - currentFileName.get() + ".")); - return null; - } + try { + points = context.deserialize(json.getAsJsonObject().get(BOUNDING_POLYGON_SERIALIZED_NAME), pointsType); + } catch(JsonParseException | NumberFormatException e) { + errorInfoEntries.add(new IOErrorInfoEntry(annotationFileName, + INVALID_COORDINATES_ERROR_MESSAGE + + BOUNDING_POLYGON_SERIALIZED_NAME + + IMAGE_ATTRIBUTION_MESSAGE_PART + + currentFileName.get() + ".")); + return null; + } - final Optional> tags = parseBoundingShapeTags(context, jsonObject, errorInfoEntries, - BOUNDING_POLYGON_SERIALIZED_NAME, - annotationFileName, - currentFileName.get()); + if(points == null || points.isEmpty() || points.size() % 2 != 0) { + errorInfoEntries.add(new IOErrorInfoEntry(annotationFileName, + INVALID_COORDINATE_NUMBER_ERROR_MESSAGE + + BOUNDING_POLYGON_SERIALIZED_NAME + + IMAGE_ATTRIBUTION_MESSAGE_PART + + currentFileName.get() + ".")); + return null; + } - if(tags.isEmpty()) { - return null; - } + if(!points.stream().allMatch(value -> MathUtils.isWithin(value, 0.0, 1.0))) { + errorInfoEntries.add(new IOErrorInfoEntry(annotationFileName, + INVALID_COORDINATES_ERROR_MESSAGE + + BOUNDING_POLYGON_SERIALIZED_NAME + + IMAGE_ATTRIBUTION_MESSAGE_PART + + currentFileName.get() + ".")); + return null; + } - final Optional> parts = parseBoundingShapeDataParts(context, jsonObject, - errorInfoEntries, - BOUNDING_POLYGON_SERIALIZED_NAME, - annotationFileName, - currentFileName.get()); + final Optional> tags = parseBoundingShapeTags(context, jsonObject, errorInfoEntries, + BOUNDING_POLYGON_SERIALIZED_NAME, + annotationFileName, + currentFileName.get()); - if(parts.isEmpty()) { - return null; - } + if(tags.isEmpty()) { + return null; + } - final ObjectCategory objectCategory = - nameToObjectCategoryMap.computeIfAbsent(parsedObjectCategory.get().getName(), - key -> parsedObjectCategory.get()); + final Optional> parts = parseBoundingShapeDataParts(context, jsonObject, + errorInfoEntries, + BOUNDING_POLYGON_SERIALIZED_NAME, + annotationFileName, + currentFileName.get()); - boundingShapeCountPerCategory.merge(objectCategory.getName(), 1, Integer::sum); + if(parts.isEmpty()) { + return null; + } - final BoundingPolygonData boundingPolygonData = new BoundingPolygonData(objectCategory, points, tags.get()); - boundingPolygonData.setParts(parts.get()); + final ObjectCategory objectCategory = + nameToObjectCategoryMap.computeIfAbsent(parsedObjectCategory.get().getName(), + key -> parsedObjectCategory.get()); - return boundingPolygonData; - } - } + boundingShapeCountPerCategory.merge(objectCategory.getName(), 1, Integer::sum); - private static class ImageAnnotationListDeserializer implements JsonDeserializer> { - final DoubleProperty progress; + final BoundingPolygonData boundingPolygonData = new BoundingPolygonData(objectCategory, points, tags.get()); + boundingPolygonData.setParts(parts.get()); - public ImageAnnotationListDeserializer(DoubleProperty progress) { - this.progress = progress; + return boundingPolygonData; + } } + private record ImageAnnotationListDeserializer( + DoubleProperty progress) implements JsonDeserializer> { + @Override - public List deserialize(JsonElement json, java.lang.reflect.Type typeOfT, - JsonDeserializationContext context) { - final JsonArray jsonArray = json.getAsJsonArray(); + public List deserialize(JsonElement json, java.lang.reflect.Type typeOfT, + JsonDeserializationContext context) { + final JsonArray jsonArray = json.getAsJsonArray(); - int totalNrAnnotations = jsonArray.size(); - final AtomicInteger nrProcessedAnnotations = new AtomicInteger(0); + int totalNrAnnotations = jsonArray.size(); + final AtomicInteger nrProcessedAnnotations = new AtomicInteger(0); - return StreamSupport.stream(jsonArray.spliterator(), false) - .map(jsonElement -> { - progress.set(1.0 * nrProcessedAnnotations.incrementAndGet() / totalNrAnnotations); + return StreamSupport.stream(jsonArray.spliterator(), false) + .map(jsonElement -> { + progress.set(1.0 * nrProcessedAnnotations.incrementAndGet() / totalNrAnnotations); - return (ImageAnnotation) context.deserialize(jsonElement, ImageAnnotation.class); - }) - .filter(Objects::nonNull) - .collect(Collectors.toList()); + return (ImageAnnotation) context.deserialize(jsonElement, ImageAnnotation.class); + }) + .filter(Objects::nonNull) + .toList(); + } } - } } diff --git a/src/main/java/com/github/mfl28/boundingboxeditor/model/io/JSONSaveStrategy.java b/src/main/java/com/github/mfl28/boundingboxeditor/model/io/JSONSaveStrategy.java index 64fad01..56e54a6 100644 --- a/src/main/java/com/github/mfl28/boundingboxeditor/model/io/JSONSaveStrategy.java +++ b/src/main/java/com/github/mfl28/boundingboxeditor/model/io/JSONSaveStrategy.java @@ -53,7 +53,7 @@ public class JSONSaveStrategy implements ImageAnnotationSaveStrategy { @Override public ImageAnnotationExportResult save(ImageAnnotationData annotations, Path destination, DoubleProperty progress) { - final int totalNrAnnotations = annotations.getImageAnnotations().size(); + final int totalNrAnnotations = annotations.imageAnnotations().size(); final AtomicInteger nrProcessedAnnotations = new AtomicInteger(0); final Gson gson = new GsonBuilder() @@ -62,7 +62,7 @@ public ImageAnnotationExportResult save(ImageAnnotationData annotations, Path de (JsonSerializer) (src, typeOfSrc, context) -> { JsonArray serializedAnnotations = new JsonArray(); - for(ImageAnnotation annotation : src.getImageAnnotations()) { + for(ImageAnnotation annotation : src.imageAnnotations()) { serializedAnnotations.add(context.serialize(annotation)); progress.set(1.0 * nrProcessedAnnotations.incrementAndGet() / totalNrAnnotations); diff --git a/src/main/java/com/github/mfl28/boundingboxeditor/model/io/PVOCLoadStrategy.java b/src/main/java/com/github/mfl28/boundingboxeditor/model/io/PVOCLoadStrategy.java index 61226f9..ff4e8c9 100644 --- a/src/main/java/com/github/mfl28/boundingboxeditor/model/io/PVOCLoadStrategy.java +++ b/src/main/java/com/github/mfl28/boundingboxeditor/model/io/PVOCLoadStrategy.java @@ -39,7 +39,6 @@ import java.util.*; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.atomic.AtomicInteger; -import java.util.stream.Collectors; import java.util.stream.Stream; /** @@ -74,8 +73,7 @@ public ImageAnnotationImportResult load(Path path, Set filesToLoad, try(Stream fileStream = Files.walk(path, INCLUDE_SUBDIRECTORIES ? Integer.MAX_VALUE : 1)) { List annotationFiles = fileStream .filter(pathItem -> pathItem.getFileName().toString().endsWith(".xml")) - .map(Path::toFile) - .collect(Collectors.toList()); + .map(Path::toFile).toList(); unParsedFileErrorMessages = Collections.synchronizedList(new ArrayList<>()); @@ -99,7 +97,7 @@ public ImageAnnotationImportResult load(Path path, Set filesToLoad, } }) .filter(Objects::nonNull) - .collect(Collectors.toList()); + .toList(); return new ImageAnnotationImportResult( imageAnnotations.size(), diff --git a/src/main/java/com/github/mfl28/boundingboxeditor/model/io/PVOCSaveStrategy.java b/src/main/java/com/github/mfl28/boundingboxeditor/model/io/PVOCSaveStrategy.java index 68fabcd..1e93ad2 100644 --- a/src/main/java/com/github/mfl28/boundingboxeditor/model/io/PVOCSaveStrategy.java +++ b/src/main/java/com/github/mfl28/boundingboxeditor/model/io/PVOCSaveStrategy.java @@ -87,11 +87,11 @@ public ImageAnnotationExportResult save(ImageAnnotationData annotations, Path de List unParsedFileErrorMessages = Collections.synchronizedList(new ArrayList<>()); - int totalNrOfAnnotations = annotations.getImageAnnotations().size(); + int totalNrOfAnnotations = annotations.imageAnnotations().size(); AtomicInteger nrProcessedAnnotations = new AtomicInteger(0); - annotations.getImageAnnotations().parallelStream().forEach(annotation -> { + annotations.imageAnnotations().parallelStream().forEach(annotation -> { try { createXmlFileFromImageAnnotationDataElement(annotation); } catch(TransformerException | ParserConfigurationException e) { @@ -103,7 +103,7 @@ public ImageAnnotationExportResult save(ImageAnnotationData annotations, Path de }); return new ImageAnnotationExportResult( - annotations.getImageAnnotations().size() - unParsedFileErrorMessages.size(), + annotations.imageAnnotations().size() - unParsedFileErrorMessages.size(), unParsedFileErrorMessages ); } diff --git a/src/main/java/com/github/mfl28/boundingboxeditor/model/io/YOLOLoadStrategy.java b/src/main/java/com/github/mfl28/boundingboxeditor/model/io/YOLOLoadStrategy.java index 272efdb..be2eeb5 100644 --- a/src/main/java/com/github/mfl28/boundingboxeditor/model/io/YOLOLoadStrategy.java +++ b/src/main/java/com/github/mfl28/boundingboxeditor/model/io/YOLOLoadStrategy.java @@ -32,12 +32,11 @@ import java.util.*; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.atomic.AtomicInteger; -import java.util.stream.Collectors; import java.util.stream.Stream; /** * Loads rectangular bounding-box annotations in the YOLO-format described at - * https://github.com/AlexeyAB/Yolo_mark/issues/60#issuecomment-401854885 + * ... */ public class YOLOLoadStrategy implements ImageAnnotationLoadStrategy { public static final String INVALID_BOUNDING_BOX_COORDINATES_MESSAGE = "Invalid bounding-box coordinates on line "; @@ -76,8 +75,7 @@ public ImageAnnotationImportResult load(Path path, Set filesToLoad, try(Stream fileStream = Files.walk(path, INCLUDE_SUBDIRECTORIES ? Integer.MAX_VALUE : 1)) { List annotationFiles = fileStream .filter(pathItem -> pathItem.getFileName().toString().endsWith(".txt")) - .map(Path::toFile) - .collect(Collectors.toList()); + .map(Path::toFile).toList(); int totalNrOfFiles = annotationFiles.size(); AtomicInteger nrProcessedFiles = new AtomicInteger(0); @@ -100,7 +98,7 @@ public ImageAnnotationImportResult load(Path path, Set filesToLoad, } }) .filter(Objects::nonNull) - .collect(Collectors.toList()); + .toList(); return new ImageAnnotationImportResult( imageAnnotations.size(), diff --git a/src/main/java/com/github/mfl28/boundingboxeditor/model/io/YOLOSaveStrategy.java b/src/main/java/com/github/mfl28/boundingboxeditor/model/io/YOLOSaveStrategy.java index 55dc3d8..3df4989 100644 --- a/src/main/java/com/github/mfl28/boundingboxeditor/model/io/YOLOSaveStrategy.java +++ b/src/main/java/com/github/mfl28/boundingboxeditor/model/io/YOLOSaveStrategy.java @@ -36,11 +36,10 @@ import java.text.DecimalFormatSymbols; import java.util.*; import java.util.concurrent.atomic.AtomicInteger; -import java.util.stream.Collectors; /** * Saves rectangular bounding-box annotations in the YOLO-format described at - * https://github.com/AlexeyAB/Yolo_mark/issues/60#issuecomment-401854885 + * ... */ public class YOLOSaveStrategy implements ImageAnnotationSaveStrategy { private static final DecimalFormat DECIMAL_FORMAT = @@ -54,11 +53,11 @@ public class YOLOSaveStrategy implements ImageAnnotationSaveStrategy { public ImageAnnotationExportResult save(ImageAnnotationData annotations, Path destination, DoubleProperty progress) { this.saveFolderPath = destination; - this.categories = annotations.getCategoryNameToBoundingShapeCountMap().entrySet().stream() + this.categories = annotations.categoryNameToBoundingShapeCountMap().entrySet().stream() .filter(stringIntegerEntry -> stringIntegerEntry.getValue() > 0) .map(Map.Entry::getKey) .sorted() - .collect(Collectors.toList()); + .toList(); List unParsedFileErrorMessages = Collections.synchronizedList(new ArrayList<>()); @@ -68,10 +67,10 @@ public ImageAnnotationExportResult save(ImageAnnotationData annotations, Path de unParsedFileErrorMessages.add(new IOErrorInfoEntry(OBJECT_DATA_FILE_NAME, e.getMessage())); } - int totalNrOfAnnotations = annotations.getImageAnnotations().size(); + int totalNrOfAnnotations = annotations.imageAnnotations().size(); AtomicInteger nrProcessedAnnotations = new AtomicInteger(0); - annotations.getImageAnnotations().parallelStream().forEach(annotation -> { + annotations.imageAnnotations().parallelStream().forEach(annotation -> { try { createAnnotationFile(annotation); } catch(IOException e) { @@ -114,8 +113,8 @@ private void createAnnotationFile(ImageAnnotation annotation) throws IOException for(int i = 0; i < boundingShapeDataList.size() - 1; ++i) { BoundingShapeData boundingShapeData = boundingShapeDataList.get(i); - if(boundingShapeData instanceof BoundingBoxData) { - fileWriter.write(createBoundingBoxDataEntry((BoundingBoxData) boundingShapeData)); + if(boundingShapeData instanceof BoundingBoxData boundingBoxData) { + fileWriter.write(createBoundingBoxDataEntry(boundingBoxData)); fileWriter.newLine(); } } @@ -123,8 +122,8 @@ private void createAnnotationFile(ImageAnnotation annotation) throws IOException if(!boundingShapeDataList.isEmpty()) { BoundingShapeData lastShapeData = boundingShapeDataList.get(boundingShapeDataList.size() - 1); - if(lastShapeData instanceof BoundingBoxData) { - fileWriter.write(createBoundingBoxDataEntry((BoundingBoxData) lastShapeData)); + if(lastShapeData instanceof BoundingBoxData boundingBoxData) { + fileWriter.write(createBoundingBoxDataEntry(boundingBoxData)); } } } diff --git a/src/main/java/com/github/mfl28/boundingboxeditor/model/io/restclients/BoundingBoxPredictionEntry.java b/src/main/java/com/github/mfl28/boundingboxeditor/model/io/restclients/BoundingBoxPredictionEntry.java index 64efd38..e04c58f 100644 --- a/src/main/java/com/github/mfl28/boundingboxeditor/model/io/restclients/BoundingBoxPredictionEntry.java +++ b/src/main/java/com/github/mfl28/boundingboxeditor/model/io/restclients/BoundingBoxPredictionEntry.java @@ -21,20 +21,5 @@ import java.util.List; import java.util.Map; -public class BoundingBoxPredictionEntry { - private final Map> categoryToBoundingBoxes; - private final Double score; - - public BoundingBoxPredictionEntry(Map> categoryToBoundingBoxes, Double score) { - this.categoryToBoundingBoxes = categoryToBoundingBoxes; - this.score = score; - } - - public Map> getCategoryToBoundingBoxes() { - return categoryToBoundingBoxes; - } - - public Double getScore() { - return score; - } +public record BoundingBoxPredictionEntry(Map> categoryToBoundingBoxes, Double score) { } diff --git a/src/main/java/com/github/mfl28/boundingboxeditor/model/io/restclients/ModelEntry.java b/src/main/java/com/github/mfl28/boundingboxeditor/model/io/restclients/ModelEntry.java index 0aa6df3..623ca3f 100644 --- a/src/main/java/com/github/mfl28/boundingboxeditor/model/io/restclients/ModelEntry.java +++ b/src/main/java/com/github/mfl28/boundingboxeditor/model/io/restclients/ModelEntry.java @@ -18,20 +18,5 @@ */ package com.github.mfl28.boundingboxeditor.model.io.restclients; -public class ModelEntry { - private final String modelName; - private final String modelUrl; - - public ModelEntry(String modelName, String modelUrl) { - this.modelName = modelName; - this.modelUrl = modelUrl; - } - - public String getModelName() { - return modelName; - } - - public String getModelUrl() { - return modelUrl; - } +public record ModelEntry(String modelName, String modelUrl) { } diff --git a/src/main/java/com/github/mfl28/boundingboxeditor/model/io/results/IOErrorInfoEntry.java b/src/main/java/com/github/mfl28/boundingboxeditor/model/io/results/IOErrorInfoEntry.java index 17ec9e1..8bb45fd 100644 --- a/src/main/java/com/github/mfl28/boundingboxeditor/model/io/results/IOErrorInfoEntry.java +++ b/src/main/java/com/github/mfl28/boundingboxeditor/model/io/results/IOErrorInfoEntry.java @@ -50,15 +50,6 @@ public String getSourceName() { return sourceName.get(); } - /** - * Set the name of the source of the error. - * - * @param sourceName the name of the source - */ - public void setSourceName(String sourceName) { - this.sourceName.set(sourceName); - } - /** * Returns the error source-name property. * @@ -77,15 +68,6 @@ public String getErrorDescription() { return errorDescription.get(); } - /** - * Sets a description of the error that occurred. - * - * @param errorDescription the error-description - */ - public void setErrorDescription(String errorDescription) { - this.errorDescription.set(errorDescription); - } - /** * Returns the description-property of the error that occurred. * @@ -106,12 +88,10 @@ public boolean equals(Object o) { return true; } - if(!(o instanceof IOErrorInfoEntry)) { + if(!(o instanceof IOErrorInfoEntry that)) { return false; } - IOErrorInfoEntry that = (IOErrorInfoEntry) o; - return Objects.equals(sourceName.get(), that.sourceName.get()) && Objects.equals(errorDescription.get(), that.errorDescription.get()); } diff --git a/src/main/java/com/github/mfl28/boundingboxeditor/model/io/services/BoundingBoxPredictorService.java b/src/main/java/com/github/mfl28/boundingboxeditor/model/io/services/BoundingBoxPredictorService.java index e831a4a..82f16d8 100644 --- a/src/main/java/com/github/mfl28/boundingboxeditor/model/io/services/BoundingBoxPredictorService.java +++ b/src/main/java/com/github/mfl28/boundingboxeditor/model/io/services/BoundingBoxPredictorService.java @@ -43,66 +43,29 @@ public class BoundingBoxPredictorService extends IoService boundingBoxPredictorConfig = new SimpleObjectProperty<>(this, "boundingBoxPredictorConfig"); - public File getImageFile() { - return imageFile.get(); - } public void setImageFile(File imageFile) { this.imageFile.set(imageFile); } - public ObjectProperty imageFileProperty() { - return imageFile; - } - - public ImageMetaData getImageMetaData() { - return imageMetaData.get(); - } - public void setImageMetaData(ImageMetaData imageMetaDate) { this.imageMetaData.set(imageMetaDate); } - public ObjectProperty imageMetaDataProperty() { - return imageMetaData; - } - - public Map getCategoryNameToCategoryMap() { - return categoryNameToCategoryMap.get(); - } public void setCategoryNameToCategoryMap(Map categoryNameToCategoryMap) { this.categoryNameToCategoryMap.set(categoryNameToCategoryMap); } - public ObjectProperty> categoryNameToCategoryMapProperty() { - return categoryNameToCategoryMap; - } - - public BoundingBoxPredictorClient getPredictorClient() { - return predictorClient.get(); - } - public void setPredictorClient(BoundingBoxPredictorClient predictorClient) { this.predictorClient.set(predictorClient); } - public ObjectProperty predictorClientProperty() { - return predictorClient; - } - - public BoundingBoxPredictorConfig getBoundingBoxPredictorConfig() { - return boundingBoxPredictorConfig.get(); - } public void setBoundingBoxPredictorConfig(BoundingBoxPredictorConfig boundingBoxPredictorConfig) { this.boundingBoxPredictorConfig.set(boundingBoxPredictorConfig); } - public ObjectProperty boundingBoxPredictorConfigProperty() { - return boundingBoxPredictorConfig; - } - @Override protected Task createTask() { return new Task<>() { diff --git a/src/main/java/com/github/mfl28/boundingboxeditor/model/io/services/ImageAnnotationExportService.java b/src/main/java/com/github/mfl28/boundingboxeditor/model/io/services/ImageAnnotationExportService.java index 8439f0a..9ad6c4b 100644 --- a/src/main/java/com/github/mfl28/boundingboxeditor/model/io/services/ImageAnnotationExportService.java +++ b/src/main/java/com/github/mfl28/boundingboxeditor/model/io/services/ImageAnnotationExportService.java @@ -44,18 +44,10 @@ public void setDestination(File destination) { this.destination.setValue(destination); } - public ImageAnnotationSaveStrategy.Type getExportFormat() { - return exportFormat.get(); - } - public void setExportFormat(ImageAnnotationSaveStrategy.Type exportFormat) { this.exportFormat.setValue(exportFormat); } - public ImageAnnotationData getAnnotationData() { - return annotationData.get(); - } - public void setAnnotationData(ImageAnnotationData annotationData) { this.annotationData.setValue(annotationData); } diff --git a/src/main/java/com/github/mfl28/boundingboxeditor/model/io/services/ImageAnnotationImportService.java b/src/main/java/com/github/mfl28/boundingboxeditor/model/io/services/ImageAnnotationImportService.java index 8b9c4c1..d6239a8 100644 --- a/src/main/java/com/github/mfl28/boundingboxeditor/model/io/services/ImageAnnotationImportService.java +++ b/src/main/java/com/github/mfl28/boundingboxeditor/model/io/services/ImageAnnotationImportService.java @@ -40,22 +40,10 @@ public class ImageAnnotationImportService extends IoService> categoryNameToCategoryMap = new SimpleObjectProperty<>(this, "categoryNameToCategoryMap"); - public Set getImportableFileNames() { - return importableFileNames.get(); - } - public void setImportableFileNames(Set importableFileNames) { this.importableFileNames.set(importableFileNames); } - public ObjectProperty> importableFileNamesProperty() { - return importableFileNames; - } - - public Map getCategoryNameToCategoryMap() { - return categoryNameToCategoryMap.get(); - } - public void setCategoryNameToCategoryMap(Map categoryNameToCategoryMap) { this.categoryNameToCategoryMap.set(categoryNameToCategoryMap); } @@ -68,10 +56,6 @@ public void setSource(File source) { this.source.set(source); } - public ImageAnnotationLoadStrategy.Type getImportFormat() { - return importFormat.get(); - } - public void setImportFormat(ImageAnnotationLoadStrategy.Type importFormat) { this.importFormat.set(importFormat); } diff --git a/src/main/java/com/github/mfl28/boundingboxeditor/model/io/services/ImageMetaDataLoadingService.java b/src/main/java/com/github/mfl28/boundingboxeditor/model/io/services/ImageMetaDataLoadingService.java index cb4ae01..3863136 100644 --- a/src/main/java/com/github/mfl28/boundingboxeditor/model/io/services/ImageMetaDataLoadingService.java +++ b/src/main/java/com/github/mfl28/boundingboxeditor/model/io/services/ImageMetaDataLoadingService.java @@ -31,7 +31,6 @@ import java.io.File; import java.util.*; import java.util.concurrent.atomic.AtomicInteger; -import java.util.stream.Collectors; public class ImageMetaDataLoadingService extends IoService { private final ObjectProperty source = new SimpleObjectProperty<>(this, "source"); @@ -46,10 +45,6 @@ public void setSource(File source) { this.source.set(source); } - public List getImageFiles() { - return imageFiles.get(); - } - public void setImageFiles(List imageFiles) { this.imageFiles.set(imageFiles); } @@ -88,7 +83,7 @@ protected ImageMetaDataLoadingResult call() throws Exception { final List validImageFiles = imageFiles.get().stream().filter(item -> fileNameToMetaDataMap.containsKey(item.getName())) - .collect(Collectors.toList()); + .toList(); return new ImageMetaDataLoadingResult(fileNameToMetaDataMap.size(), errorInfoEntries, validImageFiles, diff --git a/src/main/java/com/github/mfl28/boundingboxeditor/model/io/services/ModelNameFetchService.java b/src/main/java/com/github/mfl28/boundingboxeditor/model/io/services/ModelNameFetchService.java index 4b0b3b4..440a45a 100644 --- a/src/main/java/com/github/mfl28/boundingboxeditor/model/io/services/ModelNameFetchService.java +++ b/src/main/java/com/github/mfl28/boundingboxeditor/model/io/services/ModelNameFetchService.java @@ -30,23 +30,14 @@ import java.util.ArrayList; import java.util.Collections; import java.util.List; -import java.util.stream.Collectors; public class ModelNameFetchService extends IoService { private final ObjectProperty client = new SimpleObjectProperty<>(this, "client"); - public BoundingBoxPredictorClient getClient() { - return client.get(); - } - public void setClient(BoundingBoxPredictorClient client) { this.client.set(client); } - public ObjectProperty clientProperty() { - return client; - } - @Override protected Task createTask() { return new Task<>() { @@ -64,9 +55,9 @@ protected ModelNameFetchResult call() { } List models = - modelEntries.stream().map(ModelEntry::getModelName) + modelEntries.stream().map(ModelEntry::modelName) .filter(modelName -> !modelName.isBlank()) - .collect(Collectors.toList()); + .toList(); return new ModelNameFetchResult(1, Collections.emptyList(), models); } diff --git a/src/main/java/com/github/mfl28/boundingboxeditor/ui/BoundingBoxTreeItem.java b/src/main/java/com/github/mfl28/boundingboxeditor/ui/BoundingBoxTreeItem.java index a9a53fc..58e5bbe 100644 --- a/src/main/java/com/github/mfl28/boundingboxeditor/ui/BoundingBoxTreeItem.java +++ b/src/main/java/com/github/mfl28/boundingboxeditor/ui/BoundingBoxTreeItem.java @@ -55,12 +55,10 @@ public boolean equals(Object obj) { return true; } - if(!(obj instanceof BoundingBoxTreeItem)) { + if(!(obj instanceof BoundingBoxTreeItem other)) { return false; } - BoundingBoxTreeItem other = (BoundingBoxTreeItem) obj; - return id == other.id && getValue().equals(other.getValue()) && getChildren().equals(other.getChildren()); } diff --git a/src/main/java/com/github/mfl28/boundingboxeditor/ui/BoundingBoxView.java b/src/main/java/com/github/mfl28/boundingboxeditor/ui/BoundingBoxView.java index 9feaa2f..00b9180 100644 --- a/src/main/java/com/github/mfl28/boundingboxeditor/ui/BoundingBoxView.java +++ b/src/main/java/com/github/mfl28/boundingboxeditor/ui/BoundingBoxView.java @@ -43,7 +43,6 @@ import java.util.Arrays; import java.util.List; import java.util.Objects; -import java.util.stream.Collectors; /** * Represents the visual (UI)-component of a bounding-box. To the app-user, instances of @@ -70,7 +69,7 @@ public class BoundingBoxView extends Rectangle implements * and movable by the user. * * @param objectCategory the category this bounding-box will be assigned to - * into the data component represented by the {@link BoundingBoxData} class) + * into the data component represented by the {@link BoundingBoxData} class */ public BoundingBoxView(ObjectCategory objectCategory) { this.boundingShapeViewData = new BoundingShapeViewData(this, objectCategory); @@ -142,12 +141,10 @@ public boolean equals(Object obj) { return true; } - if(!(obj instanceof BoundingBoxView)) { + if(!(obj instanceof BoundingBoxView other)) { return false; } - BoundingBoxView other = (BoundingBoxView) obj; - return Objects.equals(boundingShapeViewData, other.boundingShapeViewData) && MathUtils.doubleAlmostEqual(getX(), other.getX()) && MathUtils.doubleAlmostEqual(getY(), other.getY()) @@ -243,7 +240,7 @@ void autoScaleWithBounds(ReadOnlyObjectProperty autoScaleBounds) { private List createResizeHandles() { return Arrays.stream(CompassPoint.values()) .map(ResizeHandle::new) - .collect(Collectors.toList()); + .toList(); } private void addMoveFunctionality() { @@ -392,37 +389,38 @@ private void bindToParentRectangle() { visibleProperty().bind(rectangle.visibleProperty().and(rectangle.selectedProperty())); switch(compassPoint) { - case NW: + case NW -> { xProperty().bind(rectangleX.subtract(SIDE_LENGTH / 2)); yProperty().bind(rectangleY.subtract(SIDE_LENGTH / 2)); - break; - case N: + } + case N -> { xProperty().bind(rectangleX.add(rectangleW.subtract(SIDE_LENGTH).divide(2))); yProperty().bind(rectangleY.subtract(SIDE_LENGTH / 2)); - break; - case NE: + } + case NE -> { xProperty().bind(rectangleX.add(rectangleW).subtract(SIDE_LENGTH / 2)); yProperty().bind(rectangleY.subtract(SIDE_LENGTH / 2)); - break; - case E: + } + case E -> { xProperty().bind(rectangleX.add(rectangleW).subtract(SIDE_LENGTH / 2)); yProperty().bind(rectangleY.add(rectangleH.subtract(SIDE_LENGTH).divide(2))); - break; - case SE: + } + case SE -> { xProperty().bind(rectangleX.add(rectangleW).subtract(SIDE_LENGTH / 2)); yProperty().bind(rectangleY.add(rectangleH).subtract(SIDE_LENGTH / 2)); - break; - case S: + } + case S -> { xProperty().bind(rectangleX.add(rectangleW.subtract(SIDE_LENGTH).divide(2))); yProperty().bind(rectangleY.add(rectangleH).subtract(SIDE_LENGTH / 2)); - break; - case SW: + } + case SW -> { xProperty().bind(rectangleX.subtract(SIDE_LENGTH / 2)); yProperty().bind(rectangleY.add(rectangleH).subtract(SIDE_LENGTH / 2)); - break; - case W: + } + case W -> { xProperty().bind(rectangleX.subtract(SIDE_LENGTH / 2)); yProperty().bind(rectangleY.add(rectangleH.subtract(SIDE_LENGTH).divide(2))); + } } } @@ -440,30 +438,14 @@ private void addResizeFunctionality() { }); switch(compassPoint) { - case NW: - setOnMouseDragged(this::handleMouseDraggedNW); - break; - case N: - setOnMouseDragged(this::handleMouseDraggedN); - break; - case NE: - setOnMouseDragged(this::handleMouseDraggedNE); - break; - case E: - setOnMouseDragged(this::handleMouseDraggedE); - break; - case SE: - setOnMouseDragged(this::handleMouseDraggedSE); - break; - case S: - setOnMouseDragged(this::handleMouseDraggedS); - break; - case SW: - setOnMouseDragged(this::handleMouseDraggedSW); - break; - case W: - setOnMouseDragged(this::handleMouseDraggedW); - break; + case NW -> setOnMouseDragged(this::handleMouseDraggedNW); + case N -> setOnMouseDragged(this::handleMouseDraggedN); + case NE -> setOnMouseDragged(this::handleMouseDraggedNE); + case E -> setOnMouseDragged(this::handleMouseDraggedE); + case SE -> setOnMouseDragged(this::handleMouseDraggedSE); + case S -> setOnMouseDragged(this::handleMouseDraggedS); + case SW -> setOnMouseDragged(this::handleMouseDraggedSW); + case W -> setOnMouseDragged(this::handleMouseDraggedW); } } diff --git a/src/main/java/com/github/mfl28/boundingboxeditor/ui/BoundingPolygonTreeItem.java b/src/main/java/com/github/mfl28/boundingboxeditor/ui/BoundingPolygonTreeItem.java index 49eba84..a83a9c9 100644 --- a/src/main/java/com/github/mfl28/boundingboxeditor/ui/BoundingPolygonTreeItem.java +++ b/src/main/java/com/github/mfl28/boundingboxeditor/ui/BoundingPolygonTreeItem.java @@ -55,12 +55,10 @@ public boolean equals(Object obj) { return true; } - if(!(obj instanceof BoundingPolygonTreeItem)) { + if(!(obj instanceof BoundingPolygonTreeItem other)) { return false; } - BoundingPolygonTreeItem other = (BoundingPolygonTreeItem) obj; - return id == other.id && getValue().equals(other.getValue()) && getChildren().equals(other.getChildren()); } diff --git a/src/main/java/com/github/mfl28/boundingboxeditor/ui/BoundingPolygonView.java b/src/main/java/com/github/mfl28/boundingboxeditor/ui/BoundingPolygonView.java index 733d07c..5e6eb6f 100644 --- a/src/main/java/com/github/mfl28/boundingboxeditor/ui/BoundingPolygonView.java +++ b/src/main/java/com/github/mfl28/boundingboxeditor/ui/BoundingPolygonView.java @@ -122,10 +122,6 @@ public void setConstructing(boolean constructing) { this.constructing.set(constructing); } - public BooleanProperty constructingProperty() { - return constructing; - } - @Override public ToggleGroup getToggleGroup() { return boundingShapeViewData.getToggleGroup(); @@ -167,12 +163,10 @@ public boolean equals(Object obj) { return true; } - if(!(obj instanceof BoundingPolygonView)) { + if(!(obj instanceof BoundingPolygonView other)) { return false; } - BoundingPolygonView other = (BoundingPolygonView) obj; - if(!Objects.equals(boundingShapeViewData, other.boundingShapeViewData) || getPoints().size() != other.getPoints().size()) { return false; @@ -603,10 +597,6 @@ public void setEditing(boolean editing) { this.editing.set(editing); } - public BooleanProperty editingProperty() { - return this.editing; - } - public boolean isSelected() { return selected.get(); } @@ -615,10 +605,6 @@ public void setSelected(boolean selected) { this.selected.set(selected); } - public BooleanProperty selectedProperty() { - return selected; - } - int getPointIndex() { return pointIndex.get(); } diff --git a/src/main/java/com/github/mfl28/boundingboxeditor/ui/BoundingShapeViewData.java b/src/main/java/com/github/mfl28/boundingboxeditor/ui/BoundingShapeViewData.java index 09ff585..65a6d6d 100644 --- a/src/main/java/com/github/mfl28/boundingboxeditor/ui/BoundingShapeViewData.java +++ b/src/main/java/com/github/mfl28/boundingboxeditor/ui/BoundingShapeViewData.java @@ -82,10 +82,6 @@ public void setToggleGroup(ToggleGroup toggleGroup) { this.toggleGroup.set(toggleGroup); } - public boolean isHighlighted() { - return highlighted.get(); - } - /** * Sets the highlighted-status of the bounding-box. * @@ -122,12 +118,10 @@ public boolean equals(Object obj) { return true; } - if(!(obj instanceof BoundingShapeViewData)) { + if(!(obj instanceof BoundingShapeViewData other)) { return false; } - BoundingShapeViewData other = (BoundingShapeViewData) obj; - return Objects.equals(tags, other.tags) && Objects.equals(objectCategory.get(), other.objectCategory.get()); } diff --git a/src/main/java/com/github/mfl28/boundingboxeditor/ui/EditorImagePaneView.java b/src/main/java/com/github/mfl28/boundingboxeditor/ui/EditorImagePaneView.java index cd1ad43..bcd6153 100644 --- a/src/main/java/com/github/mfl28/boundingboxeditor/ui/EditorImagePaneView.java +++ b/src/main/java/com/github/mfl28/boundingboxeditor/ui/EditorImagePaneView.java @@ -47,7 +47,6 @@ import java.io.File; import java.util.Collection; -import java.util.stream.Collectors; /** * A UI-element responsible for displaying the currently selected image on which the @@ -165,8 +164,8 @@ public void resetImageViewSize() { */ public void setZoomableAndPannable(boolean value) { currentBoundingShapes.forEach(viewable -> { - if(!(!value && viewable instanceof BoundingPolygonView && - ((BoundingPolygonView) viewable).isConstructing())) { + if(!(!value && viewable instanceof BoundingPolygonView boundingPolygonView && + boundingPolygonView.isConstructing())) { viewable.getViewData().getBaseShape().setMouseTransparent(value); } }); @@ -229,8 +228,8 @@ public void initializeBoundingPolygon(MouseEvent event) { BoundingPolygonView selectedBoundingPolygon; - if(!(selectedBoundingShape instanceof BoundingPolygonView && - ((BoundingPolygonView) selectedBoundingShape).isConstructing())) { + if(!(selectedBoundingShape instanceof BoundingPolygonView boundingPolygonView && + boundingPolygonView.isConstructing())) { selectedBoundingPolygon = new BoundingPolygonView(selectedCategory.get()); selectedBoundingPolygon.setToggleGroup(boundingShapeSelectionGroup); selectedBoundingPolygon.setConstructing(true); @@ -264,10 +263,6 @@ public boolean isCategorySelected() { return selectedCategory.get() != null; } - public DragAnchor getDragAnchor() { - return dragAnchor; - } - /** * Removes all provided {@link BoundingShapeViewable} objects from the list * of current {@link BoundingShapeViewable} objects. @@ -296,22 +291,20 @@ void setAllCurrentBoundingShapes(Collection boundingShape */ void addBoundingShapesToSceneGroup(Collection boundingShapes) { boundingShapeSceneGroup.getChildren().addAll(boundingShapes.stream() - .map(viewable -> viewable.getViewData() - .getNodeGroup()) - .collect(Collectors.toList())); + .map(viewable -> viewable.getViewData() + .getNodeGroup()).toList()); } /** - * Removes the provided {@link BoundingShapeViewable} objects from a the boundingShapeSceneGroup which is + * Removes the provided {@link BoundingShapeViewable} objects from the boundingShapeSceneGroup which is * a node in the scene-graph. * * @param boundingShapes the objects to remove */ void removeBoundingShapesFromSceneGroup(Collection boundingShapes) { boundingShapeSceneGroup.getChildren().removeAll(boundingShapes.stream() - .map(viewable -> viewable.getViewData() - .getNodeGroup()) - .collect(Collectors.toList())); + .map(viewable -> viewable.getViewData() + .getNodeGroup()).toList()); } /** diff --git a/src/main/java/com/github/mfl28/boundingboxeditor/ui/EditorToolBarView.java b/src/main/java/com/github/mfl28/boundingboxeditor/ui/EditorToolBarView.java index 2ca2a82..98e9646 100644 --- a/src/main/java/com/github/mfl28/boundingboxeditor/ui/EditorToolBarView.java +++ b/src/main/java/com/github/mfl28/boundingboxeditor/ui/EditorToolBarView.java @@ -114,7 +114,7 @@ public class EditorToolBarView extends ToolBar implements View { private final Button predictButton = new Button(PREDICT_BUTTON_TEXT); /** - * Creates a new tool-bar containing controls to navigate images + * Creates a new toolbar containing controls to navigate images * and change image and bounding-shape related settings. */ EditorToolBarView() { diff --git a/src/main/java/com/github/mfl28/boundingboxeditor/ui/EditorView.java b/src/main/java/com/github/mfl28/boundingboxeditor/ui/EditorView.java index 4258a66..98f3d13 100644 --- a/src/main/java/com/github/mfl28/boundingboxeditor/ui/EditorView.java +++ b/src/main/java/com/github/mfl28/boundingboxeditor/ui/EditorView.java @@ -24,7 +24,7 @@ /** * Represents a UI-element containing the {@link EditorImagePaneView} object on which the user can draw/edit - * bounding shape objects. Furthermore this element contains controls to navigate and edit + * bounding shape objects. Furthermore, this element contains controls to navigate and edit * images. * * @see BorderPane @@ -40,7 +40,7 @@ public class EditorView extends BorderPane implements View { /** * Creates a new editor view UI-element containing the {@link EditorImagePaneView} object on which the user can * draw/edit - * bounding shape objects. Furthermore this element contains controls to navigate and edit + * bounding shape objects. Furthermore, this element contains controls to navigate and edit * images. */ EditorView() { diff --git a/src/main/java/com/github/mfl28/boundingboxeditor/ui/EditorsSplitPaneView.java b/src/main/java/com/github/mfl28/boundingboxeditor/ui/EditorsSplitPaneView.java index 03090e2..dc871fb 100644 --- a/src/main/java/com/github/mfl28/boundingboxeditor/ui/EditorsSplitPaneView.java +++ b/src/main/java/com/github/mfl28/boundingboxeditor/ui/EditorsSplitPaneView.java @@ -19,7 +19,6 @@ package com.github.mfl28.boundingboxeditor.ui; import com.github.mfl28.boundingboxeditor.controller.Controller; -import com.github.mfl28.boundingboxeditor.model.data.ObjectCategory; import com.github.mfl28.boundingboxeditor.utils.ColorUtils; import com.github.mfl28.boundingboxeditor.utils.UiUtils; import javafx.geometry.Orientation; @@ -101,16 +100,6 @@ public TextField getCategoryNameTextField() { return categoryNameTextField; } - /** - * Returns the button which allows the user to add a - * {@link ObjectCategory}. - * - * @return the button - */ - public Button getAddCategoryButton() { - return addCategoryButton; - } - /** * Returns the {@link ObjectTreeView} object which is responsible * for displaying currently existing bounding-shapes. It also provides diff --git a/src/main/java/com/github/mfl28/boundingboxeditor/ui/IconButton.java b/src/main/java/com/github/mfl28/boundingboxeditor/ui/IconButton.java index 7bc0fba..c37093f 100644 --- a/src/main/java/com/github/mfl28/boundingboxeditor/ui/IconButton.java +++ b/src/main/java/com/github/mfl28/boundingboxeditor/ui/IconButton.java @@ -30,7 +30,7 @@ class IconButton extends Button { * Creates a new icon-button. * * @param iconCssId the css-id-string of the button (in case of {@link IconType}.BACKGROUND) or the - * id of the {@link Region} containing the icon in case of {@link IconType}.GRAPHIC) + * id of the {@link Region} containing the icon (in case of {@link IconType}.GRAPHIC) * @param iconType indicates the way the icon should be embedded in the button: *
    *
  • {@link IconType}.BACKGROUND: the icon will be directly set as the shape of the diff --git a/src/main/java/com/github/mfl28/boundingboxeditor/ui/ImageFileExplorerView.java b/src/main/java/com/github/mfl28/boundingboxeditor/ui/ImageFileExplorerView.java index 5621562..e33a592 100644 --- a/src/main/java/com/github/mfl28/boundingboxeditor/ui/ImageFileExplorerView.java +++ b/src/main/java/com/github/mfl28/boundingboxeditor/ui/ImageFileExplorerView.java @@ -31,7 +31,6 @@ import java.io.File; import java.util.List; -import java.util.stream.Collectors; /** * UI-element that contains the controls to view, select and search image-files. @@ -73,7 +72,7 @@ public void setImageFiles(List imageFiles) { ObservableList imageInfoItems = FXCollections.unmodifiableObservableList( FXCollections.observableList(imageFiles.stream() .map(ImageFileListView.FileInfo::new) - .collect(Collectors.toList())) + .toList()) ); imageFileListView.setItems(imageInfoItems); diff --git a/src/main/java/com/github/mfl28/boundingboxeditor/ui/ImageFileListView.java b/src/main/java/com/github/mfl28/boundingboxeditor/ui/ImageFileListView.java index 742a6f3..dfdd8da 100644 --- a/src/main/java/com/github/mfl28/boundingboxeditor/ui/ImageFileListView.java +++ b/src/main/java/com/github/mfl28/boundingboxeditor/ui/ImageFileListView.java @@ -38,7 +38,6 @@ import java.io.File; import java.util.Objects; -import java.util.stream.Collectors; /** * A UI-element used for displaying and navigating/selecting the loaded image-files. @@ -85,7 +84,7 @@ private void setUpInternalListeners() { // Triggers loading of the new images into the cache. imageCache.getAll(newValue.stream() .map(fileInfo -> fileInfo.getFile().toURI().toString()) - .collect(Collectors.toList())); + .toList()); } } }); @@ -126,12 +125,10 @@ public boolean equals(Object o) { return true; } - if(!(o instanceof FileInfo)) { + if(!(o instanceof FileInfo fileInfo)) { return false; } - FileInfo fileInfo = (FileInfo) o; - return Objects.equals(file, fileInfo.file) && Objects.equals(hasAssignedBoundingBoxes, fileInfo.hasAssignedBoundingBoxes); } diff --git a/src/main/java/com/github/mfl28/boundingboxeditor/ui/MainView.java b/src/main/java/com/github/mfl28/boundingboxeditor/ui/MainView.java index 947ed95..3059d3e 100644 --- a/src/main/java/com/github/mfl28/boundingboxeditor/ui/MainView.java +++ b/src/main/java/com/github/mfl28/boundingboxeditor/ui/MainView.java @@ -101,7 +101,7 @@ public static void displayErrorAlert(String title, String content, Window owner) } /** - * Displays a a dialog with 'Yes', 'No' and 'Cancel' buttons and returns the chosen option. + * Displays a dialog with 'Yes', 'No' and 'Cancel' buttons and returns the chosen option. * * @param title The title of the dialog window * @param content The content text of the dialog window @@ -118,7 +118,7 @@ content, new ButtonType("Yes", ButtonBar.ButtonData.YES), } /** - * Displays a a dialog with 'Yes', 'No' buttons and returns the chosen option. + * Displays a dialog with 'Yes', 'No' buttons and returns the chosen option. * * @param title The title of the dialog window * @param content The content text of the dialog window @@ -224,31 +224,22 @@ public static void displayIOResultErrorInfoAlert(IOResult ioResult, Window owner .count(); switch(ioResult.getOperationType()) { - case ANNOTATION_IMPORT: - displayAnnotationImportInfoAlert(ioResult, errorTable, numErrorEntries, owner); - break; - case ANNOTATION_SAVING: - MainView.displayInfoAlert(ANNOTATION_SAVING_ERROR_REPORT_TITLE, - "There were errors while saving annotations.", - numErrorEntries + " image-annotation file" - + (numErrorEntries > 1 ? "s" : "") + " could not be saved.", - errorTable, owner); - break; - case IMAGE_METADATA_LOADING: - displayImageMetadataLoadingInfoAlert(ioResult, errorTable, numErrorEntries, owner); - break; - case BOUNDING_BOX_PREDICTION: - MainView.displayInfoAlert("Bounding Box Prediction Error Report", - "There were errors while performing the prediction", - "Bounding box predictions for " + numErrorEntries + " image file" + - (numErrorEntries > 1 ? "s" : "") + " could not be loaded.", - errorTable, owner); - break; - case MODEL_NAME_FETCHING: - MainView.displayInfoAlert("Model Fetching Error Report", - "There were errors while fetching model names from the server", - null, errorTable, owner); - break; + case ANNOTATION_IMPORT -> displayAnnotationImportInfoAlert(ioResult, errorTable, numErrorEntries, owner); + case ANNOTATION_SAVING -> MainView.displayInfoAlert(ANNOTATION_SAVING_ERROR_REPORT_TITLE, + "There were errors while saving annotations.", + numErrorEntries + " image-annotation file" + + (numErrorEntries > 1 ? "s" : "") + " could not be saved.", + errorTable, owner); + case IMAGE_METADATA_LOADING -> + displayImageMetadataLoadingInfoAlert(ioResult, errorTable, numErrorEntries, owner); + case BOUNDING_BOX_PREDICTION -> MainView.displayInfoAlert("Bounding Box Prediction Error Report", + "There were errors while performing the prediction", + "Bounding box predictions for " + numErrorEntries + " image file" + + (numErrorEntries > 1 ? "s" : "") + " could not be loaded.", + errorTable, owner); + case MODEL_NAME_FETCHING -> MainView.displayInfoAlert("Model Fetching Error Report", + "There were errors while fetching model names from the server", + null, errorTable, owner); } } @@ -532,8 +523,8 @@ public void displaySettingsDialog(Controller controller, Window owner) { public Optional getSettingsWindow() { return Window.getWindows() .stream() - .filter(window -> window instanceof Stage - && ((Stage) window).getTitle().equals(SettingsDialogView.SETTINGS_TITLE)) + .filter(window -> window instanceof Stage stage + && stage.getTitle().equals(SettingsDialogView.SETTINGS_TITLE)) .findFirst(); } diff --git a/src/main/java/com/github/mfl28/boundingboxeditor/ui/ObjectCategoryTreeItem.java b/src/main/java/com/github/mfl28/boundingboxeditor/ui/ObjectCategoryTreeItem.java index 52b7fd7..8b1015d 100644 --- a/src/main/java/com/github/mfl28/boundingboxeditor/ui/ObjectCategoryTreeItem.java +++ b/src/main/java/com/github/mfl28/boundingboxeditor/ui/ObjectCategoryTreeItem.java @@ -67,12 +67,10 @@ public boolean equals(Object obj) { return true; } - if(!(obj instanceof ObjectCategoryTreeItem)) { + if(!(obj instanceof ObjectCategoryTreeItem other)) { return false; } - ObjectCategoryTreeItem other = (ObjectCategoryTreeItem) obj; - return objectCategory.equals(other.objectCategory) && getChildren().equals(other.getChildren()); } @@ -96,8 +94,8 @@ public void setIconToggledOn(boolean toggledOn) { toggleIcon.setToggledOn(toggledOn); for(TreeItem child : getChildren()) { - if(child instanceof BoundingShapeTreeItem) { - ((BoundingShapeTreeItem) child).setIconToggledOn(toggledOn); + if(child instanceof BoundingShapeTreeItem boundingShapeTreeItem) { + boundingShapeTreeItem.setIconToggledOn(toggledOn); } } } @@ -164,8 +162,8 @@ private void setUpInternalListeners() { int numToggledChildrenToRemove = 0; for(TreeItem treeItem : c.getRemoved()) { - if(treeItem instanceof BoundingShapeTreeItem && - ((BoundingShapeTreeItem) treeItem).isIconToggledOn()) { + if(treeItem instanceof BoundingShapeTreeItem boundingShapeTreeItem && + boundingShapeTreeItem.isIconToggledOn()) { numToggledChildrenToRemove++; } } @@ -187,8 +185,8 @@ private void setUpInternalListeners() { private void detachChildId(int id) { List> children = getChildren(); for(int i = id; i < children.size(); ++i) { - if(children.get(i) instanceof BoundingShapeTreeItem) { - ((BoundingShapeTreeItem) children.get(i)).setId(i); + if(children.get(i) instanceof BoundingShapeTreeItem boundingShapeTreeItem) { + boundingShapeTreeItem.setId(i); } } } diff --git a/src/main/java/com/github/mfl28/boundingboxeditor/ui/ObjectTreeElementCell.java b/src/main/java/com/github/mfl28/boundingboxeditor/ui/ObjectTreeElementCell.java index 6809308..48e6898 100644 --- a/src/main/java/com/github/mfl28/boundingboxeditor/ui/ObjectTreeElementCell.java +++ b/src/main/java/com/github/mfl28/boundingboxeditor/ui/ObjectTreeElementCell.java @@ -117,8 +117,7 @@ protected void updateItem(Object newCellObject, boolean empty) { return; } - if(oldCellObject instanceof Shape) { - Shape oldItem = (Shape) oldCellObject; + if(oldCellObject instanceof Shape oldItem) { // Remove the old item's context-menu event-handler. oldItem.removeEventHandler(ContextMenuEvent.CONTEXT_MENU_REQUESTED, showContextMenuEventHandler); oldItem.visibleProperty().removeListener(boundingShapeVisibilityListener); @@ -151,13 +150,13 @@ protected void updateItem(Object newCellObject, boolean empty) { // Register the contextMenu with the cell. setContextMenu(contextMenu); - if(newCellObject instanceof Shape) { + if(newCellObject instanceof Shape shape) { // Register the contextMenu with the shape associated with the cell. This // allows to display the contextMenu by right-clicking on the shape itself. - ((Shape) newCellObject).setOnContextMenuRequested(showContextMenuEventHandler); + shape.setOnContextMenuRequested(showContextMenuEventHandler); // The context menu should be hidden when the shape associated with this cell // is hidden. - ((Shape) newCellObject).visibleProperty().addListener(boundingShapeVisibilityListener); + shape.visibleProperty().addListener(boundingShapeVisibilityListener); } } } @@ -232,7 +231,7 @@ PopOver getPopOver() { } /** - * Returns the ImageView associated withe this cell's + * Returns the ImageView associated with this cell's * popover. * * @return the imageview @@ -326,13 +325,13 @@ private HBox createContentBox() { content.setId(TREE_CELL_CONTENT_ID); content.setAlignment(Pos.CENTER_LEFT); - if(treeItem instanceof BoundingShapeTreeItem) { + if(treeItem instanceof BoundingShapeTreeItem boundingShapeTreeItem) { final BoundingShapeViewData boundingShapeViewData = ((BoundingShapeViewable) treeItem.getValue()).getViewData(); nameText.textProperty().bind(boundingShapeViewData.getObjectCategory() .nameProperty().concat(" ") - .concat(((BoundingShapeTreeItem) treeItem).getId())); + .concat(boundingShapeTreeItem.getId())); tagIconRegion.visibleProperty().bind(Bindings.size(boundingShapeViewData.getTags()).greaterThan(0)); content.getChildren().add(tagIconRegion); } else if(treeItem instanceof ObjectCategoryTreeItem) { @@ -354,9 +353,9 @@ private Region createTagIconRegion() { @SuppressWarnings("UnnecessaryLambda") private EventHandler createShowContextMenuEventHandler() { return event -> { - if(getItem() instanceof Shape - && getItem() instanceof Toggle && ((Toggle) getItem()).isSelected()) { - contextMenu.show((Shape) getItem(), event.getScreenX(), event.getScreenY()); + if(getItem() instanceof Shape shape + && getItem() instanceof Toggle toggle && toggle.isSelected()) { + contextMenu.show(shape, event.getScreenX(), event.getScreenY()); } }; } @@ -420,16 +419,16 @@ private MenuItem createChangeObjectCategoryMenuItem() { private void handleHide(ActionEvent event) { final TreeItem treeItem = getTreeItem(); - if(treeItem instanceof IconToggleable) { - ((IconToggleable) treeItem).setIconToggledOn(false); + if(treeItem instanceof IconToggleable iconToggleable) { + iconToggleable.setIconToggledOn(false); } } private void handleShow(ActionEvent event) { final TreeItem treeItem = getTreeItem(); - if(treeItem instanceof IconToggleable) { - ((IconToggleable) treeItem).setIconToggledOn(true); + if(treeItem instanceof IconToggleable iconToggleable) { + iconToggleable.setIconToggledOn(true); } } diff --git a/src/main/java/com/github/mfl28/boundingboxeditor/ui/ObjectTreeView.java b/src/main/java/com/github/mfl28/boundingboxeditor/ui/ObjectTreeView.java index 59dfafc..05ae981 100644 --- a/src/main/java/com/github/mfl28/boundingboxeditor/ui/ObjectTreeView.java +++ b/src/main/java/com/github/mfl28/boundingboxeditor/ui/ObjectTreeView.java @@ -28,7 +28,6 @@ import org.apache.commons.collections4.IteratorUtils; import java.util.*; -import java.util.stream.Collectors; /** * The bounding-box tree UI-element. Shows information about the currently existing bounding shape objects @@ -81,13 +80,13 @@ public List extractCurrentBoundingShapeData() { .flatMap(Collection::stream) .filter(child -> child.getValue() instanceof BoundingShapeDataConvertible) .map(this::treeItemToBoundingShapeData) - .collect(Collectors.toList()); + .toList(); } /** * Sets the toggle-icon-state of all tree-items. * - * @param toggleState true to to toggle on, otherwise off + * @param toggleState true to toggle on, otherwise off */ public void setToggleIconStateForAllTreeItems(boolean toggleState) { for(TreeItem child : getRoot().getChildren()) { @@ -103,8 +102,8 @@ public void setToggleIconStateForAllTreeItems(boolean toggleState) { public void setToggleIconStateForSelectedObjectTreeItem(boolean toggleState) { final TreeItem selectedTreeItem = getSelectionModel().getSelectedItem(); - if(selectedTreeItem instanceof IconToggleable) { - ((IconToggleable) selectedTreeItem).setIconToggledOn(toggleState); + if(selectedTreeItem instanceof IconToggleable iconToggleable) { + iconToggleable.setIconToggledOn(toggleState); } } @@ -119,12 +118,12 @@ public void setToggleIconStateForNonSelectedObjectTreeItems(boolean toggleState) } void setToggleIconStateForAllTreeItemsExcept(TreeItem exemption, boolean toggleState) { - if(exemption instanceof IconToggleable) { - final boolean selectedItemToggledOn = ((IconToggleable) exemption).isIconToggledOn(); + if(exemption instanceof IconToggleable iconToggleable) { + final boolean selectedItemToggledOn = iconToggleable.isIconToggledOn(); setToggleIconStateForAllTreeItems(toggleState); - ((IconToggleable) exemption).setIconToggledOn(selectedItemToggledOn); + iconToggleable.setIconToggledOn(selectedItemToggledOn); } } @@ -179,7 +178,7 @@ List extractBoundingShapesAndBuildTreeFromAnnotation(Imag return IteratorUtils.toList(new BoundingShapeTreeItemIterator(getRoot())).stream() .filter(treeItem -> treeItem.getValue() instanceof BoundingShapeViewable) .map(item -> (BoundingShapeViewable) item.getValue()) - .collect(Collectors.toList()); + .toList(); } /** @@ -200,7 +199,7 @@ static List getBoundingShapesRecursively(TreeItem return IteratorUtils.toList(iterator).stream() .filter(child -> child.getValue() instanceof BoundingShapeViewable) .map(child -> (BoundingShapeViewable) child.getValue()) - .collect(Collectors.toList()); + .toList(); } /** @@ -262,8 +261,7 @@ private ObjectCategoryTreeItem findObjectCategoryTreeItem(TreeItem root, private void setUpInternalListeners() { skinProperty().addListener((observable, oldValue, newValue) -> { - if(newValue instanceof TreeViewSkin) { - var skin = (TreeViewSkin) newValue; + if(newValue instanceof TreeViewSkin skin) { var childNodes = skin.getChildren(); if(childNodes != null && !childNodes.isEmpty()) { @@ -305,7 +303,7 @@ private BoundingShapeData treeItemToBoundingShapeData(TreeItem treeItem) .map(TreeItem::getChildren) .flatMap(Collection::stream) .map(this::treeItemToBoundingShapeData) - .collect(Collectors.toList()); + .toList(); boundingShapeData.setParts(parts); } @@ -316,10 +314,9 @@ private BoundingShapeData treeItemToBoundingShapeData(TreeItem treeItem) private void detachTreeItemFromParent(TreeItem itemToDetach) { TreeItem itemParent = itemToDetach.getParent(); - if(itemParent instanceof ObjectCategoryTreeItem - && itemToDetach instanceof BoundingShapeTreeItem) { - ((ObjectCategoryTreeItem) itemParent) - .detachBoundingShapeTreeItemChild((BoundingShapeTreeItem) itemToDetach); + if(itemParent instanceof ObjectCategoryTreeItem objectCategoryTreeItem + && itemToDetach instanceof BoundingShapeTreeItem boundingShapeTreeItem) { + objectCategoryTreeItem.detachBoundingShapeTreeItemChild(boundingShapeTreeItem); } else { itemParent.getChildren().remove(itemToDetach); } @@ -333,8 +330,8 @@ private void detachTreeItemFromParent(TreeItem itemToDetach) { private void attachTreeItemToTarget(TreeItem treeItemToAttach, TreeItem targetItem) { ObjectCategory draggedItemCategory; - if(treeItemToAttach instanceof ObjectCategoryTreeItem) { - draggedItemCategory = ((ObjectCategoryTreeItem) treeItemToAttach).getObjectCategory(); + if(treeItemToAttach instanceof ObjectCategoryTreeItem objectCategoryTreeItem) { + draggedItemCategory = objectCategoryTreeItem.getObjectCategory(); } else if(treeItemToAttach instanceof BoundingShapeTreeItem) { draggedItemCategory = ((BoundingShapeViewable) treeItemToAttach.getValue()).getViewData().getObjectCategory(); diff --git a/src/main/java/com/github/mfl28/boundingboxeditor/ui/TagScrollPaneView.java b/src/main/java/com/github/mfl28/boundingboxeditor/ui/TagScrollPaneView.java index d2acd78..3746d0d 100644 --- a/src/main/java/com/github/mfl28/boundingboxeditor/ui/TagScrollPaneView.java +++ b/src/main/java/com/github/mfl28/boundingboxeditor/ui/TagScrollPaneView.java @@ -29,8 +29,6 @@ import javafx.scene.layout.FlowPane; import javafx.scene.layout.HBox; -import java.util.stream.Collectors; - /** * A UI-element used to display and edit tags associated with a bounding-shape. * @@ -106,7 +104,7 @@ private void setUpInternalListeners() { tags.addListener((observable, oldValue, newValue) -> { if(oldValue == newValue) { // Listeners have to be updated exactly once after a new tag-list was set. If - // the tag-list reference has not changed nothing need to be done. + // the tag-list reference has not changed, nothing needs to be done. return; } @@ -116,7 +114,7 @@ private void setUpInternalListeners() { } if(newValue != null) { - tagFlowPane.getChildren().addAll(0, newValue.stream().map(TagBox::new).collect(Collectors.toList())); + tagFlowPane.getChildren().addAll(0, newValue.stream().map(TagBox::new).toList()); newValue.addListener(tagsListener); tagInputField.setDisable(false); } else { @@ -157,9 +155,8 @@ private ListChangeListener createTagsListener() { if(change.wasAdded()) { tagFlowPane.getChildren().addAll(change.getFrom(), - change.getAddedSubList().stream() - .map(TagBox::new) - .collect(Collectors.toList())); + change.getAddedSubList().stream() + .map(TagBox::new).toList()); } } }; diff --git a/src/main/java/com/github/mfl28/boundingboxeditor/ui/View.java b/src/main/java/com/github/mfl28/boundingboxeditor/ui/View.java index 8b925fc..8bed169 100644 --- a/src/main/java/com/github/mfl28/boundingboxeditor/ui/View.java +++ b/src/main/java/com/github/mfl28/boundingboxeditor/ui/View.java @@ -33,13 +33,11 @@ public interface View { * * @param controller the controller serving as the even-handler */ - default void connectToController(Controller controller) { - } + default void connectToController(Controller controller) {} /** * Resets the View. Classes implementing the View interface can optionally * implement this method to reset their state/data. */ - default void reset() { - } + default void reset() {} } diff --git a/src/main/java/com/github/mfl28/boundingboxeditor/ui/WorkspaceSplitPaneView.java b/src/main/java/com/github/mfl28/boundingboxeditor/ui/WorkspaceSplitPaneView.java index 61d9746..7ec2808 100644 --- a/src/main/java/com/github/mfl28/boundingboxeditor/ui/WorkspaceSplitPaneView.java +++ b/src/main/java/com/github/mfl28/boundingboxeditor/ui/WorkspaceSplitPaneView.java @@ -97,10 +97,6 @@ public void reset() { editorsSplitPane.reset(); } - public boolean isShowObjectPopover() { - return showObjectPopover.get(); - } - public BooleanProperty showObjectPopoverProperty() { return showObjectPopover; } @@ -174,9 +170,9 @@ void removeBoundingShapeWithTreeItemRecursively(TreeItem treeItem) { if(treeItem instanceof ObjectCategoryTreeItem) { treeItem.getParent().getChildren().remove(treeItem); - } else if(treeItem instanceof BoundingShapeTreeItem) { + } else if(treeItem instanceof BoundingShapeTreeItem boundingShapeTreeItem) { ObjectCategoryTreeItem parentTreeItem = (ObjectCategoryTreeItem) treeItem.getParent(); - parentTreeItem.detachBoundingShapeTreeItemChild((BoundingShapeTreeItem) treeItem); + parentTreeItem.detachBoundingShapeTreeItemChild(boundingShapeTreeItem); if(parentTreeItem.getChildren().isEmpty()) { parentTreeItem.getParent().getChildren().remove(parentTreeItem); @@ -259,10 +255,10 @@ private void setUpEditorListeners() { .getBoundingShapeSelectionGroup() .selectedToggleProperty() .addListener((observable, oldValue, newValue) -> { - if(newValue instanceof BoundingShapeViewable) { + if(newValue instanceof BoundingShapeViewable boundingShapeViewable) { getEditorsSplitPane().getObjectTree() .getSelectionModel() - .select(((BoundingShapeViewable) newValue).getViewData().getTreeItem()); + .select(boundingShapeViewable.getViewData().getTreeItem()); } }); @@ -519,8 +515,8 @@ private void handlePopoverTimerFinished(ObjectTreeElementCell cell) { imageView.setFitWidth(scaleWidth); imageView.setFitHeight(scaleHeight); - if(cell.getItem() instanceof BoundingPolygonView) { - final List points = ((BoundingPolygonView) cell.getItem()) + if(cell.getItem() instanceof BoundingPolygonView boundingPolygonView) { + final List points = boundingPolygonView .getMinMaxScaledPoints(scaleWidth, scaleHeight); final Polygon polygon = new Polygon(); diff --git a/src/main/java/com/github/mfl28/boundingboxeditor/ui/statusevents/BoundingBoxPredictionSuccessfulEvent.java b/src/main/java/com/github/mfl28/boundingboxeditor/ui/statusevents/BoundingBoxPredictionSuccessfulEvent.java index 57d79d0..9c9c15c 100644 --- a/src/main/java/com/github/mfl28/boundingboxeditor/ui/statusevents/BoundingBoxPredictionSuccessfulEvent.java +++ b/src/main/java/com/github/mfl28/boundingboxeditor/ui/statusevents/BoundingBoxPredictionSuccessfulEvent.java @@ -33,7 +33,7 @@ public BoundingBoxPredictionSuccessfulEvent(BoundingBoxPredictionResult ioResult private static String createMessage(BoundingBoxPredictionResult ioResult) { int predictedBoundingBoxes = ioResult.getImageAnnotationData() - .getCategoryNameToBoundingShapeCountMap() + .categoryNameToBoundingShapeCountMap() .values() .stream() .reduce(Integer::sum) diff --git a/src/main/java/com/github/mfl28/boundingboxeditor/ui/statusevents/ImageAnnotationsImportingSuccessfulEvent.java b/src/main/java/com/github/mfl28/boundingboxeditor/ui/statusevents/ImageAnnotationsImportingSuccessfulEvent.java index 033d398..15d6bc3 100644 --- a/src/main/java/com/github/mfl28/boundingboxeditor/ui/statusevents/ImageAnnotationsImportingSuccessfulEvent.java +++ b/src/main/java/com/github/mfl28/boundingboxeditor/ui/statusevents/ImageAnnotationsImportingSuccessfulEvent.java @@ -18,10 +18,6 @@ */ package com.github.mfl28.boundingboxeditor.ui.statusevents; -/** - * Represents the event of a successful bounding box prediction. - */ - import com.github.mfl28.boundingboxeditor.model.io.results.IOResult; /** diff --git a/src/main/java/com/github/mfl28/boundingboxeditor/utils/ColorUtils.java b/src/main/java/com/github/mfl28/boundingboxeditor/utils/ColorUtils.java index 6c9e951..f22c4cf 100644 --- a/src/main/java/com/github/mfl28/boundingboxeditor/utils/ColorUtils.java +++ b/src/main/java/com/github/mfl28/boundingboxeditor/utils/ColorUtils.java @@ -45,7 +45,7 @@ public static Color createRandomColor() { * @param color The color * @return the hexadecimal representation of the color * - * Source: https://stackoverflow.com/a/56733608/13302206 + * Source: ... */ public static String colorToHexString(Color color) { return "#" + (format(color.getRed()) + format(color.getGreen()) + format(color.getBlue())) @@ -53,7 +53,7 @@ public static String colorToHexString(Color color) { } /** - * Source: https://stackoverflow.com/a/56733608/13302206 + * Source: ... */ private static String format(double value) { String hexString = Integer.toHexString((int) Math.round(value * 255)); diff --git a/src/main/java/com/github/mfl28/boundingboxeditor/utils/UiUtils.java b/src/main/java/com/github/mfl28/boundingboxeditor/utils/UiUtils.java index 67193ff..f753a77 100644 --- a/src/main/java/com/github/mfl28/boundingboxeditor/utils/UiUtils.java +++ b/src/main/java/com/github/mfl28/boundingboxeditor/utils/UiUtils.java @@ -37,7 +37,7 @@ private UiUtils() { /*** * Creates a pane that fills any available horizontal space - * in it's parent. + * in its parent. * @return pane */ public static Pane createHSpacer() { @@ -85,7 +85,7 @@ public static Tooltip createFocusTooltip(KeyCombination keyCombination) { */ public static TextFormatter createDecimalFormatter() { return new TextFormatter<>(change -> { - if(change.getText().matches("[0-9]*")) { + if(change.getText().matches("\\d*")) { return change; } @@ -95,7 +95,7 @@ public static TextFormatter createDecimalFormatter() { public static TextFormatter createFloatFormatter() { return new TextFormatter<>(change -> { - if(!change.getControlNewText().equals(".") && change.getControlNewText().matches("[0-9]*\\.?[0-9]*")) { + if(!change.getControlNewText().equals(".") && change.getControlNewText().matches("\\d*\\.?\\d*")) { return change; } diff --git a/src/test/java/com/github/mfl28/boundingboxeditor/controller/ControllerTests.java b/src/test/java/com/github/mfl28/boundingboxeditor/controller/ControllerTests.java index c27e3cf..66e406f 100644 --- a/src/test/java/com/github/mfl28/boundingboxeditor/controller/ControllerTests.java +++ b/src/test/java/com/github/mfl28/boundingboxeditor/controller/ControllerTests.java @@ -605,7 +605,7 @@ void onLoadAnnotation_YOLO_WhenAnnotationFileContainsErrors_ShouldNotLoadInvalid verifyThat(counts.size(), Matchers.equalTo(1), saveScreenshot(testinfo)); verifyThat(counts.get("Ship"), Matchers.equalTo(1), saveScreenshot(testinfo)); verifyThat(mainView.getCurrentBoundingShapes(), Matchers.hasSize(0), saveScreenshot(testinfo)); - verifyThat(model.createImageAnnotationData().getImageAnnotations(), Matchers.hasSize(1), + verifyThat(model.createImageAnnotationData().imageAnnotations(), Matchers.hasSize(1), saveScreenshot(testinfo)); verifyThat(mainView.getStatusBar().getCurrentEventMessage(), @@ -749,7 +749,7 @@ void onLoadAnnotation_PVOC_WhenFileHasMissingCriticalElement_ShouldNotLoadAnyBou verifyThat(model.getCategoryToAssignedBoundingShapesCountMap().isEmpty(), Matchers.is(true), saveScreenshot(testinfo)); verifyThat(model.getObjectCategories(), Matchers.empty(), saveScreenshot(testinfo)); - verifyThat(model.createImageAnnotationData().getImageAnnotations(), Matchers.empty(), saveScreenshot(testinfo)); + verifyThat(model.createImageAnnotationData().imageAnnotations(), Matchers.empty(), saveScreenshot(testinfo)); verifyThat(mainView.getCurrentBoundingShapes(), Matchers.empty(), saveScreenshot(testinfo)); // Should not have changed the status message. @@ -1189,7 +1189,7 @@ private void userChoosesNotToSaveExistingAnnotationsOnAnnotationImport(FxRobot r verifyThat(model.getCategoryToAssignedBoundingShapesCountMap().size(), Matchers.equalTo(3), saveScreenshot(testinfo)); verifyThat(model.getObjectCategories(), Matchers.hasSize(3), saveScreenshot(testinfo)); - verifyThat(model.createImageAnnotationData().getImageAnnotations(), Matchers.hasSize(1), + verifyThat(model.createImageAnnotationData().imageAnnotations(), Matchers.hasSize(1), saveScreenshot(testinfo)); verifyThat(mainView.getCurrentBoundingShapes(), Matchers.empty(), saveScreenshot(testinfo)); verifyThat(mainView.getObjectTree().getRoot().getChildren().size(), Matchers.equalTo(0), @@ -1235,7 +1235,7 @@ private void userChoosesYesOnAnnotationImportDialogSubTest(FxRobot robot, Boundi verifyThat(model.getCategoryToAssignedBoundingShapesCountMap().size(), Matchers.equalTo(4), saveScreenshot(testinfo)); verifyThat(model.getObjectCategories(), Matchers.hasSize(4), saveScreenshot(testinfo)); - verifyThat(model.createImageAnnotationData().getImageAnnotations(), Matchers.hasSize(2), + verifyThat(model.createImageAnnotationData().imageAnnotations(), Matchers.hasSize(2), saveScreenshot(testinfo)); verifyThat(mainView.getImageFileListView().getItems().get(0).isHasAssignedBoundingShapes(), diff --git a/src/test/java/com/github/mfl28/boundingboxeditor/model/data/BoundingBoxDataTest.java b/src/test/java/com/github/mfl28/boundingboxeditor/model/data/BoundingBoxDataTest.java new file mode 100644 index 0000000..543c4f1 --- /dev/null +++ b/src/test/java/com/github/mfl28/boundingboxeditor/model/data/BoundingBoxDataTest.java @@ -0,0 +1,48 @@ +/* + * Copyright (C) 2022 Markus Fleischhacker + * + * This file is part of Bounding Box Editor + * + * Bounding Box Editor is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Bounding Box Editor is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Bounding Box Editor. If not, see . + */ +package com.github.mfl28.boundingboxeditor.model.data; + +import javafx.geometry.BoundingBox; +import javafx.scene.paint.Color; +import nl.jqno.equalsverifier.EqualsVerifier; +import org.junit.jupiter.api.Tag; +import org.junit.jupiter.api.Test; + +import java.util.Collections; + +@Tag("unit") +class BoundingBoxDataTest { + @Test + void checkEqualsContract() { + EqualsVerifier.simple().forClass(BoundingBoxData.class) + .withPrefabValues(BoundingShapeData.class, + new BoundingBoxData(new ObjectCategory("foo", Color.RED), + new BoundingBox(0, 0, 10, 20), + Collections.emptyList()), + new BoundingBoxData(new ObjectCategory("bar", Color.BLUE), + new BoundingBox(0, 0, 30, 40), + Collections.emptyList()) + ) + .withPrefabValues(ObjectCategory.class, + new ObjectCategory("foo", Color.RED), + new ObjectCategory("bar", Color.BLUE)) + .verify(); + } + +} \ No newline at end of file diff --git a/src/test/java/com/github/mfl28/boundingboxeditor/model/data/BoundingPolygonDataTest.java b/src/test/java/com/github/mfl28/boundingboxeditor/model/data/BoundingPolygonDataTest.java new file mode 100644 index 0000000..f5d76db --- /dev/null +++ b/src/test/java/com/github/mfl28/boundingboxeditor/model/data/BoundingPolygonDataTest.java @@ -0,0 +1,62 @@ +/* + * Copyright (C) 2022 Markus Fleischhacker + * + * This file is part of Bounding Box Editor + * + * Bounding Box Editor is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Bounding Box Editor is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Bounding Box Editor. If not, see . + */ +package com.github.mfl28.boundingboxeditor.model.data; + +import javafx.geometry.BoundingBox; +import javafx.scene.paint.Color; +import nl.jqno.equalsverifier.EqualsVerifier; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Tag; +import org.junit.jupiter.api.Test; + +import java.util.Collections; +import java.util.List; + +@Tag("unit") +class BoundingPolygonDataTest { + @Test + void checkEqualsContract() { + EqualsVerifier.simple().forClass(BoundingPolygonData.class) + .withPrefabValues(BoundingShapeData.class, + new BoundingBoxData(new ObjectCategory("foo", Color.RED), + new BoundingBox(0, 0, 10, 20), + Collections.emptyList()), + new BoundingBoxData(new ObjectCategory("bar", Color.BLUE), + new BoundingBox(0, 0, 30, 40), + Collections.emptyList()) + ) + .withPrefabValues(ObjectCategory.class, + new ObjectCategory("foo", Color.RED), + new ObjectCategory("bar", Color.BLUE)) + .verify(); + } + + @Test + void onGetRelativePointsInImage_ShouldReturnPointsList() { + List points = List.of(1.0, 2.0, 3.0, 4.0); + + final BoundingPolygonData boundingPolygonData = new BoundingPolygonData( + new ObjectCategory("foo", Color.RED), + points, + Collections.emptyList()); + + Assertions.assertEquals(points, boundingPolygonData.getRelativePointsInImage()); + } + +} \ No newline at end of file diff --git a/src/test/java/com/github/mfl28/boundingboxeditor/model/data/ImageMetaDataTest.java b/src/test/java/com/github/mfl28/boundingboxeditor/model/data/ImageMetaDataTest.java new file mode 100644 index 0000000..709b24c --- /dev/null +++ b/src/test/java/com/github/mfl28/boundingboxeditor/model/data/ImageMetaDataTest.java @@ -0,0 +1,39 @@ +/* + * Copyright (C) 2022 Markus Fleischhacker + * + * This file is part of Bounding Box Editor + * + * Bounding Box Editor is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Bounding Box Editor is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Bounding Box Editor. If not, see . + */ +package com.github.mfl28.boundingboxeditor.model.data; + +import nl.jqno.equalsverifier.EqualsVerifier; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Tag; +import org.junit.jupiter.api.Test; + + +@Tag("unit") +class ImageMetaDataTest { + @Test + void checkEqualsContract() { + EqualsVerifier.simple().forClass(ImageMetaData.class).verify(); + } + + @Test + void onGetDimensionsString_WhenNoDetailsPresent_ShouldReturnCorrectRepresentation() { + final ImageMetaData imageMetaData = new ImageMetaData("test"); + Assertions.assertEquals("[]", imageMetaData.getDimensionsString()); + } +} diff --git a/src/test/java/com/github/mfl28/boundingboxeditor/model/io/results/IOErrorInfoEntryTest.java b/src/test/java/com/github/mfl28/boundingboxeditor/model/io/results/IOErrorInfoEntryTest.java new file mode 100644 index 0000000..51ce04c --- /dev/null +++ b/src/test/java/com/github/mfl28/boundingboxeditor/model/io/results/IOErrorInfoEntryTest.java @@ -0,0 +1,33 @@ +/* + * Copyright (C) 2022 Markus Fleischhacker + * + * This file is part of Bounding Box Editor + * + * Bounding Box Editor is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Bounding Box Editor is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Bounding Box Editor. If not, see . + */ +package com.github.mfl28.boundingboxeditor.model.io.results; + +import nl.jqno.equalsverifier.EqualsVerifier; +import org.junit.jupiter.api.Tag; +import org.junit.jupiter.api.Test; + +@Tag("unit") +class IOErrorInfoEntryTest { + @Test + void checkEqualsContract() { + EqualsVerifier.simple().forClass(IOErrorInfoEntry.class) + .withNonnullFields("sourceName", "errorDescription") + .verify(); + } +} \ No newline at end of file