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&lt;Void, Voide&gt; {
  *    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) -&gt; {
+ *    if ("state".equals(evt.getPropertyName()) &amp;&amp; (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, &quot;{key}&quot;)"/>
             </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);&#xa;table.getTableHeader().setBackground(new java.awt.Color(204,204,204));&#xa;table.getTableHeader().setFont(new java.awt.Font(&quot;Tahoma&quot;, 0, 18));&#xa;model.addTableModelListener(new TableModelListener() {&#xa;    public void tableChanged(TableModelEvent e) {&#xa;        jTable1TableChanged(e);&#xa;    }&#xa;});">
               <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);&#xa;table.getColumnModel().getColumn(2).setMaxWidth(75);&#xa;table.getTableHeader().getColumnModel().getColumn(0).setMaxWidth(50);&#xa;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);&#xa;table.getColumnModel().getColumn(1).setPreferredWidth(400);&#xa;table.getColumnModel().getColumn(2).setMaxWidth(250);&#xa;table.getColumnModel().getColumn(2).setPreferredWidth(250);&#xa;table.getColumnModel().getColumn(3).setMaxWidth(125);&#xa;table.getColumnModel().getColumn(3).setPreferredWidth(125);&#xa;table.getTableHeader().getColumnModel().getColumn(0).setMaxWidth(50);&#xa;table.getTableHeader().getColumnModel().getColumn(1).setPreferredWidth(400);&#xa;table.getTableHeader().getColumnModel().getColumn(2).setMaxWidth(250);&#xa;table.getTableHeader().getColumnModel().getColumn(2).setPreferredWidth(250);&#xa;table.getTableHeader().getColumnModel().getColumn(3).setMaxWidth(125);&#xa;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, &quot;{key}&quot;)"/>
+        </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, &quot;{key}&quot;)"/>
+        </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