JAL-4125 Additions to JvOptionPane and QuitHandler with StructureViewerBase handling...
[jalview.git] / src / jalview / gui / Desktop.java
index 585537e..06afe81 100644 (file)
@@ -64,6 +64,7 @@ import java.util.List;
 import java.util.ListIterator;
 import java.util.Locale;
 import java.util.Vector;
+import java.util.concurrent.Callable;
 import java.util.concurrent.ExecutorService;
 import java.util.concurrent.Executors;
 import java.util.concurrent.Semaphore;
@@ -81,6 +82,7 @@ import javax.swing.JCheckBox;
 import javax.swing.JComboBox;
 import javax.swing.JComponent;
 import javax.swing.JDesktopPane;
+import javax.swing.JFrame;
 import javax.swing.JInternalFrame;
 import javax.swing.JLabel;
 import javax.swing.JMenuItem;
@@ -103,6 +105,7 @@ import jalview.api.AlignmentViewPanel;
 import jalview.bin.Cache;
 import jalview.bin.Jalview;
 import jalview.gui.ImageExporter.ImageWriterI;
+import jalview.gui.QuitHandler.QResponse;
 import jalview.io.BackupFiles;
 import jalview.io.DataSourceType;
 import jalview.io.FileFormat;
@@ -116,8 +119,6 @@ import jalview.io.JalviewFileChooser;
 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;
@@ -190,6 +191,16 @@ public class Desktop extends jalview.jbgui.GDesktop
 
   public static HashMap<String, FileWriter> savingFiles = new HashMap<String, FileWriter>();
 
+  private static int DRAG_MODE = JDesktopPane.OUTLINE_DRAG_MODE;
+
+  public static void setLiveDragMode(boolean b)
+  {
+    DRAG_MODE = b ? JDesktopPane.LIVE_DRAG_MODE
+            : JDesktopPane.OUTLINE_DRAG_MODE;
+    if (desktop != null)
+      desktop.setDragMode(DRAG_MODE);
+  }
+
   private JalviewChangeSupport changeSupport = new JalviewChangeSupport();
 
   public static boolean nosplash = false;
@@ -454,17 +465,14 @@ public class Desktop extends jalview.jbgui.GDesktop
 
     setIconImages(ChannelProperties.getIconList());
 
+    // override quit handling when GUI OS close [X] button pressed
     this.setDefaultCloseOperation(WindowConstants.DO_NOTHING_ON_CLOSE);
     addWindowListener(new WindowAdapter()
     {
       @Override
       public void windowClosing(WindowEvent ev)
       {
-        QResponse qresponse = desktopQuit();
-        if (qresponse != QResponse.CANCEL_QUIT)
-        {
-          instance.dispose();
-        }
+        QuitHandler.QResponse ret = desktopQuit(true, true); // ui, disposeFlag
       }
     });
 
@@ -489,7 +497,7 @@ public class Desktop extends jalview.jbgui.GDesktop
     }
 
     getContentPane().add(desktop, BorderLayout.CENTER);
-    desktop.setDragMode(JDesktopPane.OUTLINE_DRAG_MODE);
+    desktop.setDragMode(DRAG_MODE);
 
     // This line prevents Windows Look&Feel resizing all new windows to maximum
     // if previous window was maximised
@@ -1178,36 +1186,32 @@ public class Desktop extends jalview.jbgui.GDesktop
             MessageManager.getString("label.open_local_file"));
     chooser.setToolTipText(MessageManager.getString("action.open"));
 
-    chooser.setResponseHandler(0, new Runnable()
-    {
-      @Override
-      public void run()
-      {
-        File selectedFile = chooser.getSelectedFile();
-        Cache.setProperty("LAST_DIRECTORY", selectedFile.getParent());
+    chooser.setResponseHandler(0, () -> {
+      File selectedFile = chooser.getSelectedFile();
+      Cache.setProperty("LAST_DIRECTORY", selectedFile.getParent());
 
-        FileFormatI format = chooser.getSelectedFormat();
+      FileFormatI format = chooser.getSelectedFormat();
 
-        /*
-         * Call IdentifyFile to verify the file contains what its extension implies.
-         * Skip this step for dynamically added file formats, because IdentifyFile does
-         * not know how to recognise them.
-         */
-        if (FileFormats.getInstance().isIdentifiable(format))
+      /*
+       * Call IdentifyFile to verify the file contains what its extension implies.
+       * Skip this step for dynamically added file formats, because IdentifyFile does
+       * not know how to recognise them.
+       */
+      if (FileFormats.getInstance().isIdentifiable(format))
+      {
+        try
         {
-          try
-          {
-            format = new IdentifyFile().identify(selectedFile,
-                    DataSourceType.FILE);
-          } catch (FileFormatException e)
-          {
-            // format = null; //??
-          }
+          format = new IdentifyFile().identify(selectedFile,
+                  DataSourceType.FILE);
+        } catch (FileFormatException e)
+        {
+          // format = null; //??
         }
-
-        new FileLoader().LoadFile(viewport, selectedFile,
-                DataSourceType.FILE, format);
       }
+
+      new FileLoader().LoadFile(viewport, selectedFile, DataSourceType.FILE,
+              format);
+      return null;
     });
     chooser.showOpenDialog(this);
   }
@@ -1263,64 +1267,60 @@ public class Desktop extends jalview.jbgui.GDesktop
 
     Object[] options = new Object[] { MessageManager.getString("action.ok"),
         MessageManager.getString("action.cancel") };
-    Runnable action = new Runnable()
-    {
-      @Override
-      public void run()
-      {
-        @SuppressWarnings("unchecked")
-        String url = (history instanceof JTextField
-                ? ((JTextField) history).getText()
-                : ((JComboBox<String>) history).getEditor().getItem()
-                        .toString().trim());
+    Callable<Void> action = () -> {
+      @SuppressWarnings("unchecked")
+      String url = (history instanceof JTextField
+              ? ((JTextField) history).getText()
+              : ((JComboBox<String>) history).getEditor().getItem()
+                      .toString().trim());
 
-        if (url.toLowerCase(Locale.ROOT).endsWith(".jar"))
+      if (url.toLowerCase(Locale.ROOT).endsWith(".jar"))
+      {
+        if (viewport != null)
         {
-          if (viewport != null)
-          {
-            new FileLoader().LoadFile(viewport, url, DataSourceType.URL,
-                    FileFormat.Jalview);
-          }
-          else
-          {
-            new FileLoader().LoadFile(url, DataSourceType.URL,
-                    FileFormat.Jalview);
-          }
+          new FileLoader().LoadFile(viewport, url, DataSourceType.URL,
+                  FileFormat.Jalview);
         }
         else
         {
-          FileFormatI format = null;
-          try
-          {
-            format = new IdentifyFile().identify(url, DataSourceType.URL);
-          } catch (FileFormatException e)
-          {
-            // TODO revise error handling, distinguish between
-            // URL not found and response not valid
-          }
+          new FileLoader().LoadFile(url, DataSourceType.URL,
+                  FileFormat.Jalview);
+        }
+      }
+      else
+      {
+        FileFormatI format = null;
+        try
+        {
+          format = new IdentifyFile().identify(url, DataSourceType.URL);
+        } catch (FileFormatException e)
+        {
+          // TODO revise error handling, distinguish between
+          // URL not found and response not valid
+        }
 
-          if (format == null)
-          {
-            String msg = MessageManager
-                    .formatMessage("label.couldnt_locate", url);
-            JvOptionPane.showInternalMessageDialog(Desktop.desktop, msg,
-                    MessageManager.getString("label.url_not_found"),
-                    JvOptionPane.WARNING_MESSAGE);
+        if (format == null)
+        {
+          String msg = MessageManager.formatMessage("label.couldnt_locate",
+                  url);
+          JvOptionPane.showInternalMessageDialog(Desktop.desktop, msg,
+                  MessageManager.getString("label.url_not_found"),
+                  JvOptionPane.WARNING_MESSAGE);
 
-            return;
-          }
+          return null; // Void
+        }
 
-          if (viewport != null)
-          {
-            new FileLoader().LoadFile(viewport, url, DataSourceType.URL,
-                    format);
-          }
-          else
-          {
-            new FileLoader().LoadFile(url, DataSourceType.URL, format);
-          }
+        if (viewport != null)
+        {
+          new FileLoader().LoadFile(viewport, url, DataSourceType.URL,
+                  format);
+        }
+        else
+        {
+          new FileLoader().LoadFile(url, DataSourceType.URL, format);
         }
       }
+      return null; // Void
     };
     String dialogOption = MessageManager
             .getString("label.input_alignment_from_url");
@@ -1352,61 +1352,72 @@ public class Desktop extends jalview.jbgui.GDesktop
   /*
    * Check with user and saving files before actually quitting
    */
-  public QResponse desktopQuit()
+  public void desktopQuit()
   {
-    return desktopQuit(true);
+    desktopQuit(true, false);
   }
 
-  public QResponse desktopQuit(boolean ui)
+  public QuitHandler.QResponse desktopQuit(boolean ui, boolean disposeFlag)
   {
-    QuitHandler.QResponse qresponse = QuitHandler.getQuitResponse(ui);
+    final Callable<Void> doDesktopQuit = () -> {
+      Dimension screen = Toolkit.getDefaultToolkit().getScreenSize();
+      Cache.setProperty("SCREENGEOMETRY_WIDTH", screen.width + "");
+      Cache.setProperty("SCREENGEOMETRY_HEIGHT", screen.height + "");
+      storeLastKnownDimensions("", new Rectangle(getBounds().x,
+              getBounds().y, getWidth(), getHeight()));
 
-    if (qresponse == QResponse.CANCEL_QUIT)
-    {
-      return qresponse;
-    }
+      if (jconsole != null)
+      {
+        storeLastKnownDimensions("JAVA_CONSOLE_", jconsole.getBounds());
+        jconsole.stopConsole();
+      }
 
-    Dimension screen = Toolkit.getDefaultToolkit().getScreenSize();
-    Cache.setProperty("SCREENGEOMETRY_WIDTH", screen.width + "");
-    Cache.setProperty("SCREENGEOMETRY_HEIGHT", screen.height + "");
-    storeLastKnownDimensions("", new Rectangle(getBounds().x, getBounds().y,
-            getWidth(), getHeight()));
+      if (jvnews != null)
+      {
+        storeLastKnownDimensions("JALVIEW_RSS_WINDOW_", jvnews.getBounds());
+      }
 
-    if (jconsole != null)
-    {
-      storeLastKnownDimensions("JAVA_CONSOLE_", jconsole.getBounds());
-      jconsole.stopConsole();
-    }
-    if (jvnews != null)
-    {
-      storeLastKnownDimensions("JALVIEW_RSS_WINDOW_", jvnews.getBounds());
+      closeAll_actionPerformed(null);
 
-    }
-    if (dialogExecutor != null)
-    {
-      dialogExecutor.shutdownNow();
-    }
-    closeAll_actionPerformed(null);
+      // check for aborted quit
+      if (QuitHandler.quitCancelled())
+      {
+        jalview.bin.Console.debug("Desktop aborting quit");
+        return null;
+      }
 
-    if (groovyConsole != null)
-    {
-      // suppress a possible repeat prompt to save script
-      groovyConsole.setDirty(false);
-      groovyConsole.exit();
-    }
+      if (dialogExecutor != null)
+      {
+        dialogExecutor.shutdownNow();
+      }
 
-    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);
-    }
+      if (groovyConsole != null)
+      {
+        // suppress a possible repeat prompt to save script
+        groovyConsole.setDirty(false);
+        groovyConsole.exit();
+      }
 
-    jalview.bin.Console.debug("Quit selected by user");
-    quit();
+      if (QuitHandler.gotQuitResponse() == 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");
+      if (disposeFlag)
+      {
+        instance.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
+        // instance.dispose();
+      }
+      instance.quit();
+
+      return null; // Void
+    };
 
-    // unlikely to reach here!
-    return QResponse.QUIT;
+    return QuitHandler.getQuitResponse(ui, doDesktopQuit, doDesktopQuit,
+            QuitHandler.defaultCancelQuit);
   }
 
   /**
@@ -1540,11 +1551,17 @@ public class Desktop extends jalview.jbgui.GDesktop
   {
     // TODO show a progress bar while closing?
     JInternalFrame[] frames = desktop.getAllFrames();
+    boolean quitting = QuitHandler.quitting();
     for (int i = 0; i < frames.length; i++)
     {
       try
       {
         frames[i].setClosed(true);
+        // check for cancelled quit
+        if (quitting && QuitHandler.quitCancelled())
+        {
+          return;
+        }
       } catch (java.beans.PropertyVetoException ex)
       {
       }
@@ -1827,7 +1844,7 @@ public class Desktop extends jalview.jbgui.GDesktop
     saveState_actionPerformed(true);
   }
 
-  private void setProjectFile(File choice)
+  protected void setProjectFile(File choice)
   {
     this.projectFile = choice;
   }
@@ -1855,42 +1872,37 @@ public class Desktop extends jalview.jbgui.GDesktop
     // allowBackupFiles
     chooser.setFileView(new JalviewFileView());
     chooser.setDialogTitle(MessageManager.getString("label.restore_state"));
-    chooser.setResponseHandler(0, new Runnable()
-    {
-      @Override
-      public void run()
+    chooser.setResponseHandler(0, () -> {
+      File selectedFile = chooser.getSelectedFile();
+      setProjectFile(selectedFile);
+      String choice = selectedFile.getAbsolutePath();
+      Cache.setProperty("LAST_DIRECTORY", selectedFile.getParent());
+      new Thread(new Runnable()
       {
-        File selectedFile = chooser.getSelectedFile();
-        setProjectFile(selectedFile);
-        String choice = selectedFile.getAbsolutePath();
-        Cache.setProperty("LAST_DIRECTORY", selectedFile.getParent());
-        new Thread(new Runnable()
+        @Override
+        public void run()
         {
-          @Override
-          public void run()
+          try
           {
-            try
-            {
-              new Jalview2XML().loadJalviewAlign(selectedFile);
-            } catch (OutOfMemoryError oom)
-            {
-              new OOMWarning("Whilst loading project from " + choice, oom);
-            } catch (Exception ex)
-            {
-              jalview.bin.Console.error(
-                      "Problems whilst loading project from " + choice, ex);
-              JvOptionPane.showMessageDialog(Desktop.desktop,
-                      MessageManager.formatMessage(
-                              "label.error_whilst_loading_project_from",
-                              new Object[]
-                              { choice }),
-                      MessageManager
-                              .getString("label.couldnt_load_project"),
-                      JvOptionPane.WARNING_MESSAGE);
-            }
+            new Jalview2XML().loadJalviewAlign(selectedFile);
+          } catch (OutOfMemoryError oom)
+          {
+            new OOMWarning("Whilst loading project from " + choice, oom);
+          } catch (Exception ex)
+          {
+            jalview.bin.Console.error(
+                    "Problems whilst loading project from " + choice, ex);
+            JvOptionPane.showMessageDialog(Desktop.desktop,
+                    MessageManager.formatMessage(
+                            "label.error_whilst_loading_project_from",
+                            new Object[]
+                            { choice }),
+                    MessageManager.getString("label.couldnt_load_project"),
+                    JvOptionPane.WARNING_MESSAGE);
           }
-        }, "Project Loader").start();
-      }
+        }
+      }, "Project Loader").start();
+      return null;
     });
 
     chooser.showOpenDialog(this);
@@ -2554,12 +2566,7 @@ public class Desktop extends jalview.jbgui.GDesktop
       @Override
       public void actionPerformed(ActionEvent e)
       {
-        QResponse qresponse = desktopQuit();
-        if (qresponse == QResponse.CANCEL_QUIT)
-        {
-          jalview.bin.Console
-                  .debug("Desktop: Quit action cancelled by user");
-        }
+        desktopQuit();
       }
     });
   }
@@ -2975,7 +2982,7 @@ public class Desktop extends jalview.jbgui.GDesktop
   /**
    * single thread that handles display of dialogs to user.
    */
-  ExecutorService dialogExecutor = Executors.newSingleThreadExecutor();
+  ExecutorService dialogExecutor = Executors.newFixedThreadPool(3);
 
   /**
    * flag indicating if dialogExecutor should try to acquire a permit