From 5afdbcf85bf0a52dbb3124f47d05be659284c93c Mon Sep 17 00:00:00 2001 From: Ben Soares Date: Mon, 26 Sep 2022 20:17:14 +0100 Subject: [PATCH] JAL-1988 JAL-3772 linked undostack to saved changes flags. No confirmation if all viewports have been saved individually --- src/jalview/gui/AlignFrame.java | 15 +++++- src/jalview/jbgui/QuitHandler.java | 65 +++++++++++++++++++++----- src/jalview/project/Jalview2XML.java | 55 ++++++++++++++++++++++ src/jalview/viewmodel/AlignmentViewport.java | 47 ++++++++++++++----- 4 files changed, 157 insertions(+), 25 deletions(-) diff --git a/src/jalview/gui/AlignFrame.java b/src/jalview/gui/AlignFrame.java index e24cbea..8a6907c 100644 --- a/src/jalview/gui/AlignFrame.java +++ b/src/jalview/gui/AlignFrame.java @@ -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); + } } } }; diff --git a/src/jalview/jbgui/QuitHandler.java b/src/jalview/jbgui/QuitHandler.java index f7a30f3..6a95db7 100644 --- a/src/jalview/jbgui/QuitHandler.java +++ b/src/jalview/jbgui/QuitHandler.java @@ -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 avpList = (List) af + .getAlignPanels(); + for (AlignmentViewPanel avp : avpList) + { + AlignmentI a = avp.getAlignment(); + List 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 diff --git a/src/jalview/project/Jalview2XML.java b/src/jalview/project/Jalview2XML.java index d57f58e..351fc04 100644 --- a/src/jalview/project/Jalview2XML.java +++ b/src/jalview/project/Jalview2XML.java @@ -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 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; + } } diff --git a/src/jalview/viewmodel/AlignmentViewport.java b/src/jalview/viewmodel/AlignmentViewport.java index 08af2ec..975b292 100644 --- a/src/jalview/viewmodel/AlignmentViewport.java +++ b/src/jalview/viewmodel/AlignmentViewport.java @@ -20,6 +20,18 @@ */ 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 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; + } } -- 1.7.10.2