Merge branch 'improvement/JAL-3416_default_to_LIVE_DRAG_MODE_for_flatlaf' into merge...
authorBen Soares <b.soares@dundee.ac.uk>
Wed, 16 Nov 2022 11:52:30 +0000 (11:52 +0000)
committerBen Soares <b.soares@dundee.ac.uk>
Wed, 16 Nov 2022 11:52:30 +0000 (11:52 +0000)
1  2 
src/jalview/bin/Jalview.java
src/jalview/gui/Desktop.java

@@@ -61,8 -61,6 +61,8 @@@ import jalview.ext.so.SequenceOntology
  import jalview.gui.AlignFrame;
  import jalview.gui.Desktop;
  import jalview.gui.PromptUserConfig;
 +import jalview.gui.QuitHandler;
 +import jalview.gui.QuitHandler.QResponse;
  import jalview.io.AppletFormatAdapter;
  import jalview.io.BioJsHTMLOutput;
  import jalview.io.DataSourceType;
@@@ -273,28 -271,6 +273,28 @@@ public class Jalvie
      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)
 +          {
 +            // Got to here by a SIGTERM signal.
 +            // Note we will not actually cancel the quit from here -- it's too
 +            // late -- but we can wait for saving files.
 +            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
        setSystemLookAndFeel();
        if (Platform.isLinux())
        {
-         setMetalLookAndFeel();
+         setLinuxLookAndFeel();
        }
        if (Platform.isMac())
        {
      return set;
    }
  
+   private static boolean setLinuxLookAndFeel()
+   {
+     boolean set = false;
+     set = setFlatLookAndFeel();
+     if (!set)
+       set = setMetalLookAndFeel();
+     // avoid GtkLookAndFeel -- not good results especially on HiDPI
+     if (!set)
+       set = setNimbusLookAndFeel();
+     return set;
+   }
    private static void showUsage()
    {
      System.out.println(
    }
  
    /**
 -   * 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()
@@@ -64,7 -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;
@@@ -82,7 -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;
@@@ -92,7 -90,6 +92,7 @@@ import javax.swing.JProgressBar
  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;
@@@ -105,7 -102,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;
@@@ -197,6 -193,8 +197,8 @@@ public class Desktop extends jalview.jb
    {
      DRAG_MODE = b ? JDesktopPane.LIVE_DRAG_MODE
              : JDesktopPane.OUTLINE_DRAG_MODE;
+     if (desktop != null)
+       desktop.setDragMode(DRAG_MODE);
    }
  
    private JalviewChangeSupport changeSupport = new JalviewChangeSupport();
  
      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)
        {
 -        quit();
 +        QuitHandler.QResponse ret = desktopQuit(true, true); // ui, disposeFlag
        }
      });
  
  
      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()
      {
              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);
    }
  
      Object[] options = new Object[] { MessageManager.getString("action.ok"),
          MessageManager.getString("action.cancel") };
 -    Runnable action = new Runnable()
 -    {
 -      @Override
 -      public void run()
 +    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"))
        {
 -        @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 (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");
    }
  
    /*
 -   * Exit the program
 +   * Check with user and saving files before actually quitting
     */
 -  @Override
 -  public void quit()
 +  public void desktopQuit()
    {
 -    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()));
 +    desktopQuit(true, false);
 +  }
  
 -    if (jconsole != null)
 -    {
 -      storeLastKnownDimensions("JAVA_CONSOLE_", jconsole.getBounds());
 -      jconsole.stopConsole();
 -    }
 -    if (jvnews != null)
 -    {
 -      storeLastKnownDimensions("JALVIEW_RSS_WINDOW_", jvnews.getBounds());
 +  public QuitHandler.QResponse desktopQuit(boolean ui, boolean disposeFlag)
 +  {
 +    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 (dialogExecutor != null)
 -    {
 -      dialogExecutor.shutdownNow();
 -    }
 -    closeAll_actionPerformed(null);
 +      if (jconsole != null)
 +      {
 +        storeLastKnownDimensions("JAVA_CONSOLE_", jconsole.getBounds());
 +        jconsole.stopConsole();
 +      }
  
 -    if (groovyConsole != null)
 -    {
 -      // suppress a possible repeat prompt to save script
 -      groovyConsole.setDirty(false);
 -      groovyConsole.exit();
 -    }
 +      if (jvnews != null)
 +      {
 +        storeLastKnownDimensions("JALVIEW_RSS_WINDOW_", jvnews.getBounds());
 +
 +      }
 +
 +      if (dialogExecutor != null)
 +      {
 +        dialogExecutor.shutdownNow();
 +      }
 +
 +      closeAll_actionPerformed(null);
 +
 +      if (groovyConsole != null)
 +      {
 +        // suppress a possible repeat prompt to save script
 +        groovyConsole.setDirty(false);
 +        groovyConsole.exit();
 +      }
 +
 +      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
 +    };
 +
 +    return QuitHandler.getQuitResponse(ui, doDesktopQuit, doDesktopQuit,
 +            QuitHandler.defaultCancelQuit);
 +  }
 +
 +  /**
 +   * 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);
    }
  
      saveState_actionPerformed(true);
    }
  
 -  private void setProjectFile(File choice)
 +  protected void setProjectFile(File choice)
    {
      this.projectFile = choice;
    }
      // 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);
        @Override
        public void actionPerformed(ActionEvent e)
        {
 -        quit();
 +        desktopQuit();
        }
      });
    }