JAL-1988 JAL-3772 linked undostack to saved changes flags. No confirmation if all...
authorBen Soares <b.soares@dundee.ac.uk>
Mon, 26 Sep 2022 19:17:14 +0000 (20:17 +0100)
committerBen Soares <b.soares@dundee.ac.uk>
Mon, 26 Sep 2022 19:17:14 +0000 (20:17 +0100)
src/jalview/gui/AlignFrame.java
src/jalview/jbgui/QuitHandler.java
src/jalview/project/Jalview2XML.java
src/jalview/viewmodel/AlignmentViewport.java

index e24cbea..8a6907c 100644 (file)
@@ -20,8 +20,6 @@
  */
 package jalview.gui;
 
-import java.util.Locale;
-
 import java.awt.BorderLayout;
 import java.awt.Color;
 import java.awt.Component;
@@ -59,6 +57,7 @@ import java.util.Deque;
 import java.util.Enumeration;
 import java.util.Hashtable;
 import java.util.List;
+import java.util.Locale;
 import java.util.Vector;
 
 import javax.swing.ButtonGroup;
@@ -1259,6 +1258,12 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
       lastSaveSuccessful = new Jalview2XML().saveAlignment(this, file,
               shortName);
 
+      Console.debug("lastSaveSuccessful=" + lastSaveSuccessful);
+      if (lastSaveSuccessful)
+      {
+        this.getViewport().setSavedUpToDate(true);
+      }
+
       statusBar.setText(MessageManager.formatMessage(
               "label.successfully_saved_to_file_in_format", new Object[]
               { file, format }));
@@ -1356,6 +1361,12 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
                             + (lastSaveSuccessful ? "" : "un")
                             + "successfully");
           }
+
+          Console.debug("lastSaveSuccessful=" + lastSaveSuccessful);
+          if (lastSaveSuccessful)
+          {
+            AlignFrame.this.getViewport().setSavedUpToDate(true);
+          }
         }
       }
     };
index f7a30f3..6a95db7 100644 (file)
@@ -2,14 +2,21 @@ package jalview.jbgui;
 
 import java.io.File;
 import java.util.Date;
+import java.util.List;
 
 import javax.swing.JFrame;
 import javax.swing.JOptionPane;
 
 import com.formdev.flatlaf.extras.FlatDesktop;
 
+import jalview.api.AlignmentViewPanel;
 import jalview.bin.Console;
+import jalview.datamodel.AlignmentI;
+import jalview.datamodel.SequenceI;
+import jalview.gui.AlignFrame;
+import jalview.gui.Desktop;
 import jalview.io.BackupFiles;
+import jalview.project.Jalview2XML;
 import jalview.util.MessageManager;
 import jalview.util.Platform;
 
@@ -75,12 +82,11 @@ public class QuitHandler
       Console.debug("Non interactive quit -- not confirming");
       confirmQuit = false;
     }
-    /* 
-    else if (undostack is empty) {
+    else if (Jalview2XML.allSavedUpToDate())
+    {
       Console.debug("Nothing changed -- not confirming quit");
-      confirmQuit = false
+      confirmQuit = false;
     }
-    */
     else
     {
       confirmQuit = jalview.bin.Cache
@@ -97,7 +103,13 @@ public class QuitHandler
     // the save time to finish!
     if (confirmQuit)
     {
-      answer = frameOnTop(MessageManager.getString("label.quit_jalview"),
+      answer = frameOnTop(
+              new StringBuilder(
+                      MessageManager.getString("label.quit_jalview"))
+                              .append(" ")
+                              .append(MessageManager
+                                      .getString("label.unsaved_changes"))
+                              .toString(),
               MessageManager.getString("action.quit"),
               JOptionPane.OK_CANCEL_OPTION, JOptionPane.PLAIN_MESSAGE);
     }
@@ -109,8 +121,34 @@ public class QuitHandler
     }
 
     // check for saves in progress
-    int waitForSave = 5000; // MAKE THIS BETTER
-    int waitIncrement = 2000;
+    int waitForSave = 1000; // MAKE THIS BETTER
+    AlignFrame[] afArray = Desktop.getAlignFrames();
+    if (afArray == null || afArray.length == 0)
+    {
+      // no change
+    }
+    else
+    {
+      int size = 0;
+      for (int i = 0; i < afArray.length; i++)
+      {
+        AlignFrame af = afArray[i];
+        List<AlignmentViewPanel> avpList = (List<AlignmentViewPanel>) af
+                .getAlignPanels();
+        for (AlignmentViewPanel avp : avpList)
+        {
+          AlignmentI a = avp.getAlignment();
+          List<SequenceI> sList = a.getSequences();
+          for (SequenceI s : sList)
+          {
+            size += s.getLength();
+          }
+        }
+      }
+      waitForSave = size;
+      Console.debug("Set waitForSave to " + waitForSave);
+    }
+    int waitIncrement = 3000;
     long startTime = new Date().getTime();
     boolean saving = BackupFiles.hasSavesInProgress();
     if (saving)
@@ -126,10 +164,18 @@ public class QuitHandler
       {
         StringBuilder messageSB = new StringBuilder(
                 MessageManager.getString("label.save_in_progress"));
+        messageSB.append(":");
+        boolean any = false;
         for (File file : BackupFiles.savesInProgressFiles())
         {
-          messageSB.append("\n");
+          messageSB.append("\n- ");
           messageSB.append(file.getName());
+          any = true;
+        }
+        if (!any)
+        {
+          messageSB.append("\n");
+          messageSB.append(MessageManager.getString("label.unknown"));
         }
         int waitLonger = interactive ? JOptionPane.YES_OPTION
                 : JOptionPane.NO_OPTION;
@@ -140,19 +186,16 @@ public class QuitHandler
                   MessageManager.getString("action.wait"));
           if (waitLonger == JOptionPane.YES_OPTION) // wait
           {
-            Console.debug("*** YES answer=" + waitLonger);
             // do wait stuff
             saving = !waitForSave(waitIncrement);
           }
           else if (waitLonger == JOptionPane.NO_OPTION) // force quit
           {
-            Console.debug("*** NO answer=" + waitLonger);
             // do a force quit
             return returnResponse(QResponse.FORCE_QUIT); // shouldn't reach this
           }
           else if (waitLonger == JOptionPane.CANCEL_OPTION) // cancel quit
           {
-            Console.debug("*** CANCEL answer=" + waitLonger);
             return returnResponse(QResponse.CANCEL_QUIT);
           }
           else
index d57f58e..351fc04 100644 (file)
@@ -229,6 +229,11 @@ public class Jalview2XML
   private static final String UTF_8 = "UTF-8";
 
   /**
+   * used in decision if quit confirmation should be issued
+   */
+  private static boolean stateSavedUpToDate = false;
+
+  /**
    * prefix for recovering datasets for alignments with multiple views where
    * non-existent dataset IDs were written for some views
    */
@@ -616,6 +621,8 @@ public class Jalview2XML
   {
     AlignFrame[] frames = Desktop.getAlignFrames();
 
+    setStateSavedUpToDate(true);
+
     if (Cache.getDefault("DEBUG_DELAY_SAVE", false))
     {
       int n = 20;
@@ -782,6 +789,25 @@ public class Jalview2XML
       FileOutputStream fos = new FileOutputStream(
               doBackup ? backupfiles.getTempFilePath() : jarFile);
 
+      if (Cache.getDefault("DEBUG_DELAY_SAVE", false))
+      {
+        int n = 20;
+        int i = 0;
+        while (i < n)
+        {
+          Console.debug("***** debugging save sleep " + i + "/" + n);
+          try
+          {
+            Thread.sleep(1000);
+          } catch (InterruptedException e)
+          {
+            // TODO Auto-generated catch block
+            e.printStackTrace();
+          }
+          i++;
+        }
+      }
+
       JarOutputStream jout = new JarOutputStream(fos);
       List<AlignFrame> frames = new ArrayList<>();
 
@@ -6556,4 +6582,33 @@ public class Jalview2XML
 
     return colour;
   }
+
+  public static void setStateSavedUpToDate(boolean s)
+  {
+    Console.debug("Setting overall stateSavedUpToDate to " + s);
+    stateSavedUpToDate = s;
+  }
+
+  public static boolean stateSavedUpToDate()
+  {
+    Console.debug("Returning overall stateSavedUpToDate value: "
+            + stateSavedUpToDate);
+    return stateSavedUpToDate;
+  }
+
+  public static boolean allSavedUpToDate()
+  {
+    if (stateSavedUpToDate()) // nothing happened since last project save
+      return true;
+
+    AlignFrame[] frames = Desktop.getAlignFrames();
+    for (int i = 0; i < frames.length; i++)
+    {
+      if (frames[i] == null)
+        continue;
+      if (!frames[i].getViewport().savedUpToDate())
+        return false; // at least one alignment is not individually saved
+    }
+    return true;
+  }
 }
index 08af2ec..975b292 100644 (file)
  */
 package jalview.viewmodel;
 
+import java.awt.Color;
+import java.beans.PropertyChangeSupport;
+import java.util.ArrayDeque;
+import java.util.ArrayList;
+import java.util.BitSet;
+import java.util.Deque;
+import java.util.HashMap;
+import java.util.Hashtable;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+
 import jalview.analysis.AnnotationSorter.SequenceAnnotationOrder;
 import jalview.analysis.Conservation;
 import jalview.analysis.TreeModel;
@@ -29,6 +41,7 @@ import jalview.api.AlignViewportI;
 import jalview.api.AlignmentViewPanel;
 import jalview.api.FeaturesDisplayedI;
 import jalview.api.ViewStyleI;
+import jalview.bin.Console;
 import jalview.commands.CommandI;
 import jalview.datamodel.AlignedCodonFrame;
 import jalview.datamodel.AlignmentAnnotation;
@@ -45,6 +58,7 @@ import jalview.datamodel.Sequence;
 import jalview.datamodel.SequenceCollectionI;
 import jalview.datamodel.SequenceGroup;
 import jalview.datamodel.SequenceI;
+import jalview.project.Jalview2XML;
 import jalview.renderer.ResidueShader;
 import jalview.renderer.ResidueShaderI;
 import jalview.schemes.ColourSchemeI;
@@ -61,18 +75,6 @@ import jalview.workers.ComplementConsensusThread;
 import jalview.workers.ConsensusThread;
 import jalview.workers.StrucConsensusThread;
 
-import java.awt.Color;
-import java.beans.PropertyChangeSupport;
-import java.util.ArrayDeque;
-import java.util.ArrayList;
-import java.util.BitSet;
-import java.util.Deque;
-import java.util.HashMap;
-import java.util.Hashtable;
-import java.util.Iterator;
-import java.util.List;
-import java.util.Map;
-
 /**
  * base class holding visualization and analysis attributes and common logic for
  * an active alignment view displayed in the GUI
@@ -100,6 +102,11 @@ public abstract class AlignmentViewport
   protected Deque<CommandI> redoList = new ArrayDeque<>();
 
   /**
+   * used to determine if quit should be confirmed
+   */
+  private boolean savedUpToDate = true;
+
+  /**
    * alignment displayed in the viewport. Please use get/setter
    */
   protected AlignmentI alignment;
@@ -2614,6 +2621,8 @@ public abstract class AlignmentViewport
     {
       this.historyList.push(command);
       broadcastCommand(command, false);
+      setSavedUpToDate(false);
+      Jalview2XML.setStateSavedUpToDate(false);
     }
   }
 
@@ -3096,4 +3105,18 @@ public abstract class AlignmentViewport
     return (alignment.getHiddenColumns().getVisContigsIterator(start, end,
             false));
   }
+
+  public void setSavedUpToDate(boolean s)
+  {
+    Console.debug(
+            "Setting " + this.getViewId() + " setSavedUpToDate to " + s);
+    savedUpToDate = s;
+  }
+
+  public boolean savedUpToDate()
+  {
+    Console.debug("Returning " + this.getViewId() + " savedUpToDate value: "
+            + savedUpToDate);
+    return savedUpToDate;
+  }
 }