action.save_project = Save Project
action.save_project_as = Save Project as...
action.quit = Quit
-label.quit_jalview = Quit Jalview?
+action.force_quit = Force Quit
+label.quit_jalview = Are you sure you want to quit Jalview?
+label.unsaved_changes = There are unsaved changes.
+label.save_in_progress = Some files are still saving.
+label.unknown = Unknown
+action.wait = Wait
+action.cancel_quit = Cancel quit
action.expand_views = Expand Views
action.gather_views = Gather Views
action.page_setup = Page Setup...
action.save_project = Guardar proyecto
action.save_project_as = Guardar proyecto como...
action.quit = Salir
-label.quit_jalview = Salir de Jalview?
+action.force_quit = Forzar la salida
+label.quit_jalview = ¿Estás seguro de que quieres salir de Jalview?
+label.unsaved_changes = Hay cambios sin guardar.
+label.save_in_progress = Algunos archivos aún se están guardando.
+label.unknown = desconocido
+action.wait = Espere
+action.cancel_quit = Cancelar la salida
action.expand_views = Expandir vistas
action.gather_views = Capturar vistas
action.page_setup = Configuración de la página
sb.append("Java version: ");
sb.append(System.getProperty("java.version"));
sb.append("\n");
+ sb.append("Java platform: ");
sb.append(System.getProperty("os.arch"));
sb.append(" ");
sb.append(System.getProperty("os.name"));
sb.append(" (");
sb.append(lafClass);
sb.append(")\n");
+ appendIfNotNull(sb, "Channel: ",
+ ChannelProperties.getProperty("channel"), "\n", null);
if (Console.isDebugEnabled()
|| !"release".equals(ChannelProperties.getProperty("channel")))
{
- appendIfNotNull(sb, "Channel: ",
- ChannelProperties.getProperty("channel"), "\n", null);
appendIfNotNull(sb, "Getdown appdir: ",
System.getProperty("getdowninstanceappdir"), "\n", null);
appendIfNotNull(sb, "Getdown appbase: ",
System.getProperty("getdowninstanceappbase"), "\n", null);
appendIfNotNull(sb, "Java home: ", System.getProperty("java.home"),
"\n", "unknown");
+ appendIfNotNull(sb, "Preferences file: ", propertiesFile, "\n",
+ "unknown");
}
return sb.toString();
}
if (customProxySet &&
// we have a username but no password for the scheme being
// requested
- (protocol.equalsIgnoreCase("http")
- && (httpUser != null && httpUser.length() > 0
- && (httpPassword == null
- || httpPassword.length == 0)))
+ (protocol.equalsIgnoreCase("http")
+ && (httpUser != null
+ && httpUser.length() > 0
+ && (httpPassword == null
+ || httpPassword.length == 0)))
|| (protocol.equalsIgnoreCase("https")
&& (httpsUser != null
&& httpsUser.length() > 0
import jalview.io.IdentifyFile;
import jalview.io.NewickFile;
import jalview.io.gff.SequenceOntologyFactory;
+import jalview.jbgui.QuitHandler;
+import jalview.jbgui.QuitHandler.QResponse;
import jalview.schemes.ColourSchemeI;
import jalview.schemes.ColourSchemeProperty;
import jalview.util.ChannelProperties;
if (!Platform.isJS())
{
System.setSecurityManager(null);
+
+ Runtime.getRuntime().addShutdownHook(new Thread()
+ {
+ public void run()
+ {
+ Console.debug("Running shutdown hook");
+ if (QuitHandler.gotQuitResponse() == QResponse.CANCEL_QUIT)
+ {
+ Console.debug("Checking for saving files");
+ QuitHandler.getQuitResponse(false);
+ }
+ else
+ {
+ Console.debug("Nothing more to do");
+ }
+ Console.debug("Exiting, bye!");
+ // shutdownHook cannot be cancelled, JVM will now halt
+ }
+ });
}
System.out
System.out.println(System.getProperty("os.arch") + " "
+ System.getProperty("os.name") + " "
+ System.getProperty("os.version"));
+
String val = System.getProperty("sys.install4jVersion");
if (val != null)
{
Cache.loadBuildProperties(true);
ArgsParser aparser = new ArgsParser(args);
+
boolean headless = false;
String usrPropsFile = aparser.getValue("props");
- Cache.loadProperties(usrPropsFile); // must do this before
+ Cache.loadProperties(usrPropsFile); // must do this
+ // before
if (usrPropsFile != null)
{
System.out.println(
try
{
Console.initLogger();
- } catch (NoClassDefFoundError error)
+ } catch (
+
+ NoClassDefFoundError error)
{
error.printStackTrace();
System.out.println("\nEssential logging libraries not found."
}
String file = null, data = null;
+
FileFormatI format = null;
+
DataSourceType protocol = null;
+
FileLoader fileLoader = new FileLoader(!headless);
String groovyscript = null; // script to execute after all loading is
System.out.println("No files to open!");
System.exit(1);
}
+
long progress = -1;
// Finally, deal with the remaining input data.
if (file != null)
}
}
}
+
AlignFrame startUpAlframe = null;
// We'll only open the default file if the desktop is visible.
// And the user
}
/**
- * Quit method delegates to Desktop.quit - unless running in headless mode
- * when it just ends the JVM
+ * jalview.bin.Jalview.quit() will just run the non-GUI shutdownHook and exit
*/
public void quit()
{
- if (desktop != null)
- {
- desktop.quit();
- }
- else
- {
- System.exit(0);
- }
+ // System.exit will run the shutdownHook first
+ System.exit(0);
}
public static AlignFrame getCurrentAlignFrame()
*/
package jalview.gui;
-import java.util.Locale;
-
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Component;
import java.util.Enumeration;
import java.util.Hashtable;
import java.util.List;
+import java.util.Locale;
import java.util.Vector;
import javax.swing.ButtonGroup;
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 }));
+ (lastSaveSuccessful ? "" : "un")
+ "successfully");
}
+
+ Console.debug("lastSaveSuccessful=" + lastSaveSuccessful);
+ if (lastSaveSuccessful)
+ {
+ AlignFrame.this.getViewport().setSavedUpToDate(true);
+ }
}
}
};
import javax.swing.JTextField;
import javax.swing.KeyStroke;
import javax.swing.SwingUtilities;
+import javax.swing.WindowConstants;
import javax.swing.event.HyperlinkEvent;
import javax.swing.event.HyperlinkEvent.EventType;
import javax.swing.event.InternalFrameAdapter;
import jalview.io.JalviewFileView;
import jalview.jbgui.GSplitFrame;
import jalview.jbgui.GStructureViewer;
+import jalview.jbgui.QuitHandler;
+import jalview.jbgui.QuitHandler.QResponse;
import jalview.project.Jalview2XML;
import jalview.structure.StructureSelectionManager;
import jalview.urls.IdOrgSettings;
setIconImages(ChannelProperties.getIconList());
+ this.setDefaultCloseOperation(WindowConstants.DO_NOTHING_ON_CLOSE);
addWindowListener(new WindowAdapter()
{
-
@Override
public void windowClosing(WindowEvent ev)
{
- quit();
+ QResponse qresponse = desktopQuit();
+ if (qresponse != QResponse.CANCEL_QUIT)
+ {
+ instance.dispose();
+ }
}
});
this.setDropTarget(new java.awt.dnd.DropTarget(desktop, this));
- this.addWindowListener(new WindowAdapter()
- {
- @Override
- public void windowClosing(WindowEvent evt)
- {
- quit();
- }
- });
-
MouseAdapter ma;
this.addMouseListener(ma = new MouseAdapter()
{
}
/*
- * Exit the program
+ * Check with user and saving files before actually quitting
*/
- @Override
- public void quit()
+ public QResponse desktopQuit()
+ {
+ return desktopQuit(true);
+ }
+
+ public QResponse desktopQuit(boolean ui)
{
+ QuitHandler.QResponse qresponse = QuitHandler.getQuitResponse(ui);
+
+ if (qresponse == QResponse.CANCEL_QUIT)
+ {
+ return qresponse;
+ }
+
Dimension screen = Toolkit.getDefaultToolkit().getScreenSize();
Cache.setProperty("SCREENGEOMETRY_WIDTH", screen.width + "");
Cache.setProperty("SCREENGEOMETRY_HEIGHT", screen.height + "");
groovyConsole.setDirty(false);
groovyConsole.exit();
}
+
+ if (qresponse == QResponse.FORCE_QUIT)
+ {
+ // note that shutdown hook will not be run
+ jalview.bin.Console.debug("Force Quit selected by user");
+ Runtime.getRuntime().halt(0);
+ }
+
+ jalview.bin.Console.debug("Quit selected by user");
+ quit();
+
+ // unlikely to reach here!
+ return QResponse.QUIT;
+ }
+
+ /**
+ * Don't call this directly, use desktopQuit() above. Exits the program.
+ */
+ @Override
+ public void quit()
+ {
+ // this will run the shutdownHook but QuitHandler.getQuitResponse() should
+ // not run a second time if gotQuitResponse flag has been set (i.e. user
+ // confirmed quit of some kind).
System.exit(0);
}
@Override
public void actionPerformed(ActionEvent e)
{
- quit();
+ QResponse qresponse = desktopQuit();
+ if (qresponse == QResponse.CANCEL_QUIT)
+ {
+ jalview.bin.Console
+ .debug("Desktop: Quit action cancelled by user");
+ }
}
});
}
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.HashMap;
+import java.util.List;
import java.util.Map;
import java.util.TreeMap;
private static final String oldTempFileSuffix = "_oldfile_tobedeleted";
+ private static List<BackupFiles> savesInProgress = new ArrayList<>();
+
+ private boolean addSaveInProgress()
+ {
+ if (savesInProgress.contains(this))
+ {
+ return false;
+ }
+ else
+ {
+ savesInProgress.add(this);
+ return true;
+ }
+ }
+
+ private boolean removeSaveInProgress()
+ {
+ if (savesInProgress.contains(this))
+ {
+ // remove all occurrences
+ while (savesInProgress.remove(this))
+ {
+ }
+ return true;
+ }
+ else
+ {
+ return false;
+ }
+ }
+
+ public static boolean hasSavesInProgress()
+ {
+ return savesInProgress.size() > 0;
+ }
+
+ public static List<File> savesInProgressFiles()
+ {
+ List<File> files = new ArrayList<>();
+ for (BackupFiles bfile : savesInProgress)
+ {
+ files.add(bfile.getFile());
+ }
+ return files;
+ }
+
public BackupFiles(String filename)
{
this(new File(filename));
{
classInit();
this.file = file;
+
+ // add this file from the save in progress stack
+ addSaveInProgress();
+
BackupFilesPresetEntry bfpe = BackupFilesPresetEntry
.getSavedBackupEntry();
this.suffix = bfpe.suffix;
tidyUpFiles();
}
+ // remove this file from the save in progress stack
+ removeSaveInProgress();
+
return rename;
}
return ret;
}
+ public File getFile()
+ {
+ return file;
+ }
+
public static boolean moveFileToFile(File oldFile, File newFile)
{
Console.initLogger();
*/
package jalview.jbgui;
-import javax.swing.JFrame;
-import javax.swing.JOptionPane;
-
import com.formdev.flatlaf.extras.FlatDesktop;
import com.formdev.flatlaf.extras.FlatDesktop.Action;
-import jalview.util.MessageManager;
import jalview.util.Platform;
public class APQHandlers
}
if (FlatDesktop.isSupported(Action.APP_QUIT_HANDLER))
{
- FlatDesktop.setQuitHandler(response -> {
- boolean confirmQuit = jalview.bin.Cache.getDefault(
- jalview.gui.Desktop.CONFIRM_KEYBOARD_QUIT, true);
- boolean canQuit = !confirmQuit;
- int n;
- if (confirmQuit)
- {
- // ensure Jalview window is brought to front for Quit confirmation
- // window to be visible
-
- // this method of raising the Jalview window is broken in java
- // jalviewDesktop.setVisible(true);
- // jalviewDesktop.toFront();
-
- // a better hack which works instead
- JFrame dialogParent = new JFrame();
- dialogParent.setAlwaysOnTop(true);
-
- n = JOptionPane.showConfirmDialog(dialogParent,
- MessageManager.getString("label.quit_jalview"),
- MessageManager.getString("action.quit"),
- JOptionPane.OK_CANCEL_OPTION, JOptionPane.PLAIN_MESSAGE,
- null);
-
- dialogParent.setAlwaysOnTop(false);
- dialogParent.dispose();
- }
- else
- {
- n = JOptionPane.OK_OPTION;
- }
- canQuit = (n == JOptionPane.OK_OPTION);
- if (canQuit)
- {
- response.performQuit();
- }
- else
- {
- response.cancelQuit();
- }
- });
+ QuitHandler.setQuitHandler();
setQuit = true;
}
// if we got to here, no exceptions occurred when we set the handlers.
import jalview.api.AlignmentViewPanel;
import jalview.bin.Cache;
+import jalview.gui.Desktop;
import jalview.io.FileFormatException;
+import jalview.jbgui.QuitHandler.QResponse;
import jalview.util.MessageManager;
import jalview.util.Platform;
@Override
public void actionPerformed(ActionEvent e)
{
- quit();
+ QResponse qresponse = Desktop.instance != null
+ ? Desktop.instance.desktopQuit()
+ : QResponse.QUIT;
+ if (qresponse == QResponse.CANCEL_QUIT)
+ {
+ jalview.bin.Console
+ .debug("GDesktop: Quit action cancelled by user");
+ }
}
});
aboutMenuItem.setText(MessageManager.getString("label.about"));
--- /dev/null
+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;
+
+public class QuitHandler
+{
+ public static enum QResponse
+ {
+ QUIT, CANCEL_QUIT, FORCE_QUIT
+ };
+
+ public static void setQuitHandler()
+ {
+ FlatDesktop.setQuitHandler(response -> {
+ QResponse qresponse = getQuitResponse();
+ switch (qresponse)
+ {
+ case QUIT:
+ response.performQuit();
+ break;
+ case CANCEL_QUIT:
+ response.cancelQuit();
+ break;
+ case FORCE_QUIT:
+ response.performQuit();
+ break;
+ default:
+ response.cancelQuit();
+ }
+ });
+ }
+
+ private static QResponse gotQuitResponse = QResponse.CANCEL_QUIT;
+
+ private static QResponse returnResponse(QResponse qresponse)
+ {
+ gotQuitResponse = qresponse;
+ return qresponse;
+ }
+
+ public static QResponse gotQuitResponse()
+ {
+ return gotQuitResponse;
+ }
+
+ public static QResponse getQuitResponse()
+ {
+ return getQuitResponse(true);
+ }
+
+ public static QResponse getQuitResponse(boolean ui)
+ {
+ if (gotQuitResponse() != QResponse.CANCEL_QUIT)
+ {
+ return returnResponse(getQuitResponse());
+ }
+
+ boolean interactive = ui && !Platform.isHeadless();
+ // confirm quit if needed and wanted
+ boolean confirmQuit = true;
+
+ if (!interactive)
+ {
+ Console.debug("Non interactive quit -- not confirming");
+ confirmQuit = false;
+ }
+ else if (Jalview2XML.allSavedUpToDate())
+ {
+ Console.debug("Nothing changed -- not confirming quit");
+ confirmQuit = false;
+ }
+ else
+ {
+ confirmQuit = jalview.bin.Cache
+ .getDefault(jalview.gui.Desktop.CONFIRM_KEYBOARD_QUIT, true);
+ Console.debug("Jalview property '"
+ + jalview.gui.Desktop.CONFIRM_KEYBOARD_QUIT
+ + "' is/defaults to " + confirmQuit + " -- "
+ + (confirmQuit ? "" : "not ") + "confirming quit");
+ }
+
+ int answer = JOptionPane.OK_OPTION;
+
+ // if going to confirm, do it before the save in progress check to give
+ // the save time to finish!
+ if (confirmQuit)
+ {
+ 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);
+ }
+
+ if (answer == JOptionPane.CANCEL_OPTION)
+ {
+ Console.debug("QuitHandler: Quit action cancelled by user");
+ return returnResponse(QResponse.CANCEL_QUIT);
+ }
+
+ // check for saves in progress
+ 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)
+ {
+ boolean waiting = (new Date().getTime() - startTime) < waitForSave;
+ while (saving && waiting)
+ {
+ saving = !waitForSave(waitIncrement);
+ waiting = (new Date().getTime() - startTime) < waitForSave;
+ }
+
+ if (saving) // still saving after a wait
+ {
+ 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(file.getName());
+ any = true;
+ }
+ if (!any)
+ {
+ messageSB.append("\n");
+ messageSB.append(MessageManager.getString("label.unknown"));
+ }
+ int waitLonger = interactive ? JOptionPane.YES_OPTION
+ : JOptionPane.NO_OPTION;
+ while (saving && waitLonger == JOptionPane.YES_OPTION)
+ {
+ waitLonger = waitForceQuitCancelQuitOptionDialog(
+ messageSB.toString(),
+ MessageManager.getString("action.wait"));
+ if (waitLonger == JOptionPane.YES_OPTION) // wait
+ {
+ // do wait stuff
+ saving = !waitForSave(waitIncrement);
+ }
+ else if (waitLonger == JOptionPane.NO_OPTION) // force quit
+ {
+ // do a force quit
+ return returnResponse(QResponse.FORCE_QUIT); // shouldn't reach this
+ }
+ else if (waitLonger == JOptionPane.CANCEL_OPTION) // cancel quit
+ {
+ return returnResponse(QResponse.CANCEL_QUIT);
+ }
+ else
+ {
+ Console.debug("**** Shouldn't have got here!");
+ }
+ }
+ }
+ }
+
+ // not cancelled and not saving
+ return returnResponse(QResponse.QUIT);
+ }
+
+ public static int frameOnTop(String label, String actionString,
+ int JOPTIONPANE_OPTION, int JOPTIONPANE_MESSAGETYPE)
+ {
+ return frameOnTop(new JFrame(), label, actionString, JOPTIONPANE_OPTION,
+ JOPTIONPANE_MESSAGETYPE);
+ }
+
+ public static int frameOnTop(JFrame dialogParent, String label,
+ String actionString, int JOPTIONPANE_OPTION,
+ int JOPTIONPANE_MESSAGETYPE)
+ {
+ // ensure Jalview window is brought to front for Quit confirmation
+ // window to be visible
+
+ // this method of raising the Jalview window is broken in java
+ // jalviewDesktop.setVisible(true);
+ // jalviewDesktop.toFront();
+
+ // a better hack which works instead
+
+ dialogParent.setAlwaysOnTop(true);
+
+ int answer = JOptionPane.showConfirmDialog(dialogParent, label,
+ actionString, JOPTIONPANE_OPTION, JOPTIONPANE_MESSAGETYPE);
+
+ dialogParent.setAlwaysOnTop(false);
+ dialogParent.dispose();
+
+ return answer;
+ }
+
+ private static int waitForceQuitCancelQuitOptionDialog(Object message,
+ String title)
+ {
+ JFrame dialogParent = new JFrame();
+ dialogParent.setAlwaysOnTop(true);
+ String wait = MessageManager.getString("action.wait");
+ Object[] options = { wait,
+ MessageManager.getString("action.force_quit"),
+ MessageManager.getString("action.cancel_quit") };
+
+ int answer = JOptionPane.showOptionDialog(dialogParent, message, title,
+ JOptionPane.YES_NO_CANCEL_OPTION, JOptionPane.WARNING_MESSAGE,
+ null, options, wait);
+
+ return answer;
+ }
+
+ private static boolean waitForSave(long t)
+ {
+ boolean ret = false;
+ try
+ {
+ Console.debug("Wait for save to complete: " + t + "ms");
+ long c = 0;
+ int i = 100;
+ while (c < t)
+ {
+ Thread.sleep(i);
+ c += i;
+ ret = !BackupFiles.hasSavesInProgress();
+ if (ret)
+ {
+ Console.debug(
+ "Save completed whilst waiting (" + c + "/" + t + "ms)");
+ return ret;
+ }
+ if (c % 1000 < i) // just gone over another second
+ {
+ Console.debug("...waiting (" + c + "/" + t + "ms]");
+ }
+ }
+ } catch (InterruptedException e)
+ {
+ Console.debug("Wait for save interrupted");
+ }
+ Console.debug("Save has " + (ret ? "" : "not ") + "completed");
+ return ret;
+ }
+
+}
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
*/
{
AlignFrame[] frames = Desktop.getAlignFrames();
+ setStateSavedUpToDate(true);
+
+ 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++;
+ }
+ }
+
if (frames == null)
{
return;
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<>();
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;
+ }
}
*/
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;
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;
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;
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
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;
{
this.historyList.push(command);
broadcastCommand(command, false);
+ setSavedUpToDate(false);
+ Jalview2XML.setStateSavedUpToDate(false);
}
}
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;
+ }
}