diff --git a/gs-cv/src/main/java/org/genericsystem/cv/comparator/FillModelWithData.java b/gs-cv/src/main/java/org/genericsystem/cv/comparator/FillModelWithData.java index d91a0e015..f29eed1a5 100644 --- a/gs-cv/src/main/java/org/genericsystem/cv/comparator/FillModelWithData.java +++ b/gs-cv/src/main/java/org/genericsystem/cv/comparator/FillModelWithData.java @@ -2,13 +2,11 @@ import java.io.File; import java.nio.file.Path; -import java.time.LocalDate; import java.util.Arrays; -import java.util.Date; -import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Map.Entry; +import java.util.concurrent.ConcurrentHashMap; import java.util.function.Function; import java.util.stream.Stream; @@ -21,13 +19,15 @@ import org.genericsystem.cv.model.Doc; import org.genericsystem.cv.model.Doc.DocFilename; import org.genericsystem.cv.model.Doc.DocInstance; +import org.genericsystem.cv.model.Doc.DocTimestamp; +import org.genericsystem.cv.model.Doc.RefreshTimestamp; import org.genericsystem.cv.model.DocClass; import org.genericsystem.cv.model.DocClass.DocClassInstance; +import org.genericsystem.cv.model.ImgFilter; import org.genericsystem.cv.model.ImgFilter.ImgFilterInstance; +import org.genericsystem.cv.model.LevDistance; import org.genericsystem.cv.model.MeanLevenshtein; import org.genericsystem.cv.model.ModelTools; -import org.genericsystem.cv.model.ImgFilter; -import org.genericsystem.cv.model.LevDistance; import org.genericsystem.cv.model.Score; import org.genericsystem.cv.model.Score.ScoreInstance; import org.genericsystem.cv.model.ZoneGeneric; @@ -66,8 +66,9 @@ public class FillModelWithData { private static final String docType = "id-fr-front"; public static void main(String[] mainArgs) { - final Engine engine = new Engine(gsPath, Doc.class, DocFilename.class, DocClass.class, ZoneGeneric.class, - ZoneText.class, ZoneTimestamp.class, ImgFilter.class, LevDistance.class, MeanLevenshtein.class, Score.class); + final Engine engine = new Engine(gsPath, Doc.class, RefreshTimestamp.class, DocTimestamp.class, DocFilename.class, DocClass.class, + ZoneGeneric.class, ZoneText.class, ZoneTimestamp.class, ImgFilter.class, LevDistance.class, + MeanLevenshtein.class, Score.class); engine.newCache().start(); compute(engine); // cleanModel(engine); @@ -83,7 +84,7 @@ public static void main(String[] mainArgs) { * Img. */ public static Map> getFiltersMap() { - final Map> map = new HashMap<>(); + final Map> map = new ConcurrentHashMap<>(); map.put("original", i -> i); map.put("reality", i -> i); // map.put("bernsen", Img::bernsen); @@ -293,7 +294,7 @@ private static int processFile(Root engine, File file, DocClassInstance docClass // TODO: refactor the code (duplicates) // Save the filternames if necessary - Map> updatedImgFilters = new HashMap<>(); + Map> updatedImgFilters = new ConcurrentHashMap<>(); imgFilters.forEach(entry -> { ImgFilterInstance filter = imgFilter.getImgFilter(entry.getKey()); if (filter == null) { @@ -334,7 +335,7 @@ private static int processFile(Root engine, File file, DocClassInstance docClass // Create a map of Imgs Img originalImg = new Img(Imgcodecs.imread(file.getPath())); - Map imgs = new HashMap<>(); + Map imgs = new ConcurrentHashMap<>(); updatedImgFilters.entrySet().forEach(entry -> { log.info("Applying algorithm {}...", entry.getKey()); Img img = null; @@ -388,7 +389,7 @@ private static int processFile(Root engine, File file, DocClassInstance docClass } private static Map> filterOptimizationMap() { - final Map> imgFilters = new HashMap<>(); + final Map> imgFilters = new ConcurrentHashMap<>(); // Niblack // List blockSizes = Arrays.asList(new Integer[] { 7, 9, 11, // 15, 17, 21, 27, 37 }); diff --git a/gs-cv/src/main/java/org/genericsystem/cv/model/Doc.java b/gs-cv/src/main/java/org/genericsystem/cv/model/Doc.java index be76fd0e0..bbcb6d86d 100644 --- a/gs-cv/src/main/java/org/genericsystem/cv/model/Doc.java +++ b/gs-cv/src/main/java/org/genericsystem/cv/model/Doc.java @@ -13,6 +13,8 @@ import org.genericsystem.cv.model.Doc.DocFilename; import org.genericsystem.cv.model.Doc.DocFilename.DocFilenameInstance; import org.genericsystem.cv.model.Doc.DocInstance; +import org.genericsystem.cv.model.Doc.DocTimestamp.DocTimestampInstance; +import org.genericsystem.cv.model.Doc.RefreshTimestamp.RefreshTimestampInstance; import org.genericsystem.cv.model.DocClass.DocClassInstance; import org.genericsystem.cv.model.ZoneGeneric.ZoneInstance; @@ -74,5 +76,49 @@ public DocInstance getDoc() { } } + + @SystemGeneric + @Components(Doc.class) + @PropertyConstraint + @InstanceClass(RefreshTimestampInstance.class) + public static class RefreshTimestamp implements Generic { + + public static class RefreshTimestampInstance implements Generic { + + public DocInstance getDoc() { + return (DocInstance) getBaseComponent(); + } + } + + public RefreshTimestampInstance setRefreshTimestamp(String timestamp, DocInstance docInstance) { + return (RefreshTimestampInstance) setInstance(timestamp, docInstance); + } + + public RefreshTimestampInstance getRefreshTimestamp(DocInstance docInstance) { + return (RefreshTimestampInstance) getInstance(docInstance); + } + } + + @SystemGeneric + @Components(Doc.class) + @PropertyConstraint + @InstanceClass(DocTimestampInstance.class) + public static class DocTimestamp implements Generic { + + public static class DocTimestampInstance implements Generic { + + public DocInstance getDoc() { + return (DocInstance) getBaseComponent(); + } + } + + public DocTimestampInstance setDocTimestamp(String timestamp, DocInstance docInstance) { + return (DocTimestampInstance) setInstance(timestamp, docInstance); + } + + public DocTimestampInstance getDocTimestamp(DocInstance docInstance) { + return (DocTimestampInstance) getInstance(docInstance); + } + } } diff --git a/gs-cv/src/main/java/org/genericsystem/cv/model/ModelTools.java b/gs-cv/src/main/java/org/genericsystem/cv/model/ModelTools.java index 71f0ae055..5f4c0b036 100644 --- a/gs-cv/src/main/java/org/genericsystem/cv/model/ModelTools.java +++ b/gs-cv/src/main/java/org/genericsystem/cv/model/ModelTools.java @@ -21,6 +21,8 @@ * */ public class ModelTools { + + public static final String DATE_TIME_FORMAT = "uuuu-MM-dd HH:mm:ss"; public static void main(String[] args) { Path path = Paths.get(System.getProperty("user.home"), "Downloads", "photosafpa.zip"); @@ -104,7 +106,7 @@ private static String hashCode(Path path) throws RuntimeException { * @return a {@code String} representing the local date time */ public static String getCurrentDate() { - return getCurrentDate("uuuu-MM-dd HH:mm:ss"); + return getCurrentDate(DATE_TIME_FORMAT); } /** @@ -117,4 +119,20 @@ public static String getCurrentDate(String pattern) { LocalDateTime ldt = LocalDateTime.now(); return ldt.format(DateTimeFormatter.ofPattern(pattern)); } + + public static LocalDateTime getCurrentDateFromString(String date) { + return LocalDateTime.parse(date, DateTimeFormatter.ofPattern(DATE_TIME_FORMAT)); + } + + public static LocalDateTime getCurrentDateFromString(String date, String pattern) { + return LocalDateTime.parse(date, DateTimeFormatter.ofPattern(pattern)); + } + + public static String formatDate(LocalDateTime date) { + return formatDate(date, DATE_TIME_FORMAT); + } + + public static String formatDate(LocalDateTime date, String pattern) { + return date.format(DateTimeFormatter.ofPattern(pattern)); + } } diff --git a/gs-cv/src/main/java/org/genericsystem/cv/watch/ShowDocumentZones.java b/gs-cv/src/main/java/org/genericsystem/cv/watch/ShowDocumentZones.java index ce793ca86..255be704a 100644 --- a/gs-cv/src/main/java/org/genericsystem/cv/watch/ShowDocumentZones.java +++ b/gs-cv/src/main/java/org/genericsystem/cv/watch/ShowDocumentZones.java @@ -1,16 +1,15 @@ package org.genericsystem.cv.watch; -import java.util.Arrays; - import org.genericsystem.api.core.Snapshot; import org.genericsystem.common.Generic; import org.genericsystem.common.Root; import org.genericsystem.cv.comparator.ComputeBestTextPerZone; import org.genericsystem.cv.model.Doc.DocInstance; +import org.genericsystem.cv.model.Doc.RefreshTimestamp; +import org.genericsystem.cv.model.Doc.RefreshTimestamp.RefreshTimestampInstance; +import org.genericsystem.cv.model.ModelTools; import org.genericsystem.cv.model.ZoneText; import org.genericsystem.cv.model.ZoneText.ZoneTextInstance; -import org.genericsystem.cv.model.ZoneText.ZoneTimestamp; -import org.genericsystem.cv.model.ZoneText.ZoneTimestamp.ZoneTimestampInstance; import org.genericsystem.cv.watch.ShowDocumentZones.TextDiv; import org.genericsystem.reactor.Context; import org.genericsystem.reactor.Tag; @@ -40,6 +39,7 @@ import org.genericsystem.reactor.gscomponents.HtmlTag.HtmlLabel; import org.genericsystem.reactor.gscomponents.Modal.ModalEditor; +import javafx.beans.binding.Bindings; import javafx.beans.property.Property; import javafx.beans.property.SimpleStringProperty; import javafx.beans.value.ObservableValue; @@ -73,19 +73,21 @@ public static class TextDiv extends FlexDiv { public static class RefreshButton extends HtmlButton { // Run the best text selection algorithm } - + public static class REFRESH_BEST_TEXT implements ContextAction { @Override public void accept(Context context, Tag tag) { System.out.println("Refreshing best text..."); - Root engine = context.getGeneric().getRoot(); + Root root = context.getGeneric().getRoot(); DocInstance docInstance = (DocInstance) context.getGeneric(); + RefreshTimestamp refreshTimestamp = root.find(RefreshTimestamp.class); String docType = docInstance.getDocClass().getValue().toString(); - ComputeBestTextPerZone.computeOneFile(engine, docInstance, docType); + ComputeBestTextPerZone.computeOneFile(root, docInstance, docType); + refreshTimestamp.setRefreshTimestamp(ModelTools.getCurrentDate(), docInstance); System.out.println("Done!"); } } - + @SetText("Close") @BindAction(value = { CANCEL.class, RESET_SELECTION.class }) public static class CloseButton extends HtmlButton { @@ -132,7 +134,7 @@ public static class ZoneField extends FlexDiv { // Define the inputText // TODO: need to escape special HTML characters } - + @BindText(LAST_UPDATE_LABEL.class) @Style(name = "margin", value = "0.5em") @Style(name = "flex", value = "0 0 auto") @@ -142,7 +144,6 @@ public static class LastUpdate extends FlexDiv { // Print the timestamp of the last refresh } - public static class ZONE_SELECTOR implements ObservableListExtractor { @SuppressWarnings({ "unchecked", "rawtypes" }) @Override @@ -163,25 +164,25 @@ public ObservableValue apply(Context context, Tag tag) { return new SimpleStringProperty("Zone " + ((ZoneTextInstance) context.getGeneric()).getZone()); } } - + public static class LAST_UPDATE_LABEL implements TextBinding { + + @SuppressWarnings({ "unchecked", "rawtypes" }) @Override public ObservableValue apply(Context context, Tag tag) { - // TODO use an ObservableValue for displaying the last update in real time - Generic currentDoc = context.getGeneric(); + // TODO avoid the use of an ObservableList in favor of an ObservableValue? + DocInstance currentDoc = (DocInstance) context.getGeneric(); Root root = currentDoc.getRoot(); - ZoneTimestamp zoneTimestamp = root.find(ZoneTimestamp.class); - ZoneTextInstance zoneTextInstance = (ZoneTextInstance) currentDoc.getHolders(root.find(ZoneText.class)) - .filter(zt -> "best".equals(((ZoneTextInstance) zt).getImgFilter().getValue())) - .first(); - ZoneTimestampInstance zoneTimestampInstance = null; - if (null != zoneTextInstance) - zoneTimestampInstance = zoneTimestamp.getZoneTimestamp(zoneTextInstance); - - if (null == zoneTimestampInstance) - return new SimpleStringProperty("Last update: none"); - else - return new SimpleStringProperty("Last update: " + zoneTimestampInstance.getValue()); + RefreshTimestamp refreshTimestamp = root.find(RefreshTimestamp.class); + ObservableList snap = (ObservableList) currentDoc.getHolders(refreshTimestamp).toObservableList(); + + return Bindings.createStringBinding(() -> { + RefreshTimestampInstance refreshTimestampInstance = refreshTimestamp.getRefreshTimestamp(currentDoc); + if (null == refreshTimestampInstance) + return "Last update: none"; + else + return "Last update: " + refreshTimestampInstance.getValue().toString(); + }, snap); } } diff --git a/gs-cv/src/main/java/org/genericsystem/cv/watch/WatchApp.java b/gs-cv/src/main/java/org/genericsystem/cv/watch/WatchApp.java index 1184aec62..3126c6934 100644 --- a/gs-cv/src/main/java/org/genericsystem/cv/watch/WatchApp.java +++ b/gs-cv/src/main/java/org/genericsystem/cv/watch/WatchApp.java @@ -12,6 +12,8 @@ import org.genericsystem.cv.model.ZoneGeneric; import org.genericsystem.cv.model.ZoneText; import org.genericsystem.cv.model.Doc.DocFilename; +import org.genericsystem.cv.model.Doc.DocTimestamp; +import org.genericsystem.cv.model.Doc.RefreshTimestamp; import org.genericsystem.cv.model.ZoneText.ZoneTimestamp; import org.genericsystem.cv.watch.DocPropertiesCheckerSwitcher.DOC_DEZONED; import org.genericsystem.cv.watch.DocPropertiesCheckerSwitcher.DOC_NOT_DEZONED; @@ -60,7 +62,9 @@ import javafx.collections.ObservableList; -@DependsOnModel({ Doc.class, DocFilename.class, DocClass.class, ZoneGeneric.class, ZoneText.class, ZoneTimestamp.class, ImgFilter.class, LevDistance.class, MeanLevenshtein.class, Score.class }) +@DependsOnModel({ Doc.class, RefreshTimestamp.class, DocTimestamp.class, DocFilename.class, DocClass.class, + ZoneGeneric.class, ZoneText.class, ZoneTimestamp.class, ImgFilter.class, LevDistance.class, + MeanLevenshtein.class, Score.class }) @Children({ EditDocumentZones.class, AppHeader.class, FlexDiv.class, Monitor.class }) @Children(path = FlexDiv.class, pos = 2, value = { HeaderRow.class, DocumentsList.class }) @Children(path = AppHeader.class, value = { Logo.class, AppTitleDiv.class, FlexDiv.class })