From a53cbdf4e5cf4cca9e4b4f8b51c4659c08f02367 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matej=20Kov=C3=A1r?= <xkovar4@fi.muni.cz> Date: Thu, 5 May 2022 16:25:27 +0200 Subject: [PATCH] Resolve "Indicate faces analyzed in multiple tasks" --- Comparison/pom.xml | 13 +- .../java/cz/fidentis/analyst/Project.java | 124 ++- .../analyst/ProjectConfiguration.java | 72 +- .../cz/fidentis/analyst/face/HumanFace.java | 7 +- .../fidentis/analyst/icp/IcpTransformer.java | 8 +- .../mesh/sampling/CurvatureSampling.java | 2 +- GUI/pom.xml | 2 + .../batch/ApproxHausdorffDistTask.java | 2 +- .../batch/ApproxHausdorffDistTaskGPU.java | 4 +- .../cz/fidentis/analyst/canvas/Canvas.java | 6 +- .../toolbar/SceneToolboxFaceToFace.java | 20 +- .../toolbar/SceneToolboxSingleFace.java | 21 +- .../cz/fidentis/analyst/core/FaceTab.java | 136 +++- .../fidentis/analyst/core/ProgressDialog.java | 6 +- .../cz/fidentis/analyst/core/SpinSlider.java | 8 +- .../analyst/faceState/FaceStatePanel.java | 4 +- .../cz/fidentis/analyst/gui/Installer.java | 28 +- .../analyst/project/LoadTasksTask.java | 64 ++ .../analyst/project/ModelsTableModel.java | 79 +- .../analyst/project/ProjectPanel.form | 92 ++- .../analyst/project/ProjectPanel.java | 703 ++++++++++++------ .../analyst/project/ProjectTopComp.java | 22 - .../cz/fidentis/analyst/project/Task.java | 116 +++ .../analyst/project/TaskCellEditor.java | 37 + .../analyst/project/TaskCellRenderer.java | 25 + .../cz/fidentis/analyst/scene/Camera.java | 3 +- .../fidentis/analyst/scene/DrawablePlane.java | 2 +- .../analyst/scene/DrawablePointCloud.java | 4 +- .../java/cz/fidentis/analyst/scene/Scene.java | 2 +- .../analyst/project/Bundle.properties | 4 +- .../analyst/mesh/core/MeshTriangle.java | 7 +- 31 files changed, 1115 insertions(+), 508 deletions(-) create mode 100644 GUI/src/main/java/cz/fidentis/analyst/project/LoadTasksTask.java create mode 100644 GUI/src/main/java/cz/fidentis/analyst/project/Task.java create mode 100644 GUI/src/main/java/cz/fidentis/analyst/project/TaskCellEditor.java create mode 100644 GUI/src/main/java/cz/fidentis/analyst/project/TaskCellRenderer.java diff --git a/Comparison/pom.xml b/Comparison/pom.xml index 3135753c..29811c69 100644 --- a/Comparison/pom.xml +++ b/Comparison/pom.xml @@ -110,7 +110,18 @@ <artifactId>ejml-all</artifactId> <version>0.41</version> </dependency> - + <dependency> + <groupId>com.fasterxml.jackson.core</groupId> + <artifactId>jackson-core</artifactId> + <version>2.13.0</version> + <type>jar</type> + </dependency> + <dependency> + <groupId>com.fasterxml.jackson.core</groupId> + <artifactId>jackson-databind</artifactId> + <version>2.13.0</version> + <type>jar</type> + </dependency> </dependencies> <properties> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> diff --git a/Comparison/src/main/java/cz/fidentis/analyst/Project.java b/Comparison/src/main/java/cz/fidentis/analyst/Project.java index 33f3eccc..25491e29 100644 --- a/Comparison/src/main/java/cz/fidentis/analyst/Project.java +++ b/Comparison/src/main/java/cz/fidentis/analyst/Project.java @@ -4,6 +4,9 @@ import cz.fidentis.analyst.face.HumanFace; import java.io.File; import java.io.IOException; import java.nio.file.Path; +import java.util.prefs.Preferences; +import com.fasterxml.jackson.databind.ObjectMapper; +import java.nio.file.Paths; /** @@ -15,8 +18,13 @@ import java.nio.file.Path; public class Project { private boolean saved = true; + private String projectName = ""; - /* Project data (paths to faces, opened tabs..) */ + private ObjectMapper mapper = new ObjectMapper(); + + private Preferences userPreferences = Preferences.userNodeForPackage(Project.class); + + /* Project data (paths to faces) */ private ProjectConfiguration cfg = new ProjectConfiguration(); /** @@ -39,6 +47,10 @@ public class Project { this.cfg = cfg; } + public String getProjectName() { + return projectName; + } + /** * Adds new path to project configuration * @param path Path to be added @@ -57,40 +69,6 @@ public class Project { return this.cfg.getPaths().contains(path); } - /** - * Adds new FaceToFace tab to project configuration - * @param name1 String name of first face - * @param name2 String name of second face - */ - public void addNewFaceToFaceTabFace(String name1, String name2) { - this.cfg.addFaceToFaceTabFace(name1, name2); - } - - /** - * Adds new face to FaceTab - * @param name String name of face - */ - public void addNewSingleFaceTabFace(String name) { - this.cfg.addSingleFaceTabFace(name); - } - - /** - * Removes FaceTab - * @param name String name of face - */ - public void removeFaceTab(String name) { - this.cfg.removeFaceTab(name); - } - - /** - * Removes FaceToFace tab - * @param name1 String name of first face - * @param name2 String name of second face - */ - public void removeFaceToFaceTab(String name1, String name2) { - this.cfg.removeFaceToFaceTab(name1, name2); - } - /** * Loads face from path * @param name String name of face @@ -140,5 +118,81 @@ public class Project { } return false; } + + /** + * Close currently loaded project + */ + public void closeProject() { + userPreferences.remove("pathToMostRecentProject"); + } + + /** + * Save currently loaded project + * @param file file where to store project + * @return true if project was successfully saved + */ + public boolean saveProject(File file) { + + try { + mapper.writeValue(file, cfg); + userPreferences.put("pathToMostRecentProject", file.getAbsolutePath()); + setSaved(true); + projectName = file.getName().split(".json")[0]; + return true; + } catch (IOException ex) { + //Exceptions.printStackTrace(ex); + } + return false; + } + + /** + * Create new project + */ + public void newProject() { + setCfg(new ProjectConfiguration()); + projectName = ""; + setSaved(true); + } + + /** + * Gets path to project file + * @return String path to project file + */ + public String getPathToProjectFile() { + return userPreferences.get("pathToMostRecentProject", ""); + } + + /** + * Loads most recent project from user preferences + * @return File where project is saved, null if no project was found + */ + public File getRecentProject() { + + String path = getPathToProjectFile(); + if (path.equals("")) { + return null; + } + Path p = Paths.get(path); + return p.toFile(); + } + /** + * Loads project from file + * @param projectFile file with project + * @return true if project was successfully loaded, false otherwise + */ + public boolean openProjectFromFile(File projectFile) { + if (projectFile != null) { + try { + closeProject(); + cfg = mapper.readValue(projectFile, ProjectConfiguration.class); + userPreferences.put("pathToMostRecentProject", projectFile.getAbsolutePath()); + setSaved(true); + projectName = projectFile.getName().split(".json")[0]; + } catch (IOException ex) { + return false; + } + } + return true; + } } diff --git a/Comparison/src/main/java/cz/fidentis/analyst/ProjectConfiguration.java b/Comparison/src/main/java/cz/fidentis/analyst/ProjectConfiguration.java index dc8f0cbe..38796410 100644 --- a/Comparison/src/main/java/cz/fidentis/analyst/ProjectConfiguration.java +++ b/Comparison/src/main/java/cz/fidentis/analyst/ProjectConfiguration.java @@ -3,13 +3,11 @@ package cz.fidentis.analyst; import java.io.File; import java.nio.file.Path; import java.util.ArrayList; -import java.util.HashMap; import java.util.List; -import java.util.Map; /** * This class encapsulates data important for project (re)storing such as paths - * to faces or which tabs were opened + * to faces * * @author Matej Kovar */ @@ -17,15 +15,6 @@ public class ProjectConfiguration { /* Paths to loaded models */ private List<Path> paths = new ArrayList<>(); - - private List<String> singleTabFaces = new ArrayList<>(); - - // f.e. [face1 : [face2, face3], face2 : [face4, face5, face6], face3 : [face4]...] - private Map<String, List<String>> faceToFaceTabFaces = new HashMap<>(); - - //private Map<HumanFace, SingleFaceTab> singleFaceTabs = new HashMap<>(); - //private Map<HumanFace, FaceToFaceTab> faceToFaceTabs = new HashMap<>(); - public List<Path> getPaths() { return paths; @@ -95,63 +84,4 @@ public class ProjectConfiguration { public void clearPaths() { paths.clear(); } - - public List<String> getSingleTabFaces() { - return singleTabFaces; - } - - public void setSingleTabFaces(List<String> singleTabFaces) { - this.singleTabFaces = singleTabFaces; - } - - public Map<String, List<String>> getFaceToFaceTabFaces() { - return faceToFaceTabFaces; - } - - public void setFaceToFaceTabFaces(Map<String, List<String>> faceToFaceTabFaces) { - this.faceToFaceTabFaces = faceToFaceTabFaces; - } - - /** - * Adds SingleFace tab - * @param name String name of face - */ - public void addSingleFaceTabFace(String name) { - singleTabFaces.add(name); - } - - /** - * Adds FaceToFace tab - * @param name1 String name of first face - * @param name2 String name of second face - */ - public void addFaceToFaceTabFace(String name1, String name2) { - if (faceToFaceTabFaces.containsKey(name1)) { - faceToFaceTabFaces.get(name1).add(name2); - } else { - List<String> faces = new ArrayList<>(); - faces.add(name2); - faceToFaceTabFaces.put(name1, faces); - } - } - - /** - * Removes SingleFace tab - * @param name String name of face - */ - public void removeFaceTab(String name) { - singleTabFaces.remove(name); - } - - /** - * Removes FaceToFace tab - * @param name1 String name of first face - * @param name2 String name of second face - */ - public void removeFaceToFaceTab(String name1, String name2) { - faceToFaceTabFaces.get(name1).remove(name2); - if (faceToFaceTabFaces.get(name1).isEmpty()) { - faceToFaceTabFaces.remove(name1); - } - } } diff --git a/Comparison/src/main/java/cz/fidentis/analyst/face/HumanFace.java b/Comparison/src/main/java/cz/fidentis/analyst/face/HumanFace.java index 01774892..9c92f23a 100644 --- a/Comparison/src/main/java/cz/fidentis/analyst/face/HumanFace.java +++ b/Comparison/src/main/java/cz/fidentis/analyst/face/HumanFace.java @@ -15,7 +15,6 @@ import cz.fidentis.analyst.visitors.face.HumanFaceVisitor; import cz.fidentis.analyst.visitors.mesh.BoundingBox; import cz.fidentis.analyst.visitors.mesh.BoundingBox.BBox; import cz.fidentis.analyst.visitors.mesh.CurvatureCalculator; -import java.awt.image.BufferedImage; import java.io.File; import java.io.IOException; @@ -61,9 +60,7 @@ public class HumanFace implements Serializable { private final transient EventBus eventBus; private final String id; - - private transient BufferedImage preview; - + private boolean hasCurvature = false; /** @@ -73,7 +70,6 @@ public class HumanFace implements Serializable { /** * Reads a 3D human face from the given OBJ file. - * Use {@link restoreFromFile} to restore the human face from a dump file. * * @param file OBJ file * @param loadLandmarks If {@code true}, then the constructor aims to load @@ -108,7 +104,6 @@ public class HumanFace implements Serializable { /** * Reads a 3D human face from the given OBJ file. * Also loads landmarks (feature points) if appropriate file is found. - * Use {@link restoreFromFile} to restore the human face from a dump file. * * @param file OBJ file * @throws IOException on I/O failure diff --git a/Comparison/src/main/java/cz/fidentis/analyst/icp/IcpTransformer.java b/Comparison/src/main/java/cz/fidentis/analyst/icp/IcpTransformer.java index da76e5a2..83b480d9 100644 --- a/Comparison/src/main/java/cz/fidentis/analyst/icp/IcpTransformer.java +++ b/Comparison/src/main/java/cz/fidentis/analyst/icp/IcpTransformer.java @@ -118,7 +118,7 @@ public class IcpTransformer extends MeshVisitor { * Mean distance of vertices is computed for each ICP iteration. * If the difference between the previous and current mean distances is less than the error, * then the ICP computation stops. Reasonable number seems to be 0.05. - * @param strategy One of the reduction strategies. If {@code null}, then {@link NoUndersampling} is used. + * @param strategy One of the reduction strategies. If {@code null}, then {@code NoUndersampling} is used. * @throws IllegalArgumentException if some parameter is wrong */ public IcpTransformer(MeshFacet mainFacet, int maxIteration, boolean scale, double error, PointSampling strategy) { @@ -141,7 +141,7 @@ public class IcpTransformer extends MeshVisitor { * Mean distance of vertices is computed for each ICP iteration. * If the difference between the previous and current mean distances is less than the error, * then the ICP computation stops. Reasonable number seems to be 0.05. - * @param strategy One of the reduction strategies. If {@code null}, then {@link NoUndersampling} is used. + * @param strategy One of the reduction strategies. If {@code null}, then {@code NoUndersampling} is used. * @throws IllegalArgumentException if some parameter is wrong */ public IcpTransformer(Set<MeshFacet> mainFacets, int maxIteration, boolean scale, double error, PointSampling strategy) { @@ -174,7 +174,7 @@ public class IcpTransformer extends MeshVisitor { * Mean distance of vertices is computed for each ICP iteration. * If the difference between the previous and current mean distances is less than the error, * then the ICP computation stops. Reasonable number seems to be 0.05. - * @param strategy One of the reduction strategies. If {@code null}, then {@link NoUndersampling} is used. + * @param strategy One of the reduction strategies. If {@code null}, then {@code NoUndersampling} is used. * @throws IllegalArgumentException if some parameter is wrong */ public IcpTransformer(MeshModel mainModel, int maxIteration, boolean scale, double error, PointSampling strategy) { @@ -197,7 +197,7 @@ public class IcpTransformer extends MeshVisitor { * Mean distance of vertices is computed for each ICP iteration. * If the difference between the previous and current mean distances is less than the error, * then the ICP computation stops. Reasonable number seems to be 0.05. - * @param strategy One of the reduction strategies. If {@code null}, then {@link NoUndersampling} is used. + * @param strategy One of the reduction strategies. If {@code null}, then {@code NoUndersampling} is used. * @throws IllegalArgumentException if some parameter is wrong */ public IcpTransformer(KdTree primaryKdTree, int maxIteration, boolean scale, double error, PointSampling strategy) { diff --git a/Comparison/src/main/java/cz/fidentis/analyst/visitors/mesh/sampling/CurvatureSampling.java b/Comparison/src/main/java/cz/fidentis/analyst/visitors/mesh/sampling/CurvatureSampling.java index 19fad2e0..19825e4c 100644 --- a/Comparison/src/main/java/cz/fidentis/analyst/visitors/mesh/sampling/CurvatureSampling.java +++ b/Comparison/src/main/java/cz/fidentis/analyst/visitors/mesh/sampling/CurvatureSampling.java @@ -9,7 +9,7 @@ import java.util.stream.Collectors; /** * A relevance-based point sampling using highest curvature. - * {@see https://graphics.stanford.edu/papers/zipper/zipper.pdf} + * {@link https://graphics.stanford.edu/papers/zipper/zipper.pdf} * If curvature is not set in inspected facets, then it is computed and set automatically. * This visitor is tread-safe. * diff --git a/GUI/pom.xml b/GUI/pom.xml index 68f43d64..a1db4d79 100644 --- a/GUI/pom.xml +++ b/GUI/pom.xml @@ -142,6 +142,7 @@ <artifactId>AbsoluteLayout</artifactId> <version>RELEASE123</version> </dependency> + <!-- <dependency> <groupId>com.fasterxml.jackson.core</groupId> <artifactId>jackson-databind</artifactId> @@ -154,6 +155,7 @@ <version>2.13.0</version> <type>jar</type> </dependency> + --> <dependency> <groupId>com.google.guava</groupId> <artifactId>guava</artifactId> diff --git a/GUI/src/main/java/cz/fidentis/analyst/batch/ApproxHausdorffDistTask.java b/GUI/src/main/java/cz/fidentis/analyst/batch/ApproxHausdorffDistTask.java index 3b4ba0be..833e2de7 100644 --- a/GUI/src/main/java/cz/fidentis/analyst/batch/ApproxHausdorffDistTask.java +++ b/GUI/src/main/java/cz/fidentis/analyst/batch/ApproxHausdorffDistTask.java @@ -43,7 +43,7 @@ public class ApproxHausdorffDistTask extends SimilarityTask { * * @param progressDialog A window that show the progress of the computation. Must not be {@code null} * @param controlPanel A control panel with computation parameters. Must not be {@code null} - * @param avgFace average face + * @param templateFaceIndex Index of the template face */ public ApproxHausdorffDistTask(ProgressDialog progressDialog, BatchPanel controlPanel, int templateFaceIndex) { super(progressDialog, controlPanel); diff --git a/GUI/src/main/java/cz/fidentis/analyst/batch/ApproxHausdorffDistTaskGPU.java b/GUI/src/main/java/cz/fidentis/analyst/batch/ApproxHausdorffDistTaskGPU.java index f6879d11..1e23a088 100644 --- a/GUI/src/main/java/cz/fidentis/analyst/batch/ApproxHausdorffDistTaskGPU.java +++ b/GUI/src/main/java/cz/fidentis/analyst/batch/ApproxHausdorffDistTaskGPU.java @@ -32,7 +32,7 @@ import org.jocl.cl_queue_properties; * A GPU accelerated variant of {@link ApproxHausdorffDistTask}. * The computation is accelerated by using both the CPU and GPU parallelism. * The OpenCL code is based on - * {@see https://github.com/gpu/JOCLSamples/blob/master/src/main/java/org/jocl/samples/JOCLSample.java}. + * {@link https://github.com/gpu/JOCLSamples/blob/master/src/main/java/org/jocl/samples/JOCLSample.java}. * However, the computation is slower than using CPU-based multitasking only * (For 500 faces, 40 seconds of the HD finalization phase on GPU compared to 18 second on 8-core CPU) * This class is marked as deprecated for this reason. @@ -97,7 +97,7 @@ public class ApproxHausdorffDistTaskGPU extends SimilarityTask { * * @param progressDialog A window that show the progress of the computation. Must not be {@code null} * @param controlPanel A control panel with computation parameters. Must not be {@code null} - * @param avgFace average face + * @param templateFaceIndex Index of the template face */ public ApproxHausdorffDistTaskGPU(ProgressDialog progressDialog, BatchPanel controlPanel, int templateFaceIndex) { super(progressDialog, controlPanel); diff --git a/GUI/src/main/java/cz/fidentis/analyst/canvas/Canvas.java b/GUI/src/main/java/cz/fidentis/analyst/canvas/Canvas.java index 5f03fde1..eed57709 100644 --- a/GUI/src/main/java/cz/fidentis/analyst/canvas/Canvas.java +++ b/GUI/src/main/java/cz/fidentis/analyst/canvas/Canvas.java @@ -56,7 +56,7 @@ public class Canvas extends JPanel implements HumanFaceListener { // Scene components: private final Scene scene = new Scene(); private final SceneRenderer sceneRenderer; - private final Camera camera = new Camera(); + private Camera camera = new Camera(); private final List<HumanFace> faces = new ArrayList<>(); // Listeners: @@ -199,6 +199,10 @@ public class Canvas extends JPanel implements HumanFaceListener { return camera; } + public void setCamera(Camera camera) { + this.camera = camera; + } + /** * Returns the underlying OpenGL canvas. * diff --git a/GUI/src/main/java/cz/fidentis/analyst/canvas/toolbar/SceneToolboxFaceToFace.java b/GUI/src/main/java/cz/fidentis/analyst/canvas/toolbar/SceneToolboxFaceToFace.java index 3ec0db48..b503b460 100644 --- a/GUI/src/main/java/cz/fidentis/analyst/canvas/toolbar/SceneToolboxFaceToFace.java +++ b/GUI/src/main/java/cz/fidentis/analyst/canvas/toolbar/SceneToolboxFaceToFace.java @@ -9,9 +9,13 @@ import cz.fidentis.analyst.scene.DrawableFace; import cz.fidentis.analyst.scene.DrawablePlane; import java.awt.Color; import java.awt.FlowLayout; +import java.awt.Font; import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; import javax.swing.AbstractAction; +import javax.swing.Box; import javax.swing.ImageIcon; +import javax.swing.JButton; import javax.swing.JPanel; import javax.swing.JSlider; import javax.swing.JToggleButton; @@ -46,15 +50,18 @@ public class SceneToolboxFaceToFace extends JPanel implements HumanFaceListener private JSlider slider; private JToggleButton secDistButton; + private JButton endTaskButton; + private final Canvas canvas; /** * Constructor. * @param canvas Rendering canvas + * @param endTaskListener action listener */ - public SceneToolboxFaceToFace(Canvas canvas) { + public SceneToolboxFaceToFace(Canvas canvas, ActionListener endTaskListener) { this.canvas = canvas; - initComponents(); // buttons are turned on by default + initComponents(endTaskListener); // buttons are turned on by default // be informed if something changes in the faces -- see acceptEvent() canvas.getPrimaryFace().registerListener(this); @@ -135,7 +142,7 @@ public class SceneToolboxFaceToFace extends JPanel implements HumanFaceListener return button; } - private void initComponents() { + private void initComponents(ActionListener endTaskListener) { JPanel panel = new JPanel(); panel.setLayout(new FlowLayout()); add(panel); @@ -242,5 +249,12 @@ public class SceneToolboxFaceToFace extends JPanel implements HumanFaceListener canvas.renderScene(); } }); + + ///////////////////////// + endTaskButton = new JButton("End Task"); + endTaskButton.setFont(new Font("Tahoma", Font.BOLD, 12)); + endTaskButton.addActionListener(endTaskListener); + panel.add(Box.createHorizontalStrut(40)); + panel.add(endTaskButton); } } diff --git a/GUI/src/main/java/cz/fidentis/analyst/canvas/toolbar/SceneToolboxSingleFace.java b/GUI/src/main/java/cz/fidentis/analyst/canvas/toolbar/SceneToolboxSingleFace.java index c27fee48..177d4dab 100644 --- a/GUI/src/main/java/cz/fidentis/analyst/canvas/toolbar/SceneToolboxSingleFace.java +++ b/GUI/src/main/java/cz/fidentis/analyst/canvas/toolbar/SceneToolboxSingleFace.java @@ -8,9 +8,13 @@ import cz.fidentis.analyst.scene.DrawableFace; import cz.fidentis.analyst.scene.DrawablePlane; import java.awt.Color; import java.awt.FlowLayout; +import java.awt.Font; import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; import javax.swing.AbstractAction; +import javax.swing.Box; import javax.swing.ImageIcon; +import javax.swing.JButton; import javax.swing.JPanel; import javax.swing.JSlider; import javax.swing.JToggleButton; @@ -39,15 +43,18 @@ public class SceneToolboxSingleFace extends JPanel implements HumanFaceListener private JToggleButton priSymmetryButton; private JSlider slider; + private JButton endTaskButton; + private final Canvas canvas; /** * Constructor. * @param canvas Rendering canvas + * @param endTaskListener action listener */ - public SceneToolboxSingleFace(Canvas canvas) { + public SceneToolboxSingleFace(Canvas canvas, ActionListener endTaskListener) { this.canvas = canvas; - initComponents(); + initComponents(endTaskListener); // show the symmetry planes automatically, but only after they are computed priSymmetryButton.setSelected(true); @@ -100,7 +107,7 @@ public class SceneToolboxSingleFace extends JPanel implements HumanFaceListener return button; } - private void initComponents() { + private void initComponents(ActionListener endTaskListener) { JPanel panel = new JPanel(); panel.setLayout(new FlowLayout()); add(panel); @@ -156,5 +163,13 @@ public class SceneToolboxSingleFace extends JPanel implements HumanFaceListener canvas.renderScene(); }); + + ///////////////////////// + endTaskButton = new JButton("End Task"); + endTaskButton.setFont(new Font("Tahoma", Font.BOLD, 12)); + endTaskButton.addActionListener(endTaskListener); + panel.add(Box.createHorizontalStrut(40)); + panel.add(endTaskButton); + } } diff --git a/GUI/src/main/java/cz/fidentis/analyst/core/FaceTab.java b/GUI/src/main/java/cz/fidentis/analyst/core/FaceTab.java index 307d7d40..798d1131 100644 --- a/GUI/src/main/java/cz/fidentis/analyst/core/FaceTab.java +++ b/GUI/src/main/java/cz/fidentis/analyst/core/FaceTab.java @@ -9,15 +9,20 @@ import cz.fidentis.analyst.curvature.CurvatureAction; import cz.fidentis.analyst.distance.DistanceAction; import cz.fidentis.analyst.face.HumanFace; import cz.fidentis.analyst.faceState.FaceStatePanel; +import cz.fidentis.analyst.project.Task; import cz.fidentis.analyst.registration.RegistrationAction; +import cz.fidentis.analyst.scene.Camera; import cz.fidentis.analyst.symmetry.ProfilesAction; import cz.fidentis.analyst.symmetry.SymmetryAction; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.awt.event.ComponentAdapter; import java.awt.event.ComponentEvent; +import java.io.File; +import java.io.IOException; import java.nio.file.Path; import java.nio.file.Paths; +import java.util.ArrayList; import java.util.List; import java.util.Objects; import javax.swing.GroupLayout; @@ -36,9 +41,11 @@ public class FaceTab extends TopComponent { private final TopControlPanel controlPanel; private final JScrollPane scrollPane; - private String nameOfFace1 = null; - private String nameOfFace2 = null; - private ActionListener listener = null; + private HumanFace face1 = null; + private HumanFace face2 = null; + private List<Path> faces = new ArrayList<>(); + + private Project project; /** * Constructor for single face analysis and 1:1. @@ -46,25 +53,40 @@ public class FaceTab extends TopComponent { * @param primary Primary face * @param secondary Secondary face * @param name Tab name - * @param listener action listener + * @param endTaskListener action endTaskListener + * @param project Project */ - public FaceTab(HumanFace primary, HumanFace secondary, String name, ActionListener listener, Project project) { + public FaceTab(HumanFace primary, HumanFace secondary, String name, + ActionListener endTaskListener, Project project) { + canvas = new Canvas(); - this.listener = listener; + this.project = project; - nameOfFace1 = primary.getShortName(); + face1 = primary; canvas.addPrimaryFace(primary); - + if (secondary == null) { // single face analysis canvas.getScene().setDefaultColors(); - canvas.addToolBox(new SceneToolboxSingleFace(canvas)); - nameOfFace2 = null; + canvas.addToolBox(new SceneToolboxSingleFace(canvas, + (ActionEvent e) -> { + endTaskListener.actionPerformed( + new ActionEvent(this, + ActionEvent.ACTION_PERFORMED, + "FaceTab")); + })); + } else { // 1:1 canvas.addSecondaryFace(secondary); canvas.getScene().setDefaultColors(); - canvas.addToolBox(new SceneToolboxFaceToFace(canvas)); - nameOfFace2 = secondary.getShortName(); + canvas.addToolBox(new SceneToolboxFaceToFace(canvas, + (ActionEvent e) -> { + endTaskListener.actionPerformed( + new ActionEvent(this, + ActionEvent.ACTION_PERFORMED, + "FaceToFaceTab")); + })); + face2 = secondary; } controlPanel = new TopControlPanel(); @@ -115,13 +137,18 @@ public class FaceTab extends TopComponent { * * @param faces Paths to faces * @param name Tab name - * @param listener action listener + * @param endTaskListener action endTaskListener */ - public FaceTab(List<Path> faces, String name, ActionListener listener) { + public FaceTab(List<Path> faces, String name, ActionListener endTaskListener) { canvas = new Canvas(); - this.listener = listener; - canvas.addToolBox(new SceneToolboxSingleFace(canvas)); + canvas.addToolBox(new SceneToolboxSingleFace(canvas, + (ActionEvent e) -> { + endTaskListener.actionPerformed( + new ActionEvent(this, + ActionEvent.ACTION_PERFORMED, + "FaceToFaceTab")); + })); controlPanel = new TopControlPanel(); scrollPane = new JScrollPane(controlPanel); @@ -139,8 +166,13 @@ public class FaceTab extends TopComponent { controlPanel.addChangeListener(e -> getCanvas().renderScene()); + this.faces = faces; new BatchAction(canvas, controlPanel, faces); } + /* + public FaceTab() { + this(null, null, null, null, null); + }*/ @Override public int getPersistenceType() { @@ -176,12 +208,39 @@ public class FaceTab extends TopComponent { ); } + /** + * Gets name of primary face + * @return name of primary face, or null + */ public String getNameOfFace1() { - return nameOfFace1; + + if (face1 != null) { + return face1.getShortName(); + } + return null; } + /** + * Gets name of secondary face + * @return name of secondary face, or null + */ public String getNameOfFace2() { - return nameOfFace2; + if (face2 != null) { + return face2.getShortName(); + } + return null; + } + + public HumanFace getFace1() { + return face1; + } + + public HumanFace getFace2() { + return face2; + } + + public List<Path> getFaces() { + return faces; } /** @@ -190,13 +249,21 @@ public class FaceTab extends TopComponent { * @return true if face with this name is in this tab */ public boolean hasFace(String name) { - return (name.equals(nameOfFace1) || name.equals(nameOfFace2)); + return (name.equals(getNameOfFace1()) || name.equals(getNameOfFace2())); } public Canvas getCanvas() { return canvas; } + /** + * Sets camera to canvas + * @param camera + */ + public void setCamera(Camera camera) { + this.canvas.setCamera(camera); + } + /** * Create FaceStatePanel for face * @param face which will be shown on panel @@ -213,20 +280,20 @@ public class FaceTab extends TopComponent { return facePanel; } - - @Override - public boolean canClose() { - if (nameOfFace1 != null && nameOfFace2 == null) { - listener.actionPerformed(new ActionEvent(this, ActionEvent.ACTION_PERFORMED, "FaceTab")); - } else if (nameOfFace1 != null && nameOfFace2 != null) { - listener.actionPerformed(new ActionEvent(this, ActionEvent.ACTION_PERFORMED, "FaceToFaceTab")); - } else { - listener.actionPerformed(new ActionEvent(this, ActionEvent.ACTION_PERFORMED, "ManyToManyTab")); + /** + * Create task for this tab and serialize data + * @throws IOException + */ + public void serializeTask() throws IOException { + if (face1 != null) { + Task task = new Task(face1, face2, canvas.getCamera()); + + task.dumpToFile(project.getPathToProjectFile() + .substring(0, project.getPathToProjectFile().lastIndexOf(File.separatorChar))); } - return super.canClose(); //To change body of generated methods, choose Tools | Templates. + } - @Override public int hashCode() { int hash = 5; @@ -245,11 +312,14 @@ public class FaceTab extends TopComponent { return false; } final FaceTab other = (FaceTab) obj; - if (!Objects.equals(this.nameOfFace1, other.nameOfFace1)) { + if (!Objects.equals(this.getNameOfFace1(), other.getNameOfFace1())) { return false; } - return Objects.equals(this.nameOfFace2, other.nameOfFace2); + if (!Objects.equals(this.getNameOfFace2(), other.getNameOfFace2())) { + return false; + } + return Objects.equals(faces, other.getFaces()); } - + } \ No newline at end of file diff --git a/GUI/src/main/java/cz/fidentis/analyst/core/ProgressDialog.java b/GUI/src/main/java/cz/fidentis/analyst/core/ProgressDialog.java index 3ffcc1a6..cce7b65d 100644 --- a/GUI/src/main/java/cz/fidentis/analyst/core/ProgressDialog.java +++ b/GUI/src/main/java/cz/fidentis/analyst/core/ProgressDialog.java @@ -15,7 +15,7 @@ import javax.swing.SwingWorker; * Before using this dialog, a {@code SwingWorker} task class has to be implemented * that stores the reference to this {@code ProgressDialog}, e.g., * <pre> - * public class Task extends SwingWorker<Void, Voide> { + * public class Task extends SwingWorker<Void, Voide> { * private final ProgressDialog progressDialog; * * public Task(ProgressDialog progressDialog) { @@ -35,8 +35,8 @@ import javax.swing.SwingWorker; * ProgressDialog progressDialog = new ProgressDialog(null); * Task task = new Task(progressDialog); * - * task.addPropertyChangeListener((PropertyChangeEvent evt) -> { - * if ("state".equals(evt.getPropertyName()) && (SwingWorker.StateValue.DONE.equals(evt.getNewValue()))) { + * task.addPropertyChangeListener((PropertyChangeEvent evt) -> { + * if ("state".equals(evt.getPropertyName()) && (SwingWorker.StateValue.DONE.equals(evt.getNewValue()))) { * // code invoked when the task is done * } * }); diff --git a/GUI/src/main/java/cz/fidentis/analyst/core/SpinSlider.java b/GUI/src/main/java/cz/fidentis/analyst/core/SpinSlider.java index bbffbe9a..f02e4634 100644 --- a/GUI/src/main/java/cz/fidentis/analyst/core/SpinSlider.java +++ b/GUI/src/main/java/cz/fidentis/analyst/core/SpinSlider.java @@ -136,8 +136,8 @@ public class SpinSlider extends JPanel { * <b>Removed all listeners!</b> * * @param value Initial value - * @param minimum Minimum value - * @param maximum Maximum value + * @param min Minimum value + * @param max Maximum value * @param stepSize Spin step size */ public void initInteger(int value, int min, int max, int stepSize) { @@ -163,8 +163,8 @@ public class SpinSlider extends JPanel { * <b>Removed all listeners!</b> * * @param value Initial value - * @param minimum Minimum value - * @param maximum Maximum value + * @param min Minimum value + * @param max Maximum value * @param fractionDigits precision of flouting numbers, i.e., * the number of digits allowed after the floating dot */ diff --git a/GUI/src/main/java/cz/fidentis/analyst/faceState/FaceStatePanel.java b/GUI/src/main/java/cz/fidentis/analyst/faceState/FaceStatePanel.java index 3e9bdcf2..80200470 100644 --- a/GUI/src/main/java/cz/fidentis/analyst/faceState/FaceStatePanel.java +++ b/GUI/src/main/java/cz/fidentis/analyst/faceState/FaceStatePanel.java @@ -336,7 +336,7 @@ public class FaceStatePanel extends ControlPanel { /** * Shows face information on panel - * @param name String + * @param faceName String * @param path Path */ public void showFaceState(String faceName, Path path) { @@ -630,7 +630,7 @@ public class FaceStatePanel extends ControlPanel { /** * Face from list is (de)selected * @param selected true if face is selected, false if deselected - * @param name String name of face + * @param faceNames String name of face * @param path Path to face */ public void newSelection(boolean selected, String faceName, Path path) { diff --git a/GUI/src/main/java/cz/fidentis/analyst/gui/Installer.java b/GUI/src/main/java/cz/fidentis/analyst/gui/Installer.java index 6be0f44f..0fa04916 100644 --- a/GUI/src/main/java/cz/fidentis/analyst/gui/Installer.java +++ b/GUI/src/main/java/cz/fidentis/analyst/gui/Installer.java @@ -1,6 +1,6 @@ package cz.fidentis.analyst.gui; -import cz.fidentis.analyst.project.ProjectTopComp; +import cz.fidentis.analyst.project.ProjectPanel; import javax.swing.JOptionPane; import javax.swing.UIManager; import javax.swing.UnsupportedLookAndFeelException; @@ -13,23 +13,6 @@ import org.openide.modules.ModuleInstall; */ public class Installer extends ModuleInstall { - private ProjectTopComp projectTopComp; - - /** - * Constructor with projectTopComp - * @param projectTopComp ProjectTopComp - */ - public Installer(ProjectTopComp projectTopComp) { - this.projectTopComp = projectTopComp; - } - - /** - * Default constructor - */ - public Installer() { - //super(); - } - @Override public void restored() { /* @@ -62,12 +45,13 @@ public class Installer extends ModuleInstall { @Override public boolean closing() { - if (projectTopComp != null) { - projectTopComp.saveProjectOnClose(); - } - int answer = JOptionPane.showConfirmDialog(null, "Do you really want to close the application?", "", JOptionPane.YES_NO_OPTION, JOptionPane.WARNING_MESSAGE); + + if (answer == JOptionPane.YES_OPTION) { + ProjectPanel.serializeTasks(); + } + return answer == JOptionPane.YES_OPTION; } diff --git a/GUI/src/main/java/cz/fidentis/analyst/project/LoadTasksTask.java b/GUI/src/main/java/cz/fidentis/analyst/project/LoadTasksTask.java new file mode 100644 index 00000000..0abdb77e --- /dev/null +++ b/GUI/src/main/java/cz/fidentis/analyst/project/LoadTasksTask.java @@ -0,0 +1,64 @@ +package cz.fidentis.analyst.project; + +import cz.fidentis.analyst.core.ProgressDialog; +import java.io.File; +import java.util.ArrayList; +import java.util.List; +import javax.swing.SwingWorker; + +/** + * A task which opens all tasks from files + * + * @author Matej Kovar + */ +class LoadTasksTask extends SwingWorker<Boolean, Integer> { + + private List<File> tasksToOpen; + private ProgressDialog progressDialog; + private List<Task> tasksRestored = new ArrayList<>(); + + /** + * Constructor for task + * @param tasksToOpen files with tasks + * @param progressDialog dialog + */ + LoadTasksTask(List<File> tasksToOpen, ProgressDialog progressDialog) { + this.tasksToOpen = tasksToOpen; + this.progressDialog = progressDialog; + } + + @Override + protected Boolean doInBackground() throws Exception { + + int iter = 0; + for (var file : tasksToOpen) { + + if (isCancelled()) { + return false; + } + + Task task = Task.restoreFromFile(file); + tasksRestored.add(task); + + int progress = (int)Math.round(100.0 * (iter + 1) / tasksToOpen.size()); + progressDialog.setValue(progress); + iter++; + } + return true; + + } + + @Override + protected void done() { + progressDialog.dispose(); + + + if (isCancelled()) { + this.tasksRestored.clear(); + } + } + + public List<Task> getTasksRestored() { + return this.tasksRestored; + } +} diff --git a/GUI/src/main/java/cz/fidentis/analyst/project/ModelsTableModel.java b/GUI/src/main/java/cz/fidentis/analyst/project/ModelsTableModel.java index ec2fe157..adf5727b 100644 --- a/GUI/src/main/java/cz/fidentis/analyst/project/ModelsTableModel.java +++ b/GUI/src/main/java/cz/fidentis/analyst/project/ModelsTableModel.java @@ -4,6 +4,7 @@ import cz.fidentis.analyst.faceState.FaceStatePanel; import java.awt.Graphics2D; import java.awt.image.BufferedImage; import java.awt.Image; +import java.awt.event.ActionListener; import java.io.File; import java.io.IOException; import java.nio.file.Path; @@ -12,6 +13,7 @@ import java.util.ArrayList; import java.util.List; import javax.imageio.ImageIO; import javax.swing.ImageIcon; +import javax.swing.JComboBox; import javax.swing.table.DefaultTableModel; import org.openide.util.Exceptions; import org.imgscalr.Scalr; @@ -27,7 +29,7 @@ public class ModelsTableModel extends DefaultTableModel { private final ImageIcon previewBasic = new ImageIcon(FaceStatePanel.class.getClassLoader().getResource("/" + "face32x32.png")); private final ImageIcon previewBasicGray = new ImageIcon(FaceStatePanel.class.getClassLoader().getResource("/" + "face_gray32x32.png")); - // List of previews of faces which are currently filtered + // List of paths faces which are currently filtered private List<Path> pathsToFilteredFaces = new ArrayList<>(); private Integer filteredRows = 0; @@ -36,15 +38,16 @@ public class ModelsTableModel extends DefaultTableModel { * Constructor */ public ModelsTableModel() { - super(new Object[]{"", "Models", "Preview"}, 0); + super(new Object[]{"", "Models", "Tasks", "Preview"}, 0); + } private Class[] types = new Class [] { - java.lang.Boolean.class, java.lang.String.class, ImageIcon.class + java.lang.Boolean.class, java.lang.String.class, JComboBox.class, ImageIcon.class }; private boolean[] canEdit = new boolean [] { - true, false, false + true, false, true, false }; @Override @@ -62,16 +65,17 @@ public class ModelsTableModel extends DefaultTableModel { @Override public void setRowCount(int rowCount) { - super.setRowCount(rowCount); + if (rowCount == 0) { pathsToFilteredFaces.clear(); filteredRows = 0; + } + super.setRowCount(rowCount); } @Override public void removeRow(int row) { - super.removeRow(row); String faceName = this.getValueAt(row, 1).toString(); @@ -80,6 +84,8 @@ public class ModelsTableModel extends DefaultTableModel { .lastIndexOf(File.separatorChar) + 1, path.toString().lastIndexOf('.')).equals(faceName); }); + + super.removeRow(row); } /** @@ -102,8 +108,6 @@ public class ModelsTableModel extends DefaultTableModel { for (int row = 0; row < this.getRowCount() - filteredRows; row++) { - - if (this.getValueAt(row, 0) == (Object) true) { this.setValueAt(false, row, 0); } else { @@ -161,12 +165,12 @@ public class ModelsTableModel extends DefaultTableModel { public void disableRow(int row, Path path) { if (path != null && !pathsToFilteredFaces.contains(path)) { - Image iconImage = ((ImageIcon)this.getValueAt(row, 2)).getImage(); + Image iconImage = ((ImageIcon)this.getValueAt(row, 3)).getImage(); Path previewPath = this.getPreviewPath(path); if (previewPath == null || !previewPath.toFile().exists()) { - this.setValueAt(previewBasicGray, row, 2); + this.setValueAt(previewBasicGray, row, 3); } else { @@ -175,7 +179,7 @@ public class ModelsTableModel extends DefaultTableModel { // Scalr.OP_DARKER passed 5 times to grey preview by 50% image = Scalr.apply(image, Scalr.OP_DARKER, Scalr.OP_DARKER, Scalr.OP_DARKER, Scalr.OP_DARKER, Scalr.OP_DARKER); - this.setValueAt(new ImageIcon(image), row, 2); + this.setValueAt(new ImageIcon(image), row, 3); } pathsToFilteredFaces.add(path); @@ -208,7 +212,7 @@ public class ModelsTableModel extends DefaultTableModel { } - this.setValueAt(preview, row, 2); + this.setValueAt(preview, row, 3); pathsToFilteredFaces.remove(path); } } @@ -245,25 +249,68 @@ public class ModelsTableModel extends DefaultTableModel { return preview; } + + /** + * Adds new task to combo-box + * @param faceName name of the face + * @param nameOfTask name of task + */ + public void addNewTask(String faceName, String nameOfTask) { + + for (int row = 0; row < this.getRowCount(); row++) { + if (this.getValueAt(row, 1).toString() == null ? faceName == null : this.getValueAt(row, 1).toString().equals(faceName)) { + + JComboBox comboBox = ((JComboBox)this.getValueAt(row, 2)); + + comboBox.addItem(nameOfTask); + return; + } + } + } + + /** + * Removes task from combo-box + * @param faceName name of face + * @param nameOfTask name of task + */ + public void removeTask(String faceName, String nameOfTask) { + + for (int row = 0; row < this.getRowCount(); row++) { + if (this.getValueAt(row, 1).toString() == null ? faceName == null : this.getValueAt(row, 1).toString().equals(faceName)) { + + JComboBox comboBox = ((JComboBox)this.getValueAt(row, 2)); + + comboBox.removeItem(nameOfTask); + return; + } + } + } + /** * Adds new row to model * @param name String name of the face - * @param Path path to face + * @param path path to face + * @param taskSelected task */ - public void addRowWithName(String name, Path path) { + public void addRowWithName(String name, Path path, ActionListener taskSelected) { Path preview = this.getPreviewPath(path); int index = this.getRowCount() - filteredRows; + JComboBox comboBox = new JComboBox(); + comboBox.addActionListener(taskSelected); + comboBox.setFont(new java.awt.Font("Tahoma", 0, 14)); + if (preview == null || !preview.toFile().exists()) { - insertRow(index, new Object[]{false, name, previewBasic}); + insertRow(index, new Object[]{false, name, comboBox, previewBasic}); } else { try { BufferedImage image = ImageIO.read(preview.toFile()); // Scale image to fit into column BufferedImage scaledImage = Scalr.resize(image, 70, 55); - insertRow(index, new Object[]{false, name, new ImageIcon(scaledImage)}); + + insertRow(index, new Object[]{false, name, comboBox, new ImageIcon(scaledImage)}); } catch (IOException ex) { Exceptions.printStackTrace(ex); diff --git a/GUI/src/main/java/cz/fidentis/analyst/project/ProjectPanel.form b/GUI/src/main/java/cz/fidentis/analyst/project/ProjectPanel.form index e535c924..001c5e87 100644 --- a/GUI/src/main/java/cz/fidentis/analyst/project/ProjectPanel.form +++ b/GUI/src/main/java/cz/fidentis/analyst/project/ProjectPanel.form @@ -19,26 +19,21 @@ <Group type="102" alignment="0" attributes="0"> <EmptySpace min="-2" pref="41" max="-2" attributes="0"/> <Group type="103" groupAlignment="0" attributes="0"> - <Component id="buttonsPanel" pref="1025" max="32767" attributes="0"/> + <Component id="buttonsPanel" pref="968" max="32767" attributes="0"/> <Component id="tableScrollPane" max="32767" attributes="0"/> </Group> + <EmptySpace type="separate" max="-2" attributes="0"/> <Group type="103" groupAlignment="0" attributes="0"> - <Group type="103" groupAlignment="0" attributes="0"> - <Group type="102" attributes="0"> - <EmptySpace min="-2" pref="50" max="-2" attributes="0"/> - <Component id="newProjectButton" min="-2" max="-2" attributes="0"/> - </Group> - <Group type="102" alignment="1" attributes="0"> - <EmptySpace max="-2" attributes="0"/> - <Component id="saveProjectButton" min="-2" max="-2" attributes="0"/> - </Group> - </Group> - <Group type="102" alignment="1" attributes="0"> - <EmptySpace max="-2" attributes="0"/> - <Component id="openProjectButton" min="-2" max="-2" attributes="0"/> + <Component id="newProjectButton" min="-2" max="-2" attributes="0"/> + <Component id="saveProjectButton" alignment="0" min="-2" max="-2" attributes="0"/> + <Component id="openProjectButton" min="-2" max="-2" attributes="0"/> + <Group type="102" alignment="0" attributes="0"> + <Component id="projectNameLabel" min="-2" max="-2" attributes="0"/> + <EmptySpace type="unrelated" max="-2" attributes="0"/> + <Component id="projectNameOutput" min="-2" pref="122" max="-2" attributes="0"/> </Group> </Group> - <EmptySpace max="-2" attributes="0"/> + <EmptySpace max="32767" attributes="0"/> </Group> </Group> </DimensionLayout> @@ -46,20 +41,26 @@ <Group type="103" groupAlignment="0" attributes="0"> <Group type="102" alignment="0" attributes="0"> <Group type="103" groupAlignment="0" attributes="0"> + <Component id="buttonsPanel" alignment="0" min="-2" pref="56" max="-2" attributes="0"/> <Group type="102" alignment="0" attributes="0"> - <Component id="buttonsPanel" min="-2" pref="56" max="-2" attributes="0"/> - <EmptySpace max="-2" attributes="0"/> - <Component id="tableScrollPane" pref="768" max="32767" attributes="0"/> + <EmptySpace min="-2" pref="29" max="-2" attributes="0"/> + <Group type="103" groupAlignment="0" attributes="0"> + <Component id="projectNameOutput" alignment="0" min="-2" pref="15" max="-2" attributes="0"/> + <Component id="projectNameLabel" min="-2" max="-2" attributes="0"/> + </Group> </Group> - <Group type="102" alignment="0" attributes="0"> - <EmptySpace min="-2" pref="61" max="-2" attributes="0"/> + </Group> + <EmptySpace max="-2" attributes="0"/> + <Group type="103" groupAlignment="0" attributes="0"> + <Group type="102" attributes="0"> <Component id="newProjectButton" min="-2" max="-2" attributes="0"/> - <EmptySpace type="separate" max="-2" attributes="0"/> + <EmptySpace min="-2" pref="19" max="-2" attributes="0"/> <Component id="saveProjectButton" min="-2" max="-2" attributes="0"/> <EmptySpace type="separate" max="-2" attributes="0"/> <Component id="openProjectButton" min="-2" max="-2" attributes="0"/> <EmptySpace min="0" pref="0" max="32767" attributes="0"/> </Group> + <Component id="tableScrollPane" pref="768" max="32767" attributes="0"/> </Group> <EmptySpace pref="12" max="32767" attributes="0"/> </Group> @@ -94,7 +95,7 @@ </Property> </Properties> <Events> - <EventHandler event="mouseClicked" listener="java.awt.event.MouseListener" parameters="java.awt.event.MouseEvent" handler="addButtonMouseClicked"/> + <EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="addButtonActionPerformed"/> </Events> <Constraints> <Constraint layoutClass="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout" value="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout$GridBagConstraintsDescription"> @@ -115,7 +116,7 @@ </Property> </Properties> <Events> - <EventHandler event="mouseClicked" listener="java.awt.event.MouseListener" parameters="java.awt.event.MouseEvent" handler="removeButtonMouseClicked"/> + <EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="removeButtonActionPerformed"/> </Events> <Constraints> <Constraint layoutClass="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout" value="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout$GridBagConstraintsDescription"> @@ -136,7 +137,7 @@ </Property> </Properties> <Events> - <EventHandler event="mouseClicked" listener="java.awt.event.MouseListener" parameters="java.awt.event.MouseEvent" handler="selectAllButtonMouseClicked"/> + <EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="selectAllButtonActionPerformed"/> </Events> <Constraints> <Constraint layoutClass="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout" value="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout$GridBagConstraintsDescription"> @@ -157,7 +158,7 @@ </Property> </Properties> <Events> - <EventHandler event="mouseClicked" listener="java.awt.event.MouseListener" parameters="java.awt.event.MouseEvent" handler="deselectAllButtonMouseClicked"/> + <EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="deselectAllButtonActionPerformed"/> </Events> <Constraints> <Constraint layoutClass="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout" value="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout$GridBagConstraintsDescription"> @@ -179,7 +180,7 @@ </Property> </Properties> <Events> - <EventHandler event="mouseClicked" listener="java.awt.event.MouseListener" parameters="java.awt.event.MouseEvent" handler="inflateButtonMouseClicked"/> + <EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="inflateButtonActionPerformed"/> </Events> <Constraints> <Constraint layoutClass="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout" value="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout$GridBagConstraintsDescription"> @@ -195,12 +196,19 @@ <Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor"> <ResourceString bundle="cz/fidentis/analyst/project/Bundle.properties" key="ProjectPanel.analyseButton.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, "{key}")"/> </Property> + <Property name="enabled" type="boolean" value="false"/> + <Property name="maximumSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor"> + <Dimension value="[150, 23]"/> + </Property> + <Property name="minimumSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor"> + <Dimension value="[150, 23]"/> + </Property> <Property name="preferredSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor"> - <Dimension value="[100, 30]"/> + <Dimension value="[150, 30]"/> </Property> </Properties> <Events> - <EventHandler event="mouseClicked" listener="java.awt.event.MouseListener" parameters="java.awt.event.MouseEvent" handler="analyseFaces"/> + <EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="analyseButtonActionPerformed"/> </Events> <Constraints> <Constraint layoutClass="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout" value="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout$GridBagConstraintsDescription"> @@ -223,7 +231,7 @@ </Property> </Properties> <Events> - <EventHandler event="mouseClicked" listener="java.awt.event.MouseListener" parameters="java.awt.event.MouseEvent" handler="saveProjectButtonMouseClicked"/> + <EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="saveProjectButtonActionPerformed"/> </Events> </Component> <Component class="javax.swing.JButton" name="openProjectButton"> @@ -239,7 +247,7 @@ </Property> </Properties> <Events> - <EventHandler event="mouseClicked" listener="java.awt.event.MouseListener" parameters="java.awt.event.MouseEvent" handler="openProjectButtonMouseClicked"/> + <EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="openProjectButtonActionPerformed"/> </Events> </Component> <Component class="javax.swing.JButton" name="newProjectButton"> @@ -252,7 +260,7 @@ </Property> </Properties> <Events> - <EventHandler event="mouseClicked" listener="java.awt.event.MouseListener" parameters="java.awt.event.MouseEvent" handler="newProjectButtonMouseClicked"/> + <EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="newProjectButtonActionPerformed"/> </Events> </Component> <Container class="javax.swing.JScrollPane" name="tableScrollPane"> @@ -264,7 +272,7 @@ <Property name="font" type="java.awt.Font" editor="org.netbeans.beaninfo.editors.FontEditor" postCode="table.getTableHeader().setOpaque(false);
table.getTableHeader().setBackground(new java.awt.Color(204,204,204));
table.getTableHeader().setFont(new java.awt.Font("Tahoma", 0, 18));
model.addTableModelListener(new TableModelListener() {
 public void tableChanged(TableModelEvent e) {
 jTable1TableChanged(e);
 }
});"> <Font name="Tahoma" size="18" style="0"/> </Property> - <Property name="model" type="javax.swing.table.TableModel" editor="org.netbeans.modules.form.RADConnectionPropertyEditor" postCode="table.getColumnModel().getColumn(0).setMaxWidth(50);
table.getColumnModel().getColumn(2).setMaxWidth(75);
table.getTableHeader().getColumnModel().getColumn(0).setMaxWidth(50);
table.getTableHeader().getColumnModel().getColumn(2).setMaxWidth(85);"> + <Property name="model" type="javax.swing.table.TableModel" editor="org.netbeans.modules.form.RADConnectionPropertyEditor" postCode="table.getColumnModel().getColumn(0).setMaxWidth(50);
table.getColumnModel().getColumn(1).setPreferredWidth(400);
table.getColumnModel().getColumn(2).setMaxWidth(250);
table.getColumnModel().getColumn(2).setPreferredWidth(250);
table.getColumnModel().getColumn(3).setMaxWidth(125);
table.getColumnModel().getColumn(3).setPreferredWidth(125);
table.getTableHeader().getColumnModel().getColumn(0).setMaxWidth(50);
table.getTableHeader().getColumnModel().getColumn(1).setPreferredWidth(400);
table.getTableHeader().getColumnModel().getColumn(2).setMaxWidth(250);
table.getTableHeader().getColumnModel().getColumn(2).setPreferredWidth(250);
table.getTableHeader().getColumnModel().getColumn(3).setMaxWidth(125);
table.getTableHeader().getColumnModel().getColumn(3).setPreferredWidth(125);"> <Connection code="model" type="code"/> </Property> <Property name="columnModel" type="javax.swing.table.TableColumnModel" editor="org.netbeans.modules.form.editors2.TableColumnModelEditor"> @@ -289,5 +297,25 @@ </Component> </SubComponents> </Container> + <Component class="javax.swing.JLabel" name="projectNameLabel"> + <Properties> + <Property name="font" type="java.awt.Font" editor="org.netbeans.beaninfo.editors.FontEditor"> + <Font name="Tahoma" size="12" style="1"/> + </Property> + <Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor"> + <ResourceString bundle="cz/fidentis/analyst/project/Bundle.properties" key="ProjectPanel.projectNameLabel.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, "{key}")"/> + </Property> + </Properties> + </Component> + <Component class="javax.swing.JLabel" name="projectNameOutput"> + <Properties> + <Property name="font" type="java.awt.Font" editor="org.netbeans.beaninfo.editors.FontEditor"> + <Font name="Tahoma" size="12" style="0"/> + </Property> + <Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor"> + <ResourceString bundle="cz/fidentis/analyst/project/Bundle.properties" key="ProjectPanel.projectNameOutput.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, "{key}")"/> + </Property> + </Properties> + </Component> </SubComponents> </Form> diff --git a/GUI/src/main/java/cz/fidentis/analyst/project/ProjectPanel.java b/GUI/src/main/java/cz/fidentis/analyst/project/ProjectPanel.java index 1c1d82d6..a262c527 100644 --- a/GUI/src/main/java/cz/fidentis/analyst/project/ProjectPanel.java +++ b/GUI/src/main/java/cz/fidentis/analyst/project/ProjectPanel.java @@ -1,29 +1,32 @@ package cz.fidentis.analyst.project; import cz.fidentis.analyst.faceState.FaceStatePanel; -import com.fasterxml.jackson.databind.ObjectMapper; import cz.fidentis.analyst.Project; -import cz.fidentis.analyst.ProjectConfiguration; import cz.fidentis.analyst.core.FaceTab; +import cz.fidentis.analyst.core.ProgressDialog; import cz.fidentis.analyst.face.HumanFace; import cz.fidentis.analyst.filter.FilterPanel; +import cz.fidentis.analyst.scene.Camera; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; +import java.beans.PropertyChangeEvent; import java.io.File; import java.io.IOException; import java.nio.file.Path; import java.nio.file.Paths; import java.util.ArrayList; +import java.util.Arrays; import java.util.Collections; import java.util.List; -import java.util.prefs.Preferences; import java.util.stream.Collectors; import javax.swing.AbstractAction; import javax.swing.ImageIcon; +import javax.swing.JComboBox; import javax.swing.JFileChooser; import javax.swing.JOptionPane; import javax.swing.JPanel; import javax.swing.JTable; +import javax.swing.SwingWorker; import javax.swing.event.TableModelEvent; import javax.swing.event.TableModelListener; import javax.swing.filechooser.FileNameExtensionFilter; @@ -36,22 +39,22 @@ import org.openide.util.Exceptions; */ public class ProjectPanel extends JPanel { + public static final String SAVE_CURRENT_PROJECT_TITLE = "Save current project"; + public static final String SAVE_NEW_PROJECT_TITLE = "Save new project"; + private Project project; - private List<FaceTab> tabs = new ArrayList<>(); + private static List<FaceTab> tabs = new ArrayList<>(); private ModelsTableModel model = new ModelsTableModel(); /* List of indexes of selected Rows */ private List<Integer> selectedRows = new ArrayList<>(); - private ObjectMapper mapper = new ObjectMapper(); - - private Preferences userPreferences = Preferences.userNodeForPackage(Project.class); - private FaceStatePanel faceStatePanel; private FilterPanel filterPanel; - + + /** * Creates new form ProjectPanel */ @@ -61,6 +64,10 @@ public class ProjectPanel extends JPanel { initComponents(); + table.getColumnModel().getColumn(2).setCellEditor(new TaskCellEditor()); + table.getColumnModel().getColumn(2).setCellRenderer(new TaskCellRenderer()); + table.repaint(); + } /** @@ -85,6 +92,8 @@ public class ProjectPanel extends JPanel { newProjectButton = new javax.swing.JButton(); tableScrollPane = new javax.swing.JScrollPane(); table = new javax.swing.JTable(); + projectNameLabel = new javax.swing.JLabel(); + projectNameOutput = new javax.swing.JLabel(); buttonsPanel.setBorder(javax.swing.BorderFactory.createEtchedBorder()); buttonsPanel.setMinimumSize(new java.awt.Dimension(0, 0)); @@ -93,9 +102,9 @@ public class ProjectPanel extends JPanel { addButton.setFont(new java.awt.Font("Tahoma", 0, 12)); // NOI18N org.openide.awt.Mnemonics.setLocalizedText(addButton, org.openide.util.NbBundle.getMessage(ProjectPanel.class, "ProjectPanel.addButton.text")); // NOI18N addButton.setPreferredSize(new java.awt.Dimension(100, 30)); - addButton.addMouseListener(new java.awt.event.MouseAdapter() { - public void mouseClicked(java.awt.event.MouseEvent evt) { - addButtonMouseClicked(evt); + addButton.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + addButtonActionPerformed(evt); } }); gridBagConstraints = new java.awt.GridBagConstraints(); @@ -108,9 +117,9 @@ public class ProjectPanel extends JPanel { removeButton.setFont(new java.awt.Font("Tahoma", 0, 12)); // NOI18N org.openide.awt.Mnemonics.setLocalizedText(removeButton, org.openide.util.NbBundle.getMessage(ProjectPanel.class, "ProjectPanel.removeButton.text")); // NOI18N removeButton.setPreferredSize(new java.awt.Dimension(100, 30)); - removeButton.addMouseListener(new java.awt.event.MouseAdapter() { - public void mouseClicked(java.awt.event.MouseEvent evt) { - removeButtonMouseClicked(evt); + removeButton.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + removeButtonActionPerformed(evt); } }); gridBagConstraints = new java.awt.GridBagConstraints(); @@ -123,9 +132,9 @@ public class ProjectPanel extends JPanel { selectAllButton.setFont(new java.awt.Font("Tahoma", 0, 12)); // NOI18N org.openide.awt.Mnemonics.setLocalizedText(selectAllButton, org.openide.util.NbBundle.getMessage(ProjectPanel.class, "ProjectPanel.selectAllButton.text")); // NOI18N selectAllButton.setPreferredSize(new java.awt.Dimension(100, 30)); - selectAllButton.addMouseListener(new java.awt.event.MouseAdapter() { - public void mouseClicked(java.awt.event.MouseEvent evt) { - selectAllButtonMouseClicked(evt); + selectAllButton.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + selectAllButtonActionPerformed(evt); } }); gridBagConstraints = new java.awt.GridBagConstraints(); @@ -138,9 +147,9 @@ public class ProjectPanel extends JPanel { deselectAllButton.setFont(new java.awt.Font("Tahoma", 0, 12)); // NOI18N org.openide.awt.Mnemonics.setLocalizedText(deselectAllButton, org.openide.util.NbBundle.getMessage(ProjectPanel.class, "ProjectPanel.deselectAllButton.text")); // NOI18N deselectAllButton.setPreferredSize(new java.awt.Dimension(100, 30)); - deselectAllButton.addMouseListener(new java.awt.event.MouseAdapter() { - public void mouseClicked(java.awt.event.MouseEvent evt) { - deselectAllButtonMouseClicked(evt); + deselectAllButton.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + deselectAllButtonActionPerformed(evt); } }); gridBagConstraints = new java.awt.GridBagConstraints(); @@ -154,9 +163,9 @@ public class ProjectPanel extends JPanel { org.openide.awt.Mnemonics.setLocalizedText(inflateButton, org.openide.util.NbBundle.getMessage(ProjectPanel.class, "ProjectPanel.inflateButton.text")); // NOI18N inflateButton.setAlignmentX(0.5F); inflateButton.setPreferredSize(new java.awt.Dimension(100, 30)); - inflateButton.addMouseListener(new java.awt.event.MouseAdapter() { - public void mouseClicked(java.awt.event.MouseEvent evt) { - inflateButtonMouseClicked(evt); + inflateButton.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + inflateButtonActionPerformed(evt); } }); gridBagConstraints = new java.awt.GridBagConstraints(); @@ -168,10 +177,13 @@ public class ProjectPanel extends JPanel { analyseButton.setFont(new java.awt.Font("Tahoma", 1, 12)); // NOI18N org.openide.awt.Mnemonics.setLocalizedText(analyseButton, org.openide.util.NbBundle.getMessage(ProjectPanel.class, "ProjectPanel.analyseButton.text")); // NOI18N - analyseButton.setPreferredSize(new java.awt.Dimension(100, 30)); - analyseButton.addMouseListener(new java.awt.event.MouseAdapter() { - public void mouseClicked(java.awt.event.MouseEvent evt) { - analyseFaces(evt); + analyseButton.setEnabled(false); + analyseButton.setMaximumSize(new java.awt.Dimension(150, 23)); + analyseButton.setMinimumSize(new java.awt.Dimension(150, 23)); + analyseButton.setPreferredSize(new java.awt.Dimension(150, 30)); + analyseButton.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + analyseButtonActionPerformed(evt); } }); gridBagConstraints = new java.awt.GridBagConstraints(); @@ -183,26 +195,26 @@ public class ProjectPanel extends JPanel { saveProjectButton.setFont(new java.awt.Font("Tahoma", 0, 12)); // NOI18N saveProjectButton.setIcon(new javax.swing.ImageIcon(getClass().getResource("/save100x24.png"))); // NOI18N org.openide.awt.Mnemonics.setLocalizedText(saveProjectButton, org.openide.util.NbBundle.getMessage(ProjectPanel.class, "ProjectPanel.saveProjectButton.text")); // NOI18N - saveProjectButton.addMouseListener(new java.awt.event.MouseAdapter() { - public void mouseClicked(java.awt.event.MouseEvent evt) { - saveProjectButtonMouseClicked(evt); + saveProjectButton.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + saveProjectButtonActionPerformed(evt); } }); openProjectButton.setFont(new java.awt.Font("Tahoma", 0, 12)); // NOI18N openProjectButton.setIcon(new javax.swing.ImageIcon(getClass().getResource("/open100x24.png"))); // NOI18N org.openide.awt.Mnemonics.setLocalizedText(openProjectButton, org.openide.util.NbBundle.getMessage(ProjectPanel.class, "ProjectPanel.openProjectButton.text")); // NOI18N - openProjectButton.addMouseListener(new java.awt.event.MouseAdapter() { - public void mouseClicked(java.awt.event.MouseEvent evt) { - openProjectButtonMouseClicked(evt); + openProjectButton.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + openProjectButtonActionPerformed(evt); } }); newProjectButton.setIcon(new javax.swing.ImageIcon(getClass().getResource("/new100x24.png"))); // NOI18N org.openide.awt.Mnemonics.setLocalizedText(newProjectButton, org.openide.util.NbBundle.getMessage(ProjectPanel.class, "ProjectPanel.newProjectButton.text")); // NOI18N - newProjectButton.addMouseListener(new java.awt.event.MouseAdapter() { - public void mouseClicked(java.awt.event.MouseEvent evt) { - newProjectButtonMouseClicked(evt); + newProjectButton.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + newProjectButtonActionPerformed(evt); } }); @@ -218,9 +230,17 @@ public class ProjectPanel extends JPanel { }); table.setModel(model); table.getColumnModel().getColumn(0).setMaxWidth(50); - table.getColumnModel().getColumn(2).setMaxWidth(75); + table.getColumnModel().getColumn(1).setPreferredWidth(400); + table.getColumnModel().getColumn(2).setMaxWidth(250); + table.getColumnModel().getColumn(2).setPreferredWidth(250); + table.getColumnModel().getColumn(3).setMaxWidth(125); + table.getColumnModel().getColumn(3).setPreferredWidth(125); table.getTableHeader().getColumnModel().getColumn(0).setMaxWidth(50); - table.getTableHeader().getColumnModel().getColumn(2).setMaxWidth(85); + table.getTableHeader().getColumnModel().getColumn(1).setPreferredWidth(400); + table.getTableHeader().getColumnModel().getColumn(2).setMaxWidth(250); + table.getTableHeader().getColumnModel().getColumn(2).setPreferredWidth(250); + table.getTableHeader().getColumnModel().getColumn(3).setMaxWidth(125); + table.getTableHeader().getColumnModel().getColumn(3).setPreferredWidth(125); table.setDragEnabled(true); table.setRowHeight(60); table.setSelectionBackground(new java.awt.Color(102, 204, 255)); @@ -233,6 +253,12 @@ public class ProjectPanel extends JPanel { }); tableScrollPane.setViewportView(table); + projectNameLabel.setFont(new java.awt.Font("Tahoma", 1, 12)); // NOI18N + org.openide.awt.Mnemonics.setLocalizedText(projectNameLabel, org.openide.util.NbBundle.getMessage(ProjectPanel.class, "ProjectPanel.projectNameLabel.text")); // NOI18N + + projectNameOutput.setFont(new java.awt.Font("Tahoma", 0, 12)); // NOI18N + org.openide.awt.Mnemonics.setLocalizedText(projectNameOutput, org.openide.util.NbBundle.getMessage(ProjectPanel.class, "ProjectPanel.projectNameOutput.text")); // NOI18N + javax.swing.GroupLayout layout = new javax.swing.GroupLayout(this); this.setLayout(layout); layout.setHorizontalGroup( @@ -240,37 +266,39 @@ public class ProjectPanel extends JPanel { .addGroup(layout.createSequentialGroup() .addGap(41, 41, 41) .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addComponent(buttonsPanel, javax.swing.GroupLayout.DEFAULT_SIZE, 1025, Short.MAX_VALUE) + .addComponent(buttonsPanel, javax.swing.GroupLayout.DEFAULT_SIZE, 968, Short.MAX_VALUE) .addComponent(tableScrollPane)) + .addGap(18, 18, 18) .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addGroup(layout.createSequentialGroup() - .addGap(50, 50, 50) - .addComponent(newProjectButton)) - .addGroup(javax.swing.GroupLayout.Alignment.TRAILING, layout.createSequentialGroup() - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) - .addComponent(saveProjectButton))) - .addGroup(javax.swing.GroupLayout.Alignment.TRAILING, layout.createSequentialGroup() - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) - .addComponent(openProjectButton))) - .addContainerGap()) + .addComponent(newProjectButton) + .addComponent(saveProjectButton) + .addComponent(openProjectButton) + .addGroup(layout.createSequentialGroup() + .addComponent(projectNameLabel) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED) + .addComponent(projectNameOutput, javax.swing.GroupLayout.PREFERRED_SIZE, 122, javax.swing.GroupLayout.PREFERRED_SIZE))) + .addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)) ); layout.setVerticalGroup( layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) .addGroup(layout.createSequentialGroup() .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addComponent(buttonsPanel, javax.swing.GroupLayout.PREFERRED_SIZE, 56, javax.swing.GroupLayout.PREFERRED_SIZE) .addGroup(layout.createSequentialGroup() - .addComponent(buttonsPanel, javax.swing.GroupLayout.PREFERRED_SIZE, 56, javax.swing.GroupLayout.PREFERRED_SIZE) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) - .addComponent(tableScrollPane, javax.swing.GroupLayout.DEFAULT_SIZE, 768, Short.MAX_VALUE)) + .addGap(29, 29, 29) + .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addComponent(projectNameOutput, javax.swing.GroupLayout.PREFERRED_SIZE, 15, javax.swing.GroupLayout.PREFERRED_SIZE) + .addComponent(projectNameLabel)))) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) .addGroup(layout.createSequentialGroup() - .addGap(61, 61, 61) .addComponent(newProjectButton) - .addGap(18, 18, 18) + .addGap(19, 19, 19) .addComponent(saveProjectButton) .addGap(18, 18, 18) .addComponent(openProjectButton) - .addGap(0, 0, Short.MAX_VALUE))) + .addGap(0, 0, Short.MAX_VALUE)) + .addComponent(tableScrollPane, javax.swing.GroupLayout.DEFAULT_SIZE, 768, Short.MAX_VALUE)) .addContainerGap(12, Short.MAX_VALUE)) ); }// </editor-fold>//GEN-END:initComponents @@ -307,22 +335,6 @@ public class ProjectPanel extends JPanel { return project.isSaved(); } - private void newProjectButtonMouseClicked(java.awt.event.MouseEvent evt) {//GEN-FIRST:event_newProjectButtonMouseClicked - if (loadNewProject()) { - newProject(); - } - }//GEN-LAST:event_newProjectButtonMouseClicked - - private void openProjectButtonMouseClicked(java.awt.event.MouseEvent evt) {//GEN-FIRST:event_openProjectButtonMouseClicked - if (loadNewProject()) { - openProject(); - } - }//GEN-LAST:event_openProjectButtonMouseClicked - - private void saveProjectButtonMouseClicked(java.awt.event.MouseEvent evt) {//GEN-FIRST:event_saveProjectButtonMouseClicked - saveProject(); - }//GEN-LAST:event_saveProjectButtonMouseClicked - private void tableMouseClicked(java.awt.event.MouseEvent evt) {//GEN-FIRST:event_tableMouseClicked if (table.getSelectedRowCount() == 0) { checkFaceState(null, false); @@ -351,7 +363,7 @@ public class ProjectPanel extends JPanel { String name = model.getValueAt(selectedRows.get(0), 1).toString(); HumanFace face = project.loadFace(name); - createSingleFaceTab(face, name, false); + createSingleFaceTab(face, name, null); } /** @@ -378,9 +390,9 @@ public class ProjectPanel extends JPanel { if (choice == 0) { - createFaceToFaceTab(face1, face2, name1 + ":" + name2, false); + createFaceToFaceTab(face1, face2, name1 + ":" + name2, null); } else { - createFaceToFaceTab(face2, face1, name2 + ":" + name1, false); + createFaceToFaceTab(face2, face1, name2 + ":" + name1, null); } } @@ -395,31 +407,10 @@ public class ProjectPanel extends JPanel { .map(s -> project.getCfg().getPathToFaceByName(s)) .collect(Collectors.toList()); - createManyToManyTab("N:N", faces); + createManyToManyTab(String.format("%s:N", String.valueOf(selectedRows.size())), faces); } - private void inflateButtonMouseClicked(java.awt.event.MouseEvent evt) {//GEN-FIRST:event_inflateButtonMouseClicked - model.inflateSelection(); - }//GEN-LAST:event_inflateButtonMouseClicked - - private void deselectAllButtonMouseClicked(java.awt.event.MouseEvent evt) {//GEN-FIRST:event_deselectAllButtonMouseClicked - deselectAllRows(); - }//GEN-LAST:event_deselectAllButtonMouseClicked - - private void selectAllButtonMouseClicked(java.awt.event.MouseEvent evt) {//GEN-FIRST:event_selectAllButtonMouseClicked - model.setAllRowsSelection(true); - }//GEN-LAST:event_selectAllButtonMouseClicked - - private void removeButtonMouseClicked(java.awt.event.MouseEvent evt) {//GEN-FIRST:event_removeButtonMouseClicked - removeSelectedFaces(); - }//GEN-LAST:event_removeButtonMouseClicked - - private void addButtonMouseClicked(java.awt.event.MouseEvent evt) {//GEN-FIRST:event_addButtonMouseClicked - loadModel(false); - }//GEN-LAST:event_addButtonMouseClicked - - private void analyseFaces(java.awt.event.MouseEvent evt) {//GEN-FIRST:event_analyseFaces - + private void analyseButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_analyseButtonActionPerformed switch (selectedRows.size()) { case 0: @@ -438,7 +429,58 @@ public class ProjectPanel extends JPanel { analyseManyToManyFaces(); break; } - }//GEN-LAST:event_analyseFaces + }//GEN-LAST:event_analyseButtonActionPerformed + + private void inflateButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_inflateButtonActionPerformed + model.inflateSelection(); + }//GEN-LAST:event_inflateButtonActionPerformed + + private void deselectAllButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_deselectAllButtonActionPerformed + deselectAllRows(); + }//GEN-LAST:event_deselectAllButtonActionPerformed + + private void selectAllButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_selectAllButtonActionPerformed + model.setAllRowsSelection(true); + }//GEN-LAST:event_selectAllButtonActionPerformed + + private void removeButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_removeButtonActionPerformed + if (selectedRows.isEmpty()) { + JOptionPane.showMessageDialog(this, + "No face chosen"); + return; + } + int answer = JOptionPane.showConfirmDialog(null, + "Do you really want to remove all selected faces? Changes will be discarded", + "", JOptionPane.YES_NO_OPTION, JOptionPane.WARNING_MESSAGE); + + if (answer == JOptionPane.YES_OPTION) { + removeSelectedFaces(); + saveProject(); + } + }//GEN-LAST:event_removeButtonActionPerformed + + private void addButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_addButtonActionPerformed + loadModel(false); + saveProject(); + }//GEN-LAST:event_addButtonActionPerformed + + private void newProjectButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_newProjectButtonActionPerformed + if (loadNewProject()) { + newProject(); + } + }//GEN-LAST:event_newProjectButtonActionPerformed + + private void saveProjectButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_saveProjectButtonActionPerformed + if (saveNewProject(SAVE_CURRENT_PROJECT_TITLE)) { + JOptionPane.showMessageDialog(this, "Project successfully saved!"); + } + }//GEN-LAST:event_saveProjectButtonActionPerformed + + private void openProjectButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_openProjectButtonActionPerformed + if (loadNewProject()) { + openProject(); + } + }//GEN-LAST:event_openProjectButtonActionPerformed /** * Removes selected faces (those which are checked in check boxes) @@ -454,9 +496,21 @@ public class ProjectPanel extends JPanel { }); while(!tabsToClose.isEmpty()) { - tabsToClose.remove(0).close(); + + // Remove tasks from other task + if (tabsToClose.get(0).getFaces().isEmpty()) { + model.removeTask(tabsToClose.get(0).getFace1().getShortName(), tabsToClose.get(0).getName()); + if (tabsToClose.get(0).getFace2() != null) { + model.removeTask(tabsToClose.get(0).getFace2().getShortName(), tabsToClose.get(0).getName()); + } + + removeTaskFileFromProjectDir(tabsToClose.get(0)); + } + + tabsToClose.get(0).close(); + tabs.remove(tabsToClose.remove(0)); } - + // Remove already loaded and stored face info faceStatePanel.removeFaceByName(name); @@ -496,6 +550,24 @@ public class ProjectPanel extends JPanel { selectedRows.remove((Integer)row); } } + + // Disable when none faces are selected + analyseButton.setEnabled(!selectedRows.isEmpty()); + + // Set text of analyse button + switch (selectedRows.size()) { + case 0: + case 1: + analyseButton.setText("Create Task"); + break; + case 2: + analyseButton.setText("Create 1:1 Task"); + break; + default: + analyseButton.setText(String.format("Create %d:N Task", selectedRows.size())); + break; + } + } else if (e.getType() == javax.swing.event.TableModelEvent.INSERT || e.getType() == javax.swing.event.TableModelEvent.DELETE) { project.setSaved(false); } @@ -507,8 +579,13 @@ public class ProjectPanel extends JPanel { * from FileChooserBuilder */ public void loadModel(boolean loadFromFile) { + + // Storing files with tasks which will be opened + List<File> tasksToOpen = new ArrayList<>(); + File[] files; + // Selects files with faces (by dialog or from JSON file) if (!loadFromFile) { files = new FileChooserBuilder(ProjectTopComp.class) @@ -527,6 +604,7 @@ public class ProjectPanel extends JPanel { if (files == null) { System.out.print("No file chosen."); } else { + for (File file : files) { Path path = Paths.get(file.getAbsolutePath()); @@ -534,9 +612,14 @@ public class ProjectPanel extends JPanel { .lastIndexOf(File.separatorChar) + 1, path.toString().lastIndexOf('.')); + tasksToOpen.addAll(loadFaceTasks(name)); + if (project.addNewPath(path)) { - model.addRowWithName(name, path); + ActionListener taskSelected = (ActionEvent e) -> { + openTask(e); + }; + model.addRowWithName(name, path, taskSelected); } else { JOptionPane.showMessageDialog(this, @@ -545,95 +628,218 @@ public class ProjectPanel extends JPanel { } } } + + loadTasks(tasksToOpen); } /** - * Loads tabs from project file + * Loads all tasks from files + * @param tasksToOpen all files with tasks which should be opened */ - private void loadTabs() { + private void loadTasks(List<File> tasksToOpen) { + + if (tasksToOpen.isEmpty()) { + return; + } - // Load Single face tabs - project.getCfg().getSingleTabFaces().forEach(name -> { - HumanFace face1 = project.loadFace(name); - if (face1 != null) { - createSingleFaceTab(face1, name, true); + ProgressDialog progressDialog = new ProgressDialog(this, "Loading tasks"); + LoadTasksTask task = new LoadTasksTask(tasksToOpen, progressDialog); + + task.addPropertyChangeListener((PropertyChangeEvent evt) -> { + if ("state".equals(evt.getPropertyName()) && (SwingWorker.StateValue.DONE.equals(evt.getNewValue()))) { + + List<Task> tasksRestored = task.getTasksRestored(); + if (!tasksRestored.isEmpty()) { + restoreTasks(tasksRestored); + } } + }); - // Load Face to face tabs - project.getCfg().getFaceToFaceTabFaces().keySet().forEach(name -> { - HumanFace face1 = project.loadFace(name); - if (face1 != null) { - project.getCfg().getFaceToFaceTabFaces().get(name).forEach(otherName -> { - HumanFace face2 = project.loadFace(otherName); - if (face2 != null) { - createFaceToFaceTab(face1, face2, name + ":" + otherName, true); - } - }); + progressDialog.runTask(task); + } + + /** + * Restores data from tasks to tabs + * @param tasksRestored tasks which should be restored to tabs + */ + private void restoreTasks(List<Task> tasksRestored) { + + tasksRestored.forEach(task -> { + + // Face to face analysis + if (task.getSecondary() != null) { + createFaceToFaceTab(task.getPrimary(), task.getSecondary(), + task.getPrimary().getShortName() + ":" + task.getSecondary().getShortName(), + task.getCamera()); + + // Single face analysis + } else { + createSingleFaceTab(task.getPrimary(), task.getPrimary().getShortName(), task.getCamera()); } }); } + /** + * Opens and requests active task from tasks + * @param e ActionEvent + */ + private void openTask(ActionEvent e) { + + JComboBox comboBox = (JComboBox) e.getSource(); + String taskName = String.valueOf(comboBox.getSelectedItem()); + + tabs.stream().filter(tab -> (tab.getName().equals(taskName))).forEachOrdered(tab -> { + + if (!tab.isOpened()) { + tab.open(); + } + tab.requestActive(); + + }); + + } + + /** + * Ends task + * @param e ActionEvent + */ + public void endTask(ActionEvent e) { + + int answer = JOptionPane.showConfirmDialog(null, + "Do you really want to end this task? Changes will be discarded", "", JOptionPane.YES_NO_OPTION, JOptionPane.WARNING_MESSAGE); + + if (answer == JOptionPane.YES_OPTION) { + + FaceTab tab = (FaceTab)e.getSource(); + + if (tab.getFaces().isEmpty()) { + + // Remove task from face1 tasks + model.removeTask(tab.getFace1().getShortName(), tab.getName()); + + if (tab.getFace2() != null) { + // Remove task from face2 tasks + model.removeTask(tab.getFace2().getShortName(), tab.getName()); + } + + removeTaskFileFromProjectDir(tab); + } + + tab.close(); + tabs.remove(tab); + } + + } + + /** + * Removes task file from project directory - if project is saved + * @param tab face tab with task which is about to be ended + */ + public void removeTaskFileFromProjectDir(FaceTab tab) { + + // If projects exists, try to delete task from project directory + if (!project.getPathToProjectFile().isEmpty()) { + String pathToProjectDir = project.getPathToProjectFile() + .substring(0, project.getPathToProjectFile().lastIndexOf(File.separatorChar)); + + String name = tab.getFace1().getShortName(); + + if (tab.getFace2() != null) { + name = tab.getFace1().getShortName() + "_TO_" + tab.getFace2().getShortName(); + } + + String pathToTask = pathToProjectDir + File.separatorChar + name + ".bin"; + + Task.endTask(pathToTask); + + } + } + /** * Creates and opens tab with one face * @param face which will be analyzed * @param name name of the tab (name of the model) + * @param camera camera or null */ - private void createSingleFaceTab(HumanFace face, String name, boolean loadFromFile) { - ActionListener tabCloseListener = new AbstractAction() { + public void createSingleFaceTab(HumanFace face, String name, Camera camera) { + // Listener for ending task + ActionListener endTaskListener = new AbstractAction() { @Override public void actionPerformed(ActionEvent e) { - closeTab(e); + endTask(e); } }; - FaceTab newTab = new FaceTab(face, null, name, tabCloseListener, project); - + FaceTab newTab = new FaceTab(face, null, name, endTaskListener, project); + if (!tabs.contains(newTab)) { - tabs.add(newTab); - if (!loadFromFile) { - project.addNewSingleFaceTabFace(name); + + if (camera != null) { + newTab.setCamera(camera); } + + model.addNewTask(name, name); + tabs.add(newTab); + newTab.open(); newTab.requestActive(); + this.project.setSaved(false); } else { - tabs.stream().filter(t -> (t.equals(newTab))).forEachOrdered(t -> { + if (!t.isOpened()) { + t.open(); + } t.requestActive(); }); } } + /** * Creates and opens tab with two faces (1:1 analysis) * @param face1 which will be analyzed * @param face2 which will be analyzed - * @param name name of the tab + * @param nameOfTab name of the tab + * @param camera camera or null */ - private void createFaceToFaceTab(HumanFace face1, HumanFace face2, String nameOfTab, boolean loadFromFile) { - ActionListener tabCloseListener = new AbstractAction() { + public void createFaceToFaceTab(HumanFace face1, HumanFace face2, String nameOfTab, Camera camera) { + + // Listener for ending task + ActionListener endTaskListener = new AbstractAction() { @Override public void actionPerformed(ActionEvent e) { - closeTab(e); + endTask(e); } + }; - FaceTab newTab = new FaceTab(face1, face2, nameOfTab, tabCloseListener, project); + FaceTab newTab = new FaceTab(face1, face2, nameOfTab, endTaskListener, project); if (!tabs.contains(newTab)) { + + if (camera != null) { + newTab.setCamera(camera); + } + model.addNewTask(face1.getShortName(), nameOfTab); + model.addNewTask(face2.getShortName(), nameOfTab); + tabs.add(newTab); - if (!loadFromFile) { - project.addNewFaceToFaceTabFace(face1.getShortName(), face2.getShortName()); - } + newTab.open(); newTab.requestActive(); + this.project.setSaved(false); + } else { - tabs.stream().filter(t -> (t.equals(newTab))).forEachOrdered(t -> { + tabs.stream().filter(t -> (t.equals(newTab))).forEachOrdered(t -> { + if (!t.isOpened()) { + t.open(); + } t.requestActive(); }); } @@ -644,14 +850,17 @@ public class ProjectPanel extends JPanel { * @param faces faces to be analyzed * @param name name of the tab */ - private void createManyToManyTab(String name, List<Path> faces) { - ActionListener tabCloseListener = new AbstractAction() { + public void createManyToManyTab(String name, List<Path> faces) { + + // Listener for ending task + ActionListener endTaskListener = new AbstractAction() { @Override public void actionPerformed(ActionEvent e) { - closeTab(e); + endTask(e); } }; - FaceTab newTab = new FaceTab(faces, name, tabCloseListener); + + FaceTab newTab = new FaceTab(faces, name, endTaskListener); if (!tabs.contains(newTab)) { tabs.add(newTab); } @@ -675,7 +884,7 @@ public class ProjectPanel extends JPanel { * project */ public void openExistingOrNewProject() { - File recentProjectFile = getRecentProject(); + File recentProjectFile = project.getRecentProject(); if (recentProjectFile != null) { openProjectFromFile(recentProjectFile); @@ -697,23 +906,46 @@ public class ProjectPanel extends JPanel { if (choice == 1) { openProject(); + } else { + saveNewProject(SAVE_NEW_PROJECT_TITLE); + projectNameOutput.setText(project.getProjectName()); } } + /** + * Serializes all currently opened tasks + */ + public static void serializeTasks() { + + tabs.forEach(tab -> { + try { + tab.serializeTask(); + } catch (IOException ex) { + Exceptions.printStackTrace(ex); + } + }); + } + /** * Resets all project attributes */ - private void resetProject() { + public void closeProject() { + + if (!"".equals(this.project.getPathToProjectFile())) { + serializeTasks(); + } while (!tabs.isEmpty()) { tabs.get(0).close(); + tabs.remove(0); } + faceStatePanel.clearLoadedFaces(); filterPanel.clearFiltering(); model.setRowCount(0); checkFaceState(null, false); selectedRows.clear(); - userPreferences.remove("pathToMostRecentProject"); + project.closeProject(); } /** @@ -723,12 +955,15 @@ public class ProjectPanel extends JPanel { */ private boolean loadNewProject() { if (!project.isSaved()) { - int showConfirmDialog = JOptionPane.showConfirmDialog(this, "Project is not saved. Would you like to save project?", "Save project", JOptionPane.YES_NO_CANCEL_OPTION); + int showConfirmDialog = JOptionPane.showConfirmDialog(this, + "Project is not saved. Would you like to save project?", + "Save project", + JOptionPane.YES_NO_CANCEL_OPTION); switch (showConfirmDialog) { case JOptionPane.YES_OPTION: - saveProject(); + saveNewProject(SAVE_CURRENT_PROJECT_TITLE); break; case JOptionPane.CANCEL_OPTION: case JOptionPane.CLOSED_OPTION: @@ -741,43 +976,62 @@ public class ProjectPanel extends JPanel { } /** - * Saves current project + * Tries to save current project - project might not be saved + * @return true if project was saved successfully, false otherwise */ - public void saveProject() { - - File file; - + public boolean saveProject() { + File file = null; + // If current project was saved before - String path = userPreferences.get("pathToMostRecentProject", ""); + String path = project.getPathToProjectFile(); + if (path != null && !path.isEmpty()) { file = Paths.get(path).toFile(); - - // Project was not saved before, user chooses new path where to save project - } else { - JFileChooser chooser = new JFileChooser(); - //chooser.setFileSelectionMode(JFileChooser.DIRECTORIES_ONLY); - chooser.setFileFilter(new FileNameExtensionFilter("json files (*.json)", "json")); - chooser.setAcceptAllFileFilterUsed(true); - chooser.showSaveDialog(null); - - file = chooser.getSelectedFile(); } if (file != null) { - String filePath = file.getAbsolutePath(); - if (!filePath.endsWith(".json")) { - file = new File(filePath.concat(".json")); - } + project.saveProject(file); + projectNameOutput.setText(project.getProjectName()); + return true; + } + return false; + } + + /** + * Saves new project + * @param title of chooser + * @return true if project was saved successfully, false otherwise + */ + public boolean saveNewProject(String title) { + + if (saveProject()) { + return true; + } + + File file; + + JFileChooser chooser = new JFileChooser(); + + //chooser.setFileSelectionMode(JFileChooser.DIRECTORIES_ONLY); + //chooser.setFileFilter(new FileNameExtensionFilter("json files (*.json)", "json")); + chooser.setAcceptAllFileFilterUsed(true); + chooser.setDialogTitle(title); + chooser.showSaveDialog(null); + file = chooser.getSelectedFile(); + + if (file != null) { + + // Create new project folder + file.mkdir(); + String pathToFolder = file.getAbsolutePath(); + String pathToProject = pathToFolder.concat(File.separatorChar + chooser.getName(file) + ".json"); - try { - mapper.writeValue(file, project.getCfg()); - userPreferences.put("pathToMostRecentProject", file.getAbsolutePath()); - project.setSaved(true); - } catch (IOException ex) { - Exceptions.printStackTrace(ex); - } + // Create project file inside the project folder + file = new File(pathToProject); + + return project.saveProject(file); } - + return false; } /** @@ -787,37 +1041,19 @@ public class ProjectPanel extends JPanel { private void openProjectFromFile(File f) { if (f != null) { - try { - resetProject(); - project.setCfg(mapper.readValue(f, ProjectConfiguration.class)); - loadModel(true); - loadTabs(); - userPreferences.put("pathToMostRecentProject", f.getAbsolutePath()); - project.setSaved(true); - } catch (IOException ex) { - //Exceptions.printStackTrace(ex); + + closeProject(); + if (!project.openProjectFromFile(f)) { JOptionPane.showMessageDialog(this, - "Couldn't load project", - "Loading project failed", - JOptionPane.ERROR_MESSAGE); + "Couldn't load project", + "Loading project failed", + JOptionPane.ERROR_MESSAGE); } + loadModel(true); + projectNameOutput.setText(project.getProjectName()); } } - /** - * Loads most recent project from user preferences - * @return File where project is saved, null if no project was found - */ - public File getRecentProject() { - - String path = userPreferences.get("pathToMostRecentProject", ""); - if (path.equals("")) { - return null; - } - Path f = Paths.get(path); - return f.toFile(); - } - /** * Opens project, which user selects in File Chooser */ @@ -825,12 +1061,12 @@ public class ProjectPanel extends JPanel { File f; f = new FileChooserBuilder(ProjectTopComp.class) - .setTitle("Choose existing project") - .setDefaultWorkingDirectory(new File(System.getProperty("user.home"))) - .setFileFilter(new FileNameExtensionFilter("json files (*.json)", "json")) - .setAcceptAllFileFilterUsed(true) - .showOpenDialog(); - + .setTitle("Choose existing project") + .setDefaultWorkingDirectory(new File(System.getProperty("user.home"))) + .setFileFilter(new FileNameExtensionFilter("json files (*.json)", "json")) + .setAcceptAllFileFilterUsed(true) + .showOpenDialog(); + openProjectFromFile(f); } @@ -838,32 +1074,10 @@ public class ProjectPanel extends JPanel { * Creates new project */ private void newProject() { - resetProject(); - project.setCfg(new ProjectConfiguration()); - project.setSaved(true); - } - - /** - * Closes tab - * @param e ActionEvent - */ - private void closeTab(ActionEvent e) { - FaceTab tab = (FaceTab)e.getSource(); - - for (FaceTab t : tabs) { - if (t.equals(tab)) { - - if (e.getActionCommand().equals("FaceTab")) { - this.project.removeFaceTab(t.getNameOfFace1()); - } else if (e.getActionCommand().equals("FaceToFaceTab")){ - this.project.removeFaceToFaceTab(t.getNameOfFace1(), t.getNameOfFace2()); - } - tabs.remove(t); - break; - } - } - - //this.requestActive(); + closeProject(); + project.newProject(); + saveNewProject(SAVE_NEW_PROJECT_TITLE); + projectNameOutput.setText(project.getProjectName()); } /** @@ -883,7 +1097,28 @@ public class ProjectPanel extends JPanel { faceStatePanel.loadFaceGeometryInfo(face); checkFaceState(name, true); } + + /** + * Gets files where face is primary face + * @param faceName name of the face + * @return Files with serialized tasks where face is primary face + */ + public List<File> loadFaceTasks(String faceName) { + + if ("".equals(project.getPathToProjectFile())) { + return Collections.EMPTY_LIST; + } + + Path pathToProjectFolder = Paths.get(project.getPathToProjectFile() + .substring(0, project.getPathToProjectFile().lastIndexOf(File.separatorChar))); + File dir = new File(pathToProjectFolder.toString()); + + File[] files = dir.listFiles((File dir1, String name1) -> name1.startsWith(faceName)); + + return Arrays.asList(files); + } + // Variables declaration - do not modify//GEN-BEGIN:variables private javax.swing.JButton addButton; private javax.swing.JButton analyseButton; @@ -892,6 +1127,8 @@ public class ProjectPanel extends JPanel { private javax.swing.JButton inflateButton; private javax.swing.JButton newProjectButton; private javax.swing.JButton openProjectButton; + private javax.swing.JLabel projectNameLabel; + private javax.swing.JLabel projectNameOutput; private javax.swing.JButton removeButton; private javax.swing.JButton saveProjectButton; private javax.swing.JButton selectAllButton; diff --git a/GUI/src/main/java/cz/fidentis/analyst/project/ProjectTopComp.java b/GUI/src/main/java/cz/fidentis/analyst/project/ProjectTopComp.java index 97876032..04bf8e66 100644 --- a/GUI/src/main/java/cz/fidentis/analyst/project/ProjectTopComp.java +++ b/GUI/src/main/java/cz/fidentis/analyst/project/ProjectTopComp.java @@ -5,11 +5,9 @@ import cz.fidentis.analyst.faceState.FaceStatePanel; import cz.fidentis.analyst.core.ControlPanel; import cz.fidentis.analyst.core.OutputWindowThread; import cz.fidentis.analyst.core.TopControlPanel; -import cz.fidentis.analyst.gui.Installer; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import javax.swing.GroupLayout; -import javax.swing.JOptionPane; import javax.swing.JScrollPane; import javax.swing.LayoutStyle; import org.netbeans.api.settings.ConvertAsProperties; @@ -50,7 +48,6 @@ public final class ProjectTopComp extends TopComponent { private final ProjectPanel projectPanel; private final TopControlPanel controlPanel; - //private final JScrollPane projectPanelScrollPane; private final JScrollPane controlPanelScrollPane; public static final int CONTROL_PANEL_TAB_POSITION_FILTER_PANEL = 1; @@ -104,8 +101,6 @@ public final class ProjectTopComp extends TopComponent { // Asks user whether he wants to create new project or open existing projectPanel.openExistingOrNewProject(); - // Pass this class to installer so it can call method of this class on close - Installer inst = new Installer(this); this.repaint(); } @@ -159,21 +154,4 @@ public final class ProjectTopComp extends TopComponent { String version = p.getProperty("version"); // TODO read your settings according to their version } - - - /** - * Checks whether currently opened project is saved or not and asks user - * whether he wants to save it or not on close - */ - public void saveProjectOnClose() { - if (!projectPanel.isProjectSaved()) { - - int save = JOptionPane.showConfirmDialog(null, - "Project is not saved. Would you like to save project?", "Save project", JOptionPane.YES_NO_OPTION, JOptionPane.QUESTION_MESSAGE); - - if (save == JOptionPane.YES_OPTION) { - projectPanel.saveProject(); - } - } - } } diff --git a/GUI/src/main/java/cz/fidentis/analyst/project/Task.java b/GUI/src/main/java/cz/fidentis/analyst/project/Task.java new file mode 100644 index 00000000..9488c740 --- /dev/null +++ b/GUI/src/main/java/cz/fidentis/analyst/project/Task.java @@ -0,0 +1,116 @@ +package cz.fidentis.analyst.project; + +import cz.fidentis.analyst.face.HumanFace; +import cz.fidentis.analyst.scene.Camera; +import java.io.BufferedInputStream; +import java.io.BufferedOutputStream; +import java.io.File; +import java.io.FileInputStream; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.ObjectInputStream; +import java.io.ObjectOutputStream; +import java.io.RandomAccessFile; +import java.io.Serializable; +import java.nio.file.Paths; + +/** + * + * @author Matej Kovar + */ +public class Task implements Serializable { + + private HumanFace primary = null; + private HumanFace secondary = null; + private Camera camera = null; + + /** + * Constructor for task + * @param primary human face + * @param secondary human face (or null) + * @param camera camera + */ + public Task(HumanFace primary, HumanFace secondary, Camera camera) { + this.primary = primary; + this.secondary = secondary; + this.camera = camera; + } + + public HumanFace getPrimary() { + return primary; + } + + public void setPrimary(HumanFace primary) { + this.primary = primary; + } + + public HumanFace getSecondary() { + return secondary; + } + + public void setSecondary(HumanFace secondary) { + this.secondary = secondary; + } + + public Camera getCamera() { + return camera; + } + + public void setCamera(Camera camera) { + this.camera = camera; + } + + + /** + * Serializes data into file + * @param pathToProjectDirectory path to project directory + * @return file where data is stored + * @throws IOException exception + */ + public File dumpToFile(String pathToProjectDirectory) throws IOException { + + File projectDirectory = Paths.get(pathToProjectDirectory).toFile(); + + String name = primary.getShortName(); + if (secondary != null) { + name = primary.getShortName() + "_TO_" + secondary.getShortName(); + } + + File file = new File(projectDirectory.toString() + File.separatorChar + name + ".bin"); + //file.deleteOnExit(); + + RandomAccessFile raf = new RandomAccessFile(file, "rw"); + try (ObjectOutputStream fos = new ObjectOutputStream(new BufferedOutputStream(new FileOutputStream(raf.getFD())))) { + fos.writeObject(this); + fos.flush(); + } + return file; + } + + /** + * Restores serialized data from file + * @param dumpFile file with serialized data + * @return instance of Task class with primary, secondary and camera + * @throws IOException + * @throws ClassNotFoundException + */ + public static Task restoreFromFile(File dumpFile) throws IOException, ClassNotFoundException { + + try (ObjectInputStream fos = new ObjectInputStream(new BufferedInputStream(new FileInputStream(dumpFile)))) { + return (Task) fos.readObject(); + } + + } + + /** + * Tries to delete task from disc + * @param pathToTask path to task + */ + public static void endTask(String pathToTask) { + File file = new File(pathToTask); + + if (file.exists()) { + file.delete(); + } + } +} diff --git a/GUI/src/main/java/cz/fidentis/analyst/project/TaskCellEditor.java b/GUI/src/main/java/cz/fidentis/analyst/project/TaskCellEditor.java new file mode 100644 index 00000000..a12dcde4 --- /dev/null +++ b/GUI/src/main/java/cz/fidentis/analyst/project/TaskCellEditor.java @@ -0,0 +1,37 @@ +package cz.fidentis.analyst.project; + +import java.awt.Component; +import javax.swing.AbstractCellEditor; +import javax.swing.JComboBox; +import javax.swing.JTable; +import javax.swing.table.TableCellEditor; + +/** + * + * @author Matej Kovar + */ +public class TaskCellEditor extends AbstractCellEditor implements TableCellEditor { + + private JComboBox comboBox; + + TaskCellEditor() { + comboBox = new JComboBox(); + //comboBox.setOpaque(true); + //comboBox.setBackground(Color.white); + } + + @Override + public Object getCellEditorValue() { + + return comboBox; + } + + @Override + public Component getTableCellEditorComponent(JTable table, Object value, boolean isSelected, int row, int column) { + + comboBox = ((JComboBox)value); + + return comboBox; + } + +} diff --git a/GUI/src/main/java/cz/fidentis/analyst/project/TaskCellRenderer.java b/GUI/src/main/java/cz/fidentis/analyst/project/TaskCellRenderer.java new file mode 100644 index 00000000..21ab59ef --- /dev/null +++ b/GUI/src/main/java/cz/fidentis/analyst/project/TaskCellRenderer.java @@ -0,0 +1,25 @@ +package cz.fidentis.analyst.project; + +import java.awt.Component; +import javax.swing.JComboBox; +import javax.swing.JTable; +import javax.swing.table.TableCellRenderer; + +/** + * + * @author Matej Kovar + */ + + +public class TaskCellRenderer extends JComboBox implements TableCellRenderer { + + @Override + public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column) { + //setOpaque(true); + setSelectedItem(value); + //this.setForeground(this.getBackground()); + //setBackground(Color.white); + return this; + } + +} diff --git a/GUI/src/main/java/cz/fidentis/analyst/scene/Camera.java b/GUI/src/main/java/cz/fidentis/analyst/scene/Camera.java index b89b9c1e..d02d9ac0 100644 --- a/GUI/src/main/java/cz/fidentis/analyst/scene/Camera.java +++ b/GUI/src/main/java/cz/fidentis/analyst/scene/Camera.java @@ -1,5 +1,6 @@ package cz.fidentis.analyst.scene; +import java.io.Serializable; import javax.vecmath.Vector3d; /** @@ -8,7 +9,7 @@ import javax.vecmath.Vector3d; * @author Natalia Bebjakova * @author Radek Oslejsek */ -public class Camera { +public class Camera implements Serializable { public static final Vector3d DEFAULT_POSITION = new Vector3d(0, 0, 300); diff --git a/GUI/src/main/java/cz/fidentis/analyst/scene/DrawablePlane.java b/GUI/src/main/java/cz/fidentis/analyst/scene/DrawablePlane.java index 7a580019..2b8010cb 100644 --- a/GUI/src/main/java/cz/fidentis/analyst/scene/DrawablePlane.java +++ b/GUI/src/main/java/cz/fidentis/analyst/scene/DrawablePlane.java @@ -60,7 +60,7 @@ public class DrawablePlane extends Drawable { /** * Switches on/off bounding box rendering. * - * @param show If {@code true], then the bounding box is rendered as well + * @param show If {@code true}, then the bounding box is rendered as well */ public void setShowBBox(boolean show) { this.showBoundingBox = show; diff --git a/GUI/src/main/java/cz/fidentis/analyst/scene/DrawablePointCloud.java b/GUI/src/main/java/cz/fidentis/analyst/scene/DrawablePointCloud.java index d94a673e..b99b18a5 100644 --- a/GUI/src/main/java/cz/fidentis/analyst/scene/DrawablePointCloud.java +++ b/GUI/src/main/java/cz/fidentis/analyst/scene/DrawablePointCloud.java @@ -23,9 +23,7 @@ public class DrawablePointCloud extends Drawable { /** * Constructor. * - * @param featurePoints Feature points - * @param defaultColor Default color - * @param defaultPerimeter Default perimeter + * @param points Feature points */ public DrawablePointCloud(List<MeshPoint> points) { this.points = points; diff --git a/GUI/src/main/java/cz/fidentis/analyst/scene/Scene.java b/GUI/src/main/java/cz/fidentis/analyst/scene/Scene.java index 0645d1bc..62ebb720 100644 --- a/GUI/src/main/java/cz/fidentis/analyst/scene/Scene.java +++ b/GUI/src/main/java/cz/fidentis/analyst/scene/Scene.java @@ -236,7 +236,7 @@ public class Scene { * If the drawable is {@code null}, then the drawable is removed. * * @param slot Slot of the drawable - * @param face New face or {@code null} + * @param dr Drawable */ public boolean setOtherDrawable(int slot, Drawable dr) { if (slot < 0 || slot >= Scene.MAX_FACES_IN_SCENE) { diff --git a/GUI/src/main/resources/cz/fidentis/analyst/project/Bundle.properties b/GUI/src/main/resources/cz/fidentis/analyst/project/Bundle.properties index 1fbfa256..1c763ad4 100644 --- a/GUI/src/main/resources/cz/fidentis/analyst/project/Bundle.properties +++ b/GUI/src/main/resources/cz/fidentis/analyst/project/Bundle.properties @@ -7,10 +7,12 @@ FaceStatePanel.sizeOutput.text= ProjectPanel.newProjectButton.text= ProjectPanel.openProjectButton.text= ProjectPanel.saveProjectButton.text= -ProjectPanel.analyseButton.text=Analyse +ProjectPanel.analyseButton.text=Create Task ProjectPanel.inflateButton.text=Inflate ProjectPanel.deselectAllButton.text=Deselect all ProjectPanel.selectAllButton.text=Select all ProjectPanel.removeButton.text=Remove ProjectPanel.addButton.text=Add FilterPanel.nameTextField.text= +ProjectPanel.projectNameLabel.text=Project name : +ProjectPanel.projectNameOutput.text= diff --git a/MeshModel/src/main/java/cz/fidentis/analyst/mesh/core/MeshTriangle.java b/MeshModel/src/main/java/cz/fidentis/analyst/mesh/core/MeshTriangle.java index 5f66233f..d7270296 100644 --- a/MeshModel/src/main/java/cz/fidentis/analyst/mesh/core/MeshTriangle.java +++ b/MeshModel/src/main/java/cz/fidentis/analyst/mesh/core/MeshTriangle.java @@ -13,6 +13,7 @@ import javax.vecmath.Vector3d; * * @author Natalia Bebjakova * @author Dominik Racek + * @author Enkh-Undral EnkhBayar */ public class MeshTriangle implements Iterable<MeshPoint> { @@ -146,8 +147,6 @@ public class MeshTriangle implements Iterable<MeshPoint> { * @param second second point on second line * Must not be {@code null} * @return point of intersection or {@code null} if the lines are parallel - * - * @author Enkh-Undral EnkhBayar */ protected static Point3d getLinesIntersection(Point3d origin, Vector3d vector, Point3d first, Point3d second) { Point3d o = new Point3d(origin); @@ -231,8 +230,6 @@ public class MeshTriangle implements Iterable<MeshPoint> { * @param origin Point of origin form which the ray starts * @param vector directional vector of the ray * @return point of intersection or null if there is no intersection - * - * @author Enkh-Undral EnkhBayar */ public Point3d getRayIntersection(Point3d origin, Vector3d vector) { Vector3d normal = computeNormal(); @@ -484,8 +481,6 @@ public class MeshTriangle implements Iterable<MeshPoint> { * * @param point Point located on the plane of the triangle * @return true if point is in triangle, false otherwise - * - * @author Enkh-Undral EnkhBayar */ public boolean isPointInTriangle(Point3d point) { // https://www.scratchapixel.com/lessons/3d-basic-rendering/ray-tracing-rendering-a-triangle/barycentric-coordinates -- GitLab