JAL-3310 JAL-3300 two getdown fixes merged
[jalview.git] / src / jalview / gui / Desktop.java
index 9e8624a..cf91b9c 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;
@@ -61,14 +62,6 @@ import java.awt.datatransfer.Clipboard;
 import java.awt.datatransfer.ClipboardOwner;
 import java.awt.datatransfer.DataFlavor;
 import java.awt.datatransfer.Transferable;
-import java.awt.desktop.AboutEvent;
-import java.awt.desktop.AboutHandler;
-import java.awt.desktop.PreferencesEvent;
-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;
@@ -117,7 +110,6 @@ import javax.swing.JDesktopPane;
 import javax.swing.JInternalFrame;
 import javax.swing.JLabel;
 import javax.swing.JMenuItem;
-import javax.swing.JOptionPane;
 import javax.swing.JPanel;
 import javax.swing.JPopupMenu;
 import javax.swing.JProgressBar;
@@ -153,7 +145,7 @@ 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";
+  protected static final String CONFIRM_KEYBOARD_QUIT = "CONFIRM_KEYBOARD_QUIT";
 
   public static HashMap<String, FileWriter> savingFiles = new HashMap<>();
 
@@ -166,8 +158,6 @@ 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)
@@ -371,104 +361,20 @@ public class Desktop extends jalview.jbgui.GDesktop
     }
     */
 
-    // flagging this test to avoid unnecessary reflection
-    if (!setAPQHandlers)
+    try
     {
-      // 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
-      {
-
-       if (Platform.isAMac())
-       {
-               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;
+      APQHandlers.setAPQHandlers(this);
+    } catch (Exception e)
+    {
+      System.out.println("Cannot set APQHandlers");
+      // e.printStackTrace();
+    } catch (Throwable t)
+    {
+      System.out.println("Cannot set APQHandlers");
+      // t.printStackTrace();
     }
 
+
     addWindowListener(new WindowAdapter()
     {
 
@@ -518,18 +424,7 @@ public class Desktop extends jalview.jbgui.GDesktop
     }
     jconsole = new Console(this, showjconsole);
     // add essential build information
-    jconsole.setHeader(
-            "Jalview Version: " + jalview.bin.Cache.getProperty("VERSION")
-                    + "\n" + "Jalview Installation: "
-                    + jalview.bin.Cache.getDefault("INSTALLATION",
-                            "unknown")
-                    + "\n" + "Build Date: "
-                    + jalview.bin.Cache.getDefault("BUILD_DATE", "unknown")
-                    + "\n" + "Java version: "
-                    + System.getProperty("java.version") + "\n"
-                    + System.getProperty("os.arch") + " "
-                    + System.getProperty("os.name") + " "
-                    + System.getProperty("os.version"));
+    jconsole.setHeader(jalview.bin.Cache.getVersionDetailsForConsole());
 
     showConsole(showjconsole);
 
@@ -1106,7 +1001,7 @@ public class Desktop extends jalview.jbgui.GDesktop
     KeyStroke ctrlWKey = KeyStroke.getKeyStroke(KeyEvent.VK_W,
             InputEvent.CTRL_DOWN_MASK);
     KeyStroke cmdWKey = KeyStroke.getKeyStroke(KeyEvent.VK_W,
-            Toolkit.getDefaultToolkit().getMenuShortcutKeyMask());
+            jalview.util.ShortcutKeyMaskExWrapper.getMenuShortcutKeyMaskEx());
 
     InputMap inputMap = frame
             .getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW);
@@ -1220,7 +1115,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, BackupFiles.getEnabled());
 
     chooser.setFileView(new JalviewFileView());
     chooser.setDialogTitle(
@@ -1385,8 +1280,6 @@ public class Desktop extends jalview.jbgui.GDesktop
   @Override
   public void quit()
   {
-    System.out.println("********** Desktop.quit()");
-    System.out.println(savingFiles.toString());
     Dimension screen = Toolkit.getDefaultToolkit().getScreenSize();
     jalview.bin.Cache.setProperty("SCREENGEOMETRY_WIDTH",
             screen.width + "");
@@ -1464,9 +1357,10 @@ public class Desktop extends jalview.jbgui.GDesktop
       message.append("<h1><strong>Version: "
               + jalview.bin.Cache.getProperty("VERSION")
               + "</strong></h1>");
-      message.append("<strong>Last Updated: <em>"
+      message.append("<strong>Built: <em>"
               + jalview.bin.Cache.getDefault("BUILD_DATE", "unknown")
-              + "</em></strong>");
+              + "</em> from " + jalview.bin.Cache.getBuildDetailsForSplash()
+              + "</strong>");
 
     }
     else
@@ -1481,7 +1375,8 @@ public class Desktop extends jalview.jbgui.GDesktop
     if (jalview.bin.Cache.getDefault("LATEST_VERSION", "Checking")
             .equals("Checking"))
     {
-      message.append("<br>...Checking latest version...</br>");
+      // JBP removed this message for 2.11: May be reinstated in future version
+      // message.append("<br>...Checking latest version...</br>");
     }
     else if (!jalview.bin.Cache.getDefault("LATEST_VERSION", "Checking")
             .equals(jalview.bin.Cache.getProperty("VERSION")))
@@ -1741,20 +1636,43 @@ public class Desktop extends jalview.jbgui.GDesktop
   @Override
   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
@@ -1763,38 +1681,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;
@@ -1816,9 +1743,9 @@ public class Desktop extends jalview.jbgui.GDesktop
     final String[] desc = new String[] { "Jalview Project",
         "Jalview Project (old)" };
     JalviewFileChooser chooser = new JalviewFileChooser(
-            Cache.getProperty("LAST_DIRECTORY"), suffix,
-            desc,
-            "Jalview Project");
+            Cache.getProperty("LAST_DIRECTORY"), suffix, desc,
+            "Jalview Project", true, BackupFiles.getEnabled()); // last two booleans: allFiles,
+                                            // allowBackupFiles
     chooser.setFileView(new JalviewFileView());
     chooser.setDialogTitle(MessageManager.getString("label.restore_state"));
 
@@ -2822,7 +2749,7 @@ public class Desktop extends jalview.jbgui.GDesktop
   {
     getRootPane().getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW)
             .put(KeyStroke.getKeyStroke(KeyEvent.VK_Q,
-                    Toolkit.getDefaultToolkit().getMenuShortcutKeyMask()),
+                    jalview.util.ShortcutKeyMaskExWrapper.getMenuShortcutKeyMaskEx()),
                     "Quit");
     getRootPane().getActionMap().put("Quit", new AbstractAction()
     {
@@ -2879,18 +2806,18 @@ public class Desktop extends jalview.jbgui.GDesktop
       progressBarHandlers = new Hashtable<>();
     }
 
-    if (progressBars.get(new Long(id)) != null)
+    if (progressBars.get(Long.valueOf(id)) != null)
     {
-      JPanel panel = progressBars.remove(new Long(id));
-      if (progressBarHandlers.contains(new Long(id)))
+      JPanel panel = progressBars.remove(Long.valueOf(id));
+      if (progressBarHandlers.contains(Long.valueOf(id)))
       {
-        progressBarHandlers.remove(new Long(id));
+        progressBarHandlers.remove(Long.valueOf(id));
       }
       removeProgressPanel(panel);
     }
     else
     {
-      progressBars.put(new Long(id), addProgressPanel(message));
+      progressBars.put(Long.valueOf(id), addProgressPanel(message));
     }
   }
 
@@ -2905,13 +2832,13 @@ public class Desktop extends jalview.jbgui.GDesktop
           final IProgressIndicatorHandler handler)
   {
     if (progressBarHandlers == null
-            || !progressBars.containsKey(new Long(id)))
+            || !progressBars.containsKey(Long.valueOf(id)))
     {
       throw new Error(MessageManager.getString(
               "error.call_setprogressbar_before_registering_handler"));
     }
-    progressBarHandlers.put(new Long(id), handler);
-    final JPanel progressPanel = progressBars.get(new Long(id));
+    progressBarHandlers.put(Long.valueOf(id), handler);
+    final JPanel progressPanel = progressBars.get(Long.valueOf(id));
     if (handler.canCancel())
     {
       JButton cancel = new JButton(