JAL-3130 Merge of JAL-3130_Java_11_investigations-Ben-2 and updated develop
[jalview.git] / src / jalview / gui / Desktop.java
index 647971e..d3e87ad 100644 (file)
@@ -24,6 +24,7 @@ import jalview.api.AlignViewportI;
 import jalview.api.AlignmentViewPanel;
 import jalview.bin.Cache;
 import jalview.bin.Jalview;
+import jalview.io.BackupFiles;
 import jalview.io.DataSourceType;
 import jalview.io.FileFormat;
 import jalview.io.FileFormatException;
@@ -36,6 +37,7 @@ import jalview.io.JalviewFileChooser;
 import jalview.io.JalviewFileView;
 import jalview.jbgui.GSplitFrame;
 import jalview.jbgui.GStructureViewer;
+import jalview.project.Jalview2XML;
 import jalview.structure.StructureSelectionManager;
 import jalview.urls.IdOrgSettings;
 import jalview.util.ImageMaker;
@@ -67,6 +69,7 @@ import java.awt.desktop.PreferencesHandler;
 import java.awt.desktop.QuitEvent;
 import java.awt.desktop.QuitHandler;
 import java.awt.desktop.QuitResponse;
+import java.awt.desktop.QuitStrategy;
 import java.awt.dnd.DnDConstants;
 import java.awt.dnd.DropTargetDragEvent;
 import java.awt.dnd.DropTargetDropEvent;
@@ -151,6 +154,8 @@ public class Desktop extends jalview.jbgui.GDesktop
 
   private static final String EXPERIMENTAL_FEATURES = "EXPERIMENTAL_FEATURES";
 
+  private static final String CONFIRM_KEYBOARD_QUIT = "CONFIRM_KEYBOARD_QUIT";
+
   public static HashMap<String, FileWriter> savingFiles = new HashMap<>();
 
   private JalviewChangeSupport changeSupport = new JalviewChangeSupport();
@@ -162,6 +167,8 @@ public class Desktop extends jalview.jbgui.GDesktop
 
   private File projectFile;
 
+  private static boolean setAPQHandlers = false;
+
   /**
    * @param listener
    * @see jalview.gui.JalviewChangeSupport#addJalviewPropertyChangeListener(java.beans.PropertyChangeListener)
@@ -354,63 +361,115 @@ public class Desktop extends jalview.jbgui.GDesktop
 
     doConfigureStructurePrefs();
     setTitle("Jalview " + jalview.bin.Cache.getProperty("VERSION"));
-    // setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
-    /* comments
-     * galore
-     * to
-     * change the line numbers
-     */
-
     /*
     if (!Platform.isAMac())
     {
       // this.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
     }
     else
+    {
+     this.setDefaultCloseOperation(WindowConstants.DO_NOTHING_ON_CLOSE);
+    }
     */
-    // {
-    // this.setDefaultCloseOperation(WindowConstants.DO_NOTHING_ON_CLOSE);
-    java.awt.Desktop hdesktop = java.awt.Desktop.getDesktop();
 
-    hdesktop.setAboutHandler(new AboutHandler()
-    {
-      @Override
-      public void handleAbout(AboutEvent e)
-      {
-        aboutMenuItem_actionPerformed(null);
-      }
-    });
-    hdesktop.setPreferencesHandler(new PreferencesHandler()
-    {
-      @Override
-      public void handlePreferences(PreferencesEvent e)
-      {
-        preferences_actionPerformed(null);
-      }
-    });
-    hdesktop.setQuitHandler(new QuitHandler()
+    // flagging this test to avoid unnecessary reflection
+    if (!setAPQHandlers)
     {
-      @Override
-      public void handleQuitRequestWith(QuitEvent e, QuitResponse r)
+      // see if the Quit, About and Preferences handlers are available
+      Class desktopClass = java.awt.Desktop.class;
+      java.awt.Desktop hdesktop = java.awt.Desktop.getDesktop();
+
+      try
       {
-        int n = JOptionPane.showConfirmDialog(null,
-                MessageManager.getString("label.quit_jalview"),
-                MessageManager.getString("action.quit"),
-                JOptionPane.OK_CANCEL_OPTION, JOptionPane.PLAIN_MESSAGE,
-                null);
-        if (n == JOptionPane.OK_OPTION)
-        {
-          System.out.println("Shortcut Quit confirmed by user");
-          quit();
-        }
-        else
+
+        if (Platform.isAMac())
         {
-          System.out.println("Shortcut Quit cancelled by user");
+          if (desktopClass.getDeclaredMethod("setAboutHandler",
+                  new Class[]
+                  { AboutHandler.class }) != null)
+          {
+
+            hdesktop.setAboutHandler(new AboutHandler()
+            {
+              @Override
+              public void handleAbout(AboutEvent e)
+              {
+                aboutMenuItem_actionPerformed(null);
+              }
+            });
+
+          }
+
+          if (desktopClass.getDeclaredMethod("setPreferencesHandler",
+                  new Class[]
+                  { PreferencesHandler.class }) != null)
+          {
+
+            hdesktop.setPreferencesHandler(new PreferencesHandler()
+            {
+              @Override
+              public void handlePreferences(PreferencesEvent e)
+              {
+                preferences_actionPerformed(null);
+              }
+            });
+
+          }
+
+          if (desktopClass.getDeclaredMethod("setQuitHandler",
+                  new Class[]
+                  { QuitHandler.class }) != null)
+          {
+
+            hdesktop.setQuitHandler(new QuitHandler()
+            {
+              @Override
+              public void handleQuitRequestWith(QuitEvent e, QuitResponse r)
+              {
+                boolean confirmQuit = jalview.bin.Cache
+                        .getDefault(CONFIRM_KEYBOARD_QUIT, true);
+                int n;
+                if (confirmQuit)
+                {
+                  n = JOptionPane.showConfirmDialog(null,
+                          MessageManager.getString("label.quit_jalview"),
+                          MessageManager.getString("action.quit"),
+                          JOptionPane.OK_CANCEL_OPTION,
+                          JOptionPane.PLAIN_MESSAGE, null);
+                }
+                else
+                {
+                  n = JOptionPane.OK_OPTION;
+                }
+                if (n == JOptionPane.OK_OPTION)
+                {
+                  System.out.println("Shortcut Quit confirmed by user");
+                  quit();
+                  r.performQuit(); // probably won't reach this line, but just
+                                   // in
+                                   // case
+                }
+                else
+                {
+                  r.cancelQuit();
+                  System.out.println("Shortcut Quit cancelled by user");
+                }
+              }
+            });
+            hdesktop.setQuitStrategy(QuitStrategy.CLOSE_ALL_WINDOWS);
+
+          }
         }
+
+      } catch (NoSuchMethodException e)
+      {
+        System.out.println(
+                "NoSuchMethodException when looking for About, Preferences, Quit Handlers");
+        e.printStackTrace();
       }
-    });
 
-    // }
+      setAPQHandlers = true;
+    }
 
     addWindowListener(new WindowAdapter()
     {
@@ -1163,7 +1222,7 @@ public class Desktop extends jalview.jbgui.GDesktop
   {
     String fileFormat = Cache.getProperty("DEFAULT_FILE_FORMAT");
     JalviewFileChooser chooser = JalviewFileChooser
-            .forRead(Cache.getProperty("LAST_DIRECTORY"), fileFormat);
+            .forRead(Cache.getProperty("LAST_DIRECTORY"), fileFormat, true);
 
     chooser.setFileView(new JalviewFileView());
     chooser.setDialogTitle(
@@ -1678,28 +1737,49 @@ public class Desktop extends jalview.jbgui.GDesktop
   }
 
   /**
-   * DOCUMENT ME!
-   * 
-   * @param e
-   *          DOCUMENT ME!
+   * Shows a file chooser dialog and writes out the current session as a Jalview
+   * project file
    */
   @Override
-  public void saveState_actionPerformed(ActionEvent e)
+  public void saveState_actionPerformed()
   {
-    JalviewFileChooser chooser = new JalviewFileChooser("jvp",
-            "Jalview Project");
+    saveState_actionPerformed(false);
+  }
 
-    chooser.setFileView(new JalviewFileView());
-    chooser.setDialogTitle(MessageManager.getString("label.save_state"));
+  public void saveState_actionPerformed(boolean saveAs)
+  {
+    java.io.File projectFile = getProjectFile();
+    // autoSave indicates we already have a file and don't need to ask
+    boolean autoSave = projectFile != null && !saveAs
+            && BackupFiles.getEnabled();
 
-    int value = chooser.showSaveDialog(this);
+    // System.out.println("autoSave="+autoSave+", projectFile='"+projectFile+"',
+    // saveAs="+saveAs+", Backups
+    // "+(BackupFiles.getEnabled()?"enabled":"disabled"));
 
-    if (value == JalviewFileChooser.APPROVE_OPTION)
+    boolean approveSave = false;
+    if (!autoSave)
     {
-      final Desktop me = this;
-      final java.io.File choice = chooser.getSelectedFile();
-      setProjectFile(choice);
+      JalviewFileChooser chooser = new JalviewFileChooser("jvp",
+              "Jalview Project");
+
+      chooser.setFileView(new JalviewFileView());
+      chooser.setDialogTitle(MessageManager.getString("label.save_state"));
+
+      int value = chooser.showSaveDialog(this);
+
+      if (value == JalviewFileChooser.APPROVE_OPTION)
+      {
+        projectFile = chooser.getSelectedFile();
+        setProjectFile(projectFile);
+        approveSave = true;
+      }
+    }
 
+    if (approveSave || autoSave)
+    {
+      final Desktop me = this;
+      final java.io.File chosenFile = projectFile;
       new Thread(new Runnable()
       {
         @Override
@@ -1708,38 +1788,47 @@ public class Desktop extends jalview.jbgui.GDesktop
           // TODO: refactor to Jalview desktop session controller action.
           setProgressBar(MessageManager.formatMessage(
                   "label.saving_jalview_project", new Object[]
-                  { choice.getName() }), choice.hashCode());
+                  { chosenFile.getName() }), chosenFile.hashCode());
           jalview.bin.Cache.setProperty("LAST_DIRECTORY",
-                  choice.getParent());
+                  chosenFile.getParent());
           // TODO catch and handle errors for savestate
           // TODO prevent user from messing with the Desktop whilst we're saving
           try
           {
-            new Jalview2XML().saveState(choice);
+            BackupFiles backupfiles = new BackupFiles(chosenFile);
+
+            new Jalview2XML().saveState(backupfiles.getTempFile());
+
+            backupfiles.setWriteSuccess(true);
+            backupfiles.rollBackupsAndRenameTempFile();
           } catch (OutOfMemoryError oom)
           {
-            new OOMWarning(
-                    "Whilst saving current state to " + choice.getName(),
-                    oom);
+            new OOMWarning("Whilst saving current state to "
+                    + chosenFile.getName(), oom);
           } catch (Exception ex)
           {
-            Cache.log.error(
-                    "Problems whilst trying to save to " + choice.getName(),
-                    ex);
+            Cache.log.error("Problems whilst trying to save to "
+                    + chosenFile.getName(), ex);
             JvOptionPane.showMessageDialog(me,
                     MessageManager.formatMessage(
                             "label.error_whilst_saving_current_state_to",
                             new Object[]
-                            { choice.getName() }),
+                            { chosenFile.getName() }),
                     MessageManager.getString("label.couldnt_save_project"),
                     JvOptionPane.WARNING_MESSAGE);
           }
-          setProgressBar(null, choice.hashCode());
+          setProgressBar(null, chosenFile.hashCode());
         }
       }).start();
     }
   }
 
+  @Override
+  public void saveAsState_actionPerformed(ActionEvent e)
+  {
+    saveState_actionPerformed(true);
+  }
+
   private void setProjectFile(File choice)
   {
     this.projectFile = choice;
@@ -1751,20 +1840,19 @@ public class Desktop extends jalview.jbgui.GDesktop
   }
 
   /**
-   * DOCUMENT ME!
-   * 
-   * @param e
-   *          DOCUMENT ME!
+   * Shows a file chooser dialog and tries to read in the selected file as a
+   * Jalview project
    */
   @Override
-  public void loadState_actionPerformed(ActionEvent e)
+  public void loadState_actionPerformed()
   {
+    final String[] suffix = new String[] { "jvp", "jar" };
+    final String[] desc = new String[] { "Jalview Project",
+        "Jalview Project (old)" };
     JalviewFileChooser chooser = new JalviewFileChooser(
-            Cache.getProperty("LAST_DIRECTORY"), new String[]
-            { "jvp", "jar" },
-            new String[]
-            { "Jalview Project", "Jalview Project (old)" },
-            "Jalview Project");
+            Cache.getProperty("LAST_DIRECTORY"), suffix, desc,
+            "Jalview Project", true, true); // last two booleans: allFiles,
+                                            // allowBackupFiles
     chooser.setFileView(new JalviewFileView());
     chooser.setDialogTitle(MessageManager.getString("label.restore_state"));