Merge branch 'merge/JAL-1988_JAL-3772+JAL-3416+JAL-4054+JAL-4064' into bug/JAL-4125_f...
authorBen Soares <b.soares@dundee.ac.uk>
Mon, 13 Feb 2023 20:18:00 +0000 (20:18 +0000)
committerBen Soares <b.soares@dundee.ac.uk>
Mon, 13 Feb 2023 20:18:00 +0000 (20:18 +0000)
1  2 
resources/lang/Messages.properties
resources/lang/Messages_es.properties
src/jalview/gui/Desktop.java
src/jalview/gui/QuitHandler.java
src/jalview/viewmodel/AlignmentViewport.java

@@@ -36,9 -36,8 +36,10 @@@ action.force_quit = Force qui
  label.quit_jalview = Are you sure you want to quit Jalview?
  label.wait_for_save = Wait for save
  label.unsaved_changes = There are unsaved changes.
+ label.unsaved_alignments = There are unsaved alignments.
  label.save_in_progress = Some files are still saving:
 +label.confirm_quit_viewer = An external viewer is still open.  Close the external window as well?
 +label.confirm_quit_viewers = External viewers are still open.  Close these external windows as well?
  label.unknown = Unknown
  label.quit_after_saving = Jalview will quit after saving.
  label.all_saved = All files saved.
@@@ -142,8 -141,6 +143,8 @@@ action.calculate = Calculat
  action.select_all = Select all
  action.select_highlighted_columns = Select Highlighted Columns
  tooltip.select_highlighted_columns = Press B to mark highlighted columns, Ctrl-(or Cmd)-B to toggle, and Alt-B to mark all but highlighted columns 
 +action.copy_highlighted_regions = Copy Highlighted Regions
 +tooltip.copy_highlighted_regions = Copies highlighted sequence regions to the clipboard for export or further analysis
  action.deselect_all = Deselect all
  action.invert_selection = Invert selection
  action.using_jmol = Using Jmol
@@@ -215,7 -212,6 +216,7 @@@ label.colourScheme_turnpropensity = Tur
  label.colourScheme_buriedindex = Buried Index
  label.colourScheme_purine/pyrimidine = Purine/Pyrimidine
  label.colourScheme_nucleotide = Nucleotide
 +label.colourScheme_nucleotideambiguity = Nucleotide Ambiguity
  label.colourScheme_t-coffeescores = T-Coffee Scores
  label.colourScheme_rnahelices = By RNA Helices
  label.colourScheme_sequenceid = Sequence ID Colour
@@@ -516,7 -512,6 +517,7 @@@ label.delete_gaps = Delete {0} gap
  label.sequence_details = Sequence Details
  label.viewer_help = {0} Help
  label.close_viewer = Close Viewer
 +label.close_viewers = Close Viewers
  label.confirm_close_viewer = This will close Jalview''s connection to {0}.<br>Do you want to close the {1} window as well?
  label.all = All
  label.sort_by = Sort alignment by
@@@ -1414,8 -1409,6 +1415,8 @@@ label.click_to_edit = Click to edit, ri
  label.by_annotation_tooltip = Annotation Colour is configured from the main Colour menu
  label.show_linked_features = Show {0} features
  label.on_top = on top
 +label.include_features = Include Features
 +label.search_features = Search descriptions of displayed features
  label.include_linked_features = Include {0} features
  label.include_linked_tooltip = Include visible {0} features<br>converted to local sequence coordinates
  label.features_not_shown = {0} feature(s) not shown
@@@ -1424,7 -1417,6 +1425,7 @@@ label.ignore_hidden = Ignore hidden col
  label.ignore_hidden_tooltip = Ignore any characters in hidden columns when matching
  label.log_level = Log level
  label.log_level_tooltip = Temporarily set the log level for this console. The log level will revert to {0} when this Java console is closed.
 +label.copy = Copy
  label.copy_to_clipboard = Copy to clipboard
  label.copy_to_clipboard_tooltip = Copy all of the log text in this console to the system clipboard
  label.startup = Startup
@@@ -36,6 -36,7 +36,7 @@@ action.force_quit = Forzar la salid
  label.quit_jalview = ¿Estás seguro de que quieres salir de Jalview?
  label.wait_for_save = Esperar a guardar
  label.unsaved_changes = Hay cambios sin guardar.
+ label.unsaved_alignments = Hay alineamientos sin guardar.
  label.save_in_progress = Algunos archivos aún se están guardando:
  label.unknown = desconocido
  label.quit_after_saving = Jalview se cerrará después de guardar.
@@@ -204,7 -205,6 +205,7 @@@ label.colourScheme_turnpropensity = Ten
  label.colourScheme_buriedindex = Índice de encubrimiento
  label.colourScheme_purine/pyrimidine = Purina/Pirimidina
  label.colourScheme_nucleotide = Nucleótido
 +label.colourScheme_nucleotideambiguity = Ambigüedad de nucleótido
  label.colourScheme_t-coffeescores = Puntuación del T-Coffee
  label.colourScheme_rnahelices = Por hélices de RNA
  label.colourScheme_sequenceid = Color de ID de secuencia
@@@ -102,7 -102,6 +102,7 @@@ import org.stackoverflowusers.file.Wind
  
  import jalview.api.AlignViewportI;
  import jalview.api.AlignmentViewPanel;
 +import jalview.api.structures.JalviewStructureDisplayI;
  import jalview.bin.Cache;
  import jalview.bin.Jalview;
  import jalview.gui.ImageExporter.ImageWriterI;
@@@ -503,11 -502,15 +503,15 @@@ public class Desktop extends jalview.jb
      // This line prevents Windows Look&Feel resizing all new windows to maximum
      // if previous window was maximised
      desktop.setDesktopManager(new MyDesktopManager(
-             (Platform.isWindowsAndNotJS() ? new DefaultDesktopManager()
-                     : Platform.isAMacAndNotJS()
-                             ? new AquaInternalFrameManager(
-                                     desktop.getDesktopManager())
-                             : desktop.getDesktopManager())));
+             Platform.isJS() ? desktop.getDesktopManager()
+                     : new DefaultDesktopManager()));
+     /*
+     (Platform.isWindowsAndNotJS() ? new DefaultDesktopManager()
+             : Platform.isAMacAndNotJS()
+                     ? new AquaInternalFrameManager(
+                             desktop.getDesktopManager())
+                     : desktop.getDesktopManager())));
+                     */
  
      Rectangle dims = getLastKnownDimensions("");
      if (dims != null)
        if (jvnews != null)
        {
          storeLastKnownDimensions("JALVIEW_RSS_WINDOW_", jvnews.getBounds());
 +      }
 +
 +      // Frames should all close automatically. Keeping external
 +      // viewers open should already be decided by user.
 +      closeAll_actionPerformed(null);
  
 +      // check for aborted quit
 +      if (QuitHandler.quitCancelled())
 +      {
 +        jalview.bin.Console.debug("Desktop aborting quit");
 +        return null;
        }
  
        if (dialogExecutor != null)
          dialogExecutor.shutdownNow();
        }
  
 -      closeAll_actionPerformed(null);
 -
        if (groovyConsole != null)
        {
          // suppress a possible repeat prompt to save script
      }
    }
  
 +  public int structureViewersStillRunningCount()
 +  {
 +    int count = 0;
 +    JInternalFrame[] frames = desktop.getAllFrames();
 +    for (int i = 0; i < frames.length; i++)
 +    {
 +      if (frames[i] != null
 +              && frames[i] instanceof JalviewStructureDisplayI)
 +      {
 +        if (((JalviewStructureDisplayI) frames[i]).stillRunning())
 +          count++;
 +      }
 +    }
 +    return count;
 +  }
 +
    @Override
    public void raiseRelated_actionPerformed(ActionEvent e)
    {
    /**
     * 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
@@@ -7,7 -7,6 +7,7 @@@ import java.util.concurrent.Completable
  import java.util.concurrent.ExecutionException;
  import java.util.concurrent.ExecutorService;
  import java.util.concurrent.Executors;
 +import java.util.concurrent.RejectedExecutionException;
  import java.util.concurrent.TimeUnit;
  import java.util.concurrent.TimeoutException;
  
@@@ -41,6 -40,18 +41,18 @@@ public class QuitHandle
      NULL, QUIT, CANCEL_QUIT, FORCE_QUIT
    };
  
+   public static enum Message
+   {
+     UNSAVED_CHANGES, UNSAVED_ALIGNMENTS
+   };
+   protected static Message message = Message.UNSAVED_CHANGES;
+   public static void setMessage(Message m)
+   {
+     message = m;
+   }
    private static ExecutorService executor = Executors.newFixedThreadPool(3);
  
    public static QResponse setQuitHandler()
  
      if (confirmQuit)
      {
+       String messageString = MessageManager
+               .getString(message == Message.UNSAVED_ALIGNMENTS
+                       ? "label.unsaved_alignments"
+                       : "label.unsaved_changes");
 -      JvOptionPane.newOptionDialog()
 +      setQuitDialog(JvOptionPane.newOptionDialog()
                .setResponseHandler(JOptionPane.YES_OPTION, defaultOkQuit)
 -              .setResponseHandler(JOptionPane.NO_OPTION, cancelQuit)
 -              .showDialogOnTopAsync(
 -                      new StringBuilder(MessageManager
 -                              .getString("label.quit_jalview")).append("\n")
 -                              .append(messageString).toString(),
 -                      MessageManager.getString("action.quit"),
 -                      JOptionPane.YES_NO_OPTION,
 -                      JOptionPane.QUESTION_MESSAGE, null, new Object[]
 -                      { MessageManager.getString("action.quit"),
 -                          MessageManager.getString("action.cancel") },
 -                      MessageManager.getString("action.quit"), true);
 +              .setResponseHandler(JOptionPane.NO_OPTION, cancelQuit));
 +      JvOptionPane qd = getQuitDialog();
 +      qd.showDialogOnTopAsync(
 +              new StringBuilder(
 +                      MessageManager.getString("label.quit_jalview"))
-                       .append("\n")
-                       .append(MessageManager
-                               .getString("label.unsaved_changes"))
-                       .toString(),
++                      .append("\n").append(messageString).toString(),
 +              MessageManager.getString("action.quit"),
 +              JOptionPane.YES_NO_OPTION, JOptionPane.QUESTION_MESSAGE, null,
 +              new Object[]
 +              { MessageManager.getString("action.quit"),
 +                  MessageManager.getString("action.cancel") },
 +              MessageManager.getString("action.quit"), true);
      }
  
      got = gotQuitResponse();
 +
 +    // check for external viewer frames
 +    if (got != QResponse.CANCEL_QUIT)
 +    {
 +      int count = Desktop.instance.structureViewersStillRunningCount();
 +      if (count > 0)
 +      {
 +        String prompt = MessageManager
 +                .formatMessage(count == 1 ? "label.confirm_quit_viewer"
 +                        : "label.confirm_quit_viewers");
 +        String title = MessageManager.getString(
 +                count == 1 ? "label.close_viewer" : "label.close_viewers");
 +        String cancelQuitText = MessageManager
 +                .getString("action.cancel_quit");
 +        String[] buttonsText = { MessageManager.getString("action.yes"),
 +            MessageManager.getString("action.no"), cancelQuitText };
 +
 +        int confirmResponse = JvOptionPane.showOptionDialog(
 +                Desktop.instance, prompt, title,
 +                JvOptionPane.YES_NO_CANCEL_OPTION,
 +                JvOptionPane.WARNING_MESSAGE, null, buttonsText,
 +                cancelQuit);
 +
 +        if (confirmResponse == JvOptionPane.CANCEL_OPTION)
 +        {
 +          // Cancel Quit
 +          QuitHandler.setResponse(QResponse.CANCEL_QUIT);
 +        }
 +        else
 +        {
 +          // Close viewers/Leave viewers open
 +          StructureViewerBase
 +                  .setQuitClose(confirmResponse == JvOptionPane.YES_OPTION);
 +        }
 +      }
 +
 +    }
 +
 +    got = gotQuitResponse();
 +
      boolean wait = false;
      if (got == QResponse.CANCEL_QUIT)
      {
      {
        executor.submit(next).get();
        got = gotQuitResponse();
 +    } catch (RejectedExecutionException e)
 +    {
 +      // QuitHander.abortQuit() probably called
 +      // CANCEL_QUIT test will reset QuitHandler
 +      Console.info("Quit aborted!");
 +      got = QResponse.NULL;
 +      setResponse(QResponse.NULL);
      } catch (InterruptedException | ExecutionException e)
      {
        jalview.bin.Console
      }
      setResponse(got);
  
 -    if (gotQuitResponse() == QResponse.CANCEL_QUIT)
 +    if (quitCancelled())
      {
        // reset if cancelled
 +      Console.debug("Quit cancelled");
        setResponse(QResponse.NULL);
        return QResponse.CANCEL_QUIT;
      }
              }
              else
              {
 -              if (!(QuitHandler.gotQuitResponse() == QResponse.CANCEL_QUIT
 -                      || QuitHandler.gotQuitResponse() == QResponse.NULL))
 +              if (!(quitCancelled()))
                {
                  for (int i = 0; i < buttons.length; i++)
                  {
  
    public static void abortQuit()
    {
 -    setResponse(QResponse.CANCEL_QUIT);
 +    setResponse(QResponse.NULL);
 +    // executor.shutdownNow();
 +  }
 +
 +  private static JvOptionPane quitDialog = null;
 +
 +  private static void setQuitDialog(JvOptionPane qd)
 +  {
 +    quitDialog = qd;
 +  }
 +
 +  private static JvOptionPane getQuitDialog()
 +  {
 +    return quitDialog;
 +  }
 +
 +  public static boolean quitCancelled()
 +  {
 +    return QuitHandler.gotQuitResponse() == QResponse.CANCEL_QUIT
 +            || QuitHandler.gotQuitResponse() == QResponse.NULL;
 +  }
 +
 +  public static boolean quitting()
 +  {
 +    return QuitHandler.gotQuitResponse() == QResponse.QUIT
 +            || QuitHandler.gotQuitResponse() == QResponse.FORCE_QUIT;
    }
--}
++}
@@@ -50,7 -50,6 +50,7 @@@ import jalview.datamodel.AlignmentI
  import jalview.datamodel.AlignmentView;
  import jalview.datamodel.Annotation;
  import jalview.datamodel.ColumnSelection;
 +import jalview.datamodel.ContactListI;
  import jalview.datamodel.HiddenColumns;
  import jalview.datamodel.HiddenSequences;
  import jalview.datamodel.ProfilesI;
@@@ -59,6 -58,7 +59,7 @@@ import jalview.datamodel.Sequence
  import jalview.datamodel.SequenceCollectionI;
  import jalview.datamodel.SequenceGroup;
  import jalview.datamodel.SequenceI;
+ import jalview.gui.QuitHandler;
  import jalview.project.Jalview2XML;
  import jalview.renderer.ResidueShader;
  import jalview.renderer.ResidueShaderI;
@@@ -2941,12 -2941,6 +2942,12 @@@ public abstract class AlignmentViewpor
      return searchResults;
    }
  
 +  @Override
 +  public ContactListI getContactList(AlignmentAnnotation _aa, int column)
 +  {
 +    return alignment.getContactListFor(_aa, column);
 +  }
 +
    /**
     * get the consensus sequence as displayed under the PID consensus annotation
     * row.
  
    public void setSavedUpToDate(boolean s)
    {
+     setSavedUpToDate(s, QuitHandler.Message.UNSAVED_CHANGES);
+   }
+   public void setSavedUpToDate(boolean s, QuitHandler.Message m)
+   {
      Console.debug(
              "Setting " + this.getViewId() + " setSavedUpToDate to " + s);
      savedUpToDate = s;
+     QuitHandler.setMessage(m);
    }
  
    public boolean savedUpToDate()