From 2d65b8b49b707cbaf46368bee9e04b37bcf9b53a Mon Sep 17 00:00:00 2001
From: denneyl2711 <lukedenneymn@gmail.com>
Date: Tue, 6 Aug 2024 13:04:49 -0500
Subject: [PATCH] Stop multiple tasks from running at the same time.

---
 src/kintsugi3d/builder/app/Rendering.java     |  5 +++
 .../builder/core/DefaultProgressMonitor.java  |  5 +++
 .../builder/core/IBRRequestManager.java       | 10 ++++--
 src/kintsugi3d/builder/core/IOModel.java      | 13 ++++++++
 .../builder/core/ProgressMonitor.java         |  7 ++++
 .../general/GeneralRenderRequestUI.java       |  5 +++
 .../projectExporter/ExportRequestUI.java      |  5 +++
 .../export/resample/ResampleRequestUI.java    |  5 +++
 .../export/screenshot/ScreenshotUI.java       |  5 +++
 .../simpleanimation/SimpleAnimationUI.java    |  5 +++
 .../export/specular/SpecularFitRequestUI.java |  5 +++
 src/kintsugi3d/builder/javafx/ProjectIO.java  |  7 ++--
 .../menubar/MenubarController.java            | 33 +++++++++++++++++--
 .../builder/rendering/IBRInstanceManager.java | 16 +++++++++
 .../resources/DynamicResourceLoader.java      |  4 +++
 15 files changed, 122 insertions(+), 8 deletions(-)

diff --git a/src/kintsugi3d/builder/app/Rendering.java b/src/kintsugi3d/builder/app/Rendering.java
index da4e496f..8108ca59 100644
--- a/src/kintsugi3d/builder/app/Rendering.java
+++ b/src/kintsugi3d/builder/app/Rendering.java
@@ -417,6 +417,11 @@ public void warn(Throwable e)
             {
                 ioModel.getProgressMonitor().warn(e);
             }
+
+            @Override
+            public boolean isConflictingProcess() {
+                return ioModel.getProgressMonitor().isConflictingProcess();
+            }
         });
 
         app.addRefreshable(new Refreshable()
diff --git a/src/kintsugi3d/builder/core/DefaultProgressMonitor.java b/src/kintsugi3d/builder/core/DefaultProgressMonitor.java
index a7faa865..f07737b6 100644
--- a/src/kintsugi3d/builder/core/DefaultProgressMonitor.java
+++ b/src/kintsugi3d/builder/core/DefaultProgressMonitor.java
@@ -65,4 +65,9 @@ public void complete()
     public void fail(Throwable e)
     {
     }
+
+    @Override
+    public boolean isConflictingProcess() {
+        return false;
+    }
 }
diff --git a/src/kintsugi3d/builder/core/IBRRequestManager.java b/src/kintsugi3d/builder/core/IBRRequestManager.java
index ed66bb9c..0974d089 100644
--- a/src/kintsugi3d/builder/core/IBRRequestManager.java
+++ b/src/kintsugi3d/builder/core/IBRRequestManager.java
@@ -24,10 +24,7 @@
 import javafx.scene.control.Alert.AlertType;
 import kintsugi3d.builder.rendering.IBRInstanceManager;
 import kintsugi3d.gl.core.Context;
-import kintsugi3d.gl.interactive.GraphicsRequest;
 import kintsugi3d.gl.interactive.ObservableGraphicsRequest;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
 
 public class IBRRequestManager<ContextType extends Context<ContextType>> implements IBRRequestQueue<ContextType>
 {
@@ -112,6 +109,10 @@ public synchronized void addBackgroundIBRRequest(IBRRequest request)
     @Override
     public synchronized void addIBRRequest(ObservableIBRRequest request)
     {
+        if(this.progressMonitor.isConflictingProcess()){
+            return;
+        }
+
         if (instanceManager.getLoadedInstance() == null)
         {
             // Instance is currently null, wait for a load and then call this function again (recursive-ish)
@@ -209,6 +210,9 @@ public synchronized void addGraphicsRequest(ObservableGraphicsRequest request)
         {
             if (progressMonitor != null)
             {
+                if(this.progressMonitor.isConflictingProcess()){
+                    return;
+                }
                 progressMonitor.start();
             }
 
diff --git a/src/kintsugi3d/builder/core/IOModel.java b/src/kintsugi3d/builder/core/IOModel.java
index 8852c8a9..0498a20b 100644
--- a/src/kintsugi3d/builder/core/IOModel.java
+++ b/src/kintsugi3d/builder/core/IOModel.java
@@ -132,6 +132,19 @@ public void warn(Throwable e)
                 monitor.warn(e);
             }
         }
+
+        @Override
+        public boolean isConflictingProcess() {
+            boolean processing = false;
+            for (ProgressMonitor monitor : subMonitors)
+            {
+                if(monitor.isConflictingProcess()){
+                    processing = true;
+                }
+            }
+
+            return processing;
+        }
     }
 
     private IOHandler handler;
diff --git a/src/kintsugi3d/builder/core/ProgressMonitor.java b/src/kintsugi3d/builder/core/ProgressMonitor.java
index fcb24263..bb8747b7 100644
--- a/src/kintsugi3d/builder/core/ProgressMonitor.java
+++ b/src/kintsugi3d/builder/core/ProgressMonitor.java
@@ -95,4 +95,11 @@ public interface ProgressMonitor
     default void warn(Throwable e)
     {
     }
+
+    /**
+     * Usually a call to ProgressBarsController.getInstance().isProcessing().
+     * Used to stop multiple processes from conflicting with each other.
+     * @return true if a process is in progress.
+     */
+    boolean isConflictingProcess();
 }
diff --git a/src/kintsugi3d/builder/export/general/GeneralRenderRequestUI.java b/src/kintsugi3d/builder/export/general/GeneralRenderRequestUI.java
index 6b25cc16..84eccf9d 100644
--- a/src/kintsugi3d/builder/export/general/GeneralRenderRequestUI.java
+++ b/src/kintsugi3d/builder/export/general/GeneralRenderRequestUI.java
@@ -30,6 +30,7 @@
 import javafx.stage.FileChooser.ExtensionFilter;
 import javafx.stage.Stage;
 import javafx.stage.Window;
+import kintsugi3d.builder.javafx.MultithreadModels;
 import kintsugi3d.util.RecentProjects;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
@@ -136,6 +137,10 @@ public <ContextType extends Context<ContextType>> void prompt(IBRRequestQueue<Co
         {
 //            stage.close();
 
+            if(MultithreadModels.getInstance().getIOModel().getProgressMonitor().isConflictingProcess()){
+                return;
+            }
+
             File fragmentShader = new File(fragmentShaderField.getText());
             File outputDirectory = new File(exportDirectoryField.getText());
 
diff --git a/src/kintsugi3d/builder/export/projectExporter/ExportRequestUI.java b/src/kintsugi3d/builder/export/projectExporter/ExportRequestUI.java
index 88549478..0a2fee32 100644
--- a/src/kintsugi3d/builder/export/projectExporter/ExportRequestUI.java
+++ b/src/kintsugi3d/builder/export/projectExporter/ExportRequestUI.java
@@ -30,6 +30,7 @@
 import kintsugi3d.builder.core.*;
 import kintsugi3d.builder.fit.settings.ExportSettings;
 
+import kintsugi3d.builder.javafx.MultithreadModels;
 import kintsugi3d.builder.util.Kintsugi3DViewerLauncher;
 import kintsugi3d.gl.core.Context;
 import org.slf4j.Logger;
@@ -103,6 +104,10 @@ public <ContextType extends Context<ContextType>> void prompt(IBRRequestQueue<Co
             //Updates settings to equal what widget is displaying
             saveAllVariables(settings);
 
+            if(MultithreadModels.getInstance().getIOModel().getProgressMonitor().isConflictingProcess()){
+                return;
+            }
+
             try
             {
                 exportLocationFile = objFileChooser.showSaveDialog(stage);
diff --git a/src/kintsugi3d/builder/export/resample/ResampleRequestUI.java b/src/kintsugi3d/builder/export/resample/ResampleRequestUI.java
index 3789d5f0..229653cc 100644
--- a/src/kintsugi3d/builder/export/resample/ResampleRequestUI.java
+++ b/src/kintsugi3d/builder/export/resample/ResampleRequestUI.java
@@ -28,6 +28,7 @@
 import javafx.stage.FileChooser.ExtensionFilter;
 import javafx.stage.Stage;
 import javafx.stage.Window;
+import kintsugi3d.builder.javafx.MultithreadModels;
 import kintsugi3d.gl.core.Context;
 import kintsugi3d.builder.core.IBRRequestQueue;
 import kintsugi3d.builder.core.IBRRequestUI;
@@ -126,6 +127,10 @@ public <ContextType extends Context<ContextType>> void prompt(IBRRequestQueue<Co
         {
             //stage.close();
 
+            if(MultithreadModels.getInstance().getIOModel().getProgressMonitor().isConflictingProcess()){
+                return;
+            }
+
             requestQueue.addIBRRequest(
                 new ResampleRequest(
                     Integer.parseInt(widthTextField.getText()),
diff --git a/src/kintsugi3d/builder/export/screenshot/ScreenshotUI.java b/src/kintsugi3d/builder/export/screenshot/ScreenshotUI.java
index f9d035df..cd6c64de 100644
--- a/src/kintsugi3d/builder/export/screenshot/ScreenshotUI.java
+++ b/src/kintsugi3d/builder/export/screenshot/ScreenshotUI.java
@@ -27,6 +27,7 @@
 import javafx.stage.FileChooser.ExtensionFilter;
 import javafx.stage.Stage;
 import javafx.stage.Window;
+import kintsugi3d.builder.javafx.MultithreadModels;
 import kintsugi3d.gl.core.Context;
 import kintsugi3d.builder.core.IBRRequestQueue;
 import kintsugi3d.builder.core.IBRRequestUI;
@@ -115,6 +116,10 @@ public <ContextType extends Context<ContextType>> void prompt(IBRRequestQueue<Co
             //stage.close();
             if (builderSupplier != null)
             {
+                if(MultithreadModels.getInstance().getIOModel().getProgressMonitor().isConflictingProcess()){
+                    return;
+                }
+
                 requestQueue.addIBRRequest(
                     builderSupplier.get()
                         .setWidth(Integer.parseInt(widthTextField.getText()))
diff --git a/src/kintsugi3d/builder/export/simpleanimation/SimpleAnimationUI.java b/src/kintsugi3d/builder/export/simpleanimation/SimpleAnimationUI.java
index 6c35eb88..311e66b2 100644
--- a/src/kintsugi3d/builder/export/simpleanimation/SimpleAnimationUI.java
+++ b/src/kintsugi3d/builder/export/simpleanimation/SimpleAnimationUI.java
@@ -27,6 +27,7 @@
 import javafx.stage.DirectoryChooser;
 import javafx.stage.Stage;
 import javafx.stage.Window;
+import kintsugi3d.builder.javafx.MultithreadModels;
 import kintsugi3d.gl.core.Context;
 import kintsugi3d.builder.core.IBRRequestQueue;
 import kintsugi3d.builder.core.IBRRequestUI;
@@ -109,6 +110,10 @@ public <ContextType extends Context<ContextType>> void prompt(IBRRequestQueue<Co
             //stage.close();
             if (builderSupplier != null)
             {
+                if(MultithreadModels.getInstance().getIOModel().getProgressMonitor().isConflictingProcess()){
+                    return;
+                }
+
                 requestQueue.addIBRRequest(
                     builderSupplier.get()
                         .setWidth(Integer.parseInt(widthTextField.getText()))
diff --git a/src/kintsugi3d/builder/export/specular/SpecularFitRequestUI.java b/src/kintsugi3d/builder/export/specular/SpecularFitRequestUI.java
index ba0ecf70..2073555f 100644
--- a/src/kintsugi3d/builder/export/specular/SpecularFitRequestUI.java
+++ b/src/kintsugi3d/builder/export/specular/SpecularFitRequestUI.java
@@ -35,6 +35,7 @@
 import kintsugi3d.builder.core.Kintsugi3DBuilderState;
 import kintsugi3d.builder.core.TextureResolution;
 import kintsugi3d.builder.fit.settings.SpecularFitRequestParams;
+import kintsugi3d.builder.javafx.MultithreadModels;
 import kintsugi3d.gl.core.Context;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
@@ -111,6 +112,10 @@ public <ContextType extends Context<ContextType>> void prompt(IBRRequestQueue<Co
         {
             //stage.close();
 
+            if(MultithreadModels.getInstance().getIOModel().getProgressMonitor().isConflictingProcess()){
+                return;
+            }
+
             SpecularFitRequestParams settings = new SpecularFitRequestParams(new TextureResolution(
                     Integer.parseInt(widthTextField.getText()),
                     Integer.parseInt(heightTextField.getText())),
diff --git a/src/kintsugi3d/builder/javafx/ProjectIO.java b/src/kintsugi3d/builder/javafx/ProjectIO.java
index 3853e7a4..0ab81dda 100644
--- a/src/kintsugi3d/builder/javafx/ProjectIO.java
+++ b/src/kintsugi3d/builder/javafx/ProjectIO.java
@@ -50,8 +50,6 @@
 import kintsugi3d.builder.javafx.controllers.scene.ProgressBarsController;
 import kintsugi3d.builder.javafx.controllers.scene.WelcomeWindowController;
 import kintsugi3d.builder.resources.ibr.MeshImportException;
-import kintsugi3d.gl.interactive.InteractiveRenderable;
-import kintsugi3d.gl.interactive.InteractiveRenderableList;
 import kintsugi3d.util.Flag;
 import kintsugi3d.util.RecentProjects;
 import org.slf4j.Logger;
@@ -375,6 +373,11 @@ private static void startLoad(File projectFile, File vsetFile)
 
     public void openProjectFromFile(File selectedFile)
     {
+        //need to check for conflicting process early so crucial info isn't unloaded
+        if(MultithreadModels.getInstance().getIOModel().getProgressMonitor().isConflictingProcess()){
+            return;
+        }
+
         //open the project, update the recent files list & recentDirectory, disable shaders which aren't useful until processing textures
         this.projectFile = selectedFile;
         RecentProjects.setMostRecentDirectory(this.projectFile.getParentFile());
diff --git a/src/kintsugi3d/builder/javafx/controllers/menubar/MenubarController.java b/src/kintsugi3d/builder/javafx/controllers/menubar/MenubarController.java
index 51d49bb0..ae58f3fa 100644
--- a/src/kintsugi3d/builder/javafx/controllers/menubar/MenubarController.java
+++ b/src/kintsugi3d/builder/javafx/controllers/menubar/MenubarController.java
@@ -286,9 +286,6 @@ public void cancelComplete(UserCancellationException e)
             @Override
             public void start()
             {
-                //TODO: deal with conflicting processes here
-                //if process is already happening, cancel it and continue with the new one?
-
                 cancelRequested.set(false);
 
                 stageCountProperty.setValue(0);
@@ -433,6 +430,36 @@ public void fail(Throwable e)
             {
                 complete();
             }
+
+            @Override
+            public boolean isConflictingProcess(){
+                if (!ProgressBarsController.getInstance().isProcessing()){
+                    return false;
+                }
+
+                Platform.runLater(() ->
+                {
+                    ButtonType ok = new ButtonType("OK", ButtonBar.ButtonData.OK_DONE);
+                    //ButtonType stopProcess = new ButtonType("Start New Process", ButtonBar.ButtonData.YES);
+                    Alert alert = new Alert(AlertType.NONE, "Cannot run multiple tasks at the same time.\n" +
+                            "Either wait for the current task to complete or cancel it." /*+
+                            "Press OK to finish the current process."*/, ok/*, stopProcess*/);
+                    alert.setHeaderText("Conflicting Tasks");
+
+//                    //continue current process, don't start a new one
+//                    ((Button) alert.getDialogPane().lookupButton(ok)).setOnAction(event -> {
+//                    });
+//
+//                    //cancel current process and start new one
+//                    ((Button) alert.getDialogPane().lookupButton(stopProcess)).setOnAction(event -> {
+//                        cancelRequested.set(true);
+//                    });
+
+                    alert.showAndWait();
+                });
+
+                return true;
+            }
         });
 
         boolean foundExportClass = false;
diff --git a/src/kintsugi3d/builder/rendering/IBRInstanceManager.java b/src/kintsugi3d/builder/rendering/IBRInstanceManager.java
index 08f4e3d8..1b830d53 100644
--- a/src/kintsugi3d/builder/rendering/IBRInstanceManager.java
+++ b/src/kintsugi3d/builder/rendering/IBRInstanceManager.java
@@ -311,6 +311,11 @@ public void warn(Throwable e)
                     progressMonitor.warn(e);
                 }
             }
+
+            @Override
+            public boolean isConflictingProcess() {
+                return progressMonitor.isConflictingProcess();
+            }
         });
         newInstance = newItem;
     }
@@ -318,6 +323,10 @@ public void warn(Throwable e)
     @Override
     public void loadFromVSETFile(String id, File vsetFile, File supportingFilesDirectory, ReadonlyLoadOptionsModel loadOptions)
     {
+        if(this.progressMonitor.isConflictingProcess()){
+            return;
+        }
+
         this.progressMonitor.start();
         this.progressMonitor.setProcessName("Load from File");
 
@@ -346,6 +355,10 @@ public void loadAgisoftFromZIP(String id, MetashapeObjectChunk metashapeObjectCh
         // TODO There currently isn't functionality for a supportingFilesDirectory at this early in the process
         //  Restructuring required from Tetzlaff.
 
+        if(this.progressMonitor.isConflictingProcess()){
+            return;
+        }
+
         this.progressMonitor.start();
         this.progressMonitor.setProcessName("Load from Agisoft Project");
 
@@ -491,6 +504,9 @@ private void showMissingImgsAlert(MetashapeObjectChunk metashapeObjectChunk, Str
     public void loadFromAgisoftXMLFile(String id, File xmlFile, File meshFile, File imageDirectory, String primaryViewName,
         ReadonlyLoadOptionsModel loadOptions)
     {
+        if(this.progressMonitor.isConflictingProcess()){
+            return;
+        }
         this.progressMonitor.start();
         this.progressMonitor.setProcessName("Load from Agisoft Files");
 
diff --git a/src/kintsugi3d/builder/resources/DynamicResourceLoader.java b/src/kintsugi3d/builder/resources/DynamicResourceLoader.java
index 486fdd11..dbe939a3 100644
--- a/src/kintsugi3d/builder/resources/DynamicResourceLoader.java
+++ b/src/kintsugi3d/builder/resources/DynamicResourceLoader.java
@@ -252,6 +252,10 @@ else if (environmentFile.exists())
                 if (Objects.equals(environmentFile, desiredEnvironmentFile) &&
                         (!Objects.equals(environmentFile, currentEnvironmentFile) || lastModified != environmentLastModified))
                 {
+                    if(this.progressMonitor.isConflictingProcess()){
+                        return Optional.empty();
+                    }
+
                     this.progressMonitor.start();
                     this.progressMonitor.setMaxProgress(0.0);
                     this.progressMonitor.setProcessName("Load Environment Map");