Merge branch 'bug/JAL-3628_Unable_to_save_update_to_existing_file_in_Windows' into...
authorBen Soares <b.soares@dundee.ac.uk>
Tue, 7 Jul 2020 19:39:04 +0000 (20:39 +0100)
committerBen Soares <b.soares@dundee.ac.uk>
Tue, 7 Jul 2020 19:39:04 +0000 (20:39 +0100)
resources/lang/Messages.properties
resources/lang/Messages_es.properties
src/jalview/bin/Cache.java
src/jalview/gui/AlignFrame.java
src/jalview/gui/Console.java
src/jalview/io/BackupFiles.java
src/jalview/io/BackupFilesPresetEntry.java
src/jalview/ws/sifts/SiftsClient.java

index a4b24ed..7f13528 100644 (file)
@@ -377,7 +377,7 @@ label.example = Example
 label.example_param = Example: {0}
 label.select_file_format_before_saving = You must select a file format before saving!
 label.file_format_not_specified = File format not specified
-label.couldnt_save_file = Couldn't save file: {0}
+label.couldnt_save_file = Couldn''t save file: {0}
 label.error_saving_file = Error Saving File
 label.remove_from_default_list = Remove from default list?
 label.remove_user_defined_colour = Remove user defined colour
@@ -406,11 +406,11 @@ label.pdb_entries_couldnt_be_retrieved = The following pdb entries could not be
 label.couldnt_load_file = Couldn't load file
 label.couldnt_find_pdb_id_in_file = Couldn't find a PDB id in the file supplied. Please enter an Id to identify this structure.
 label.no_pdb_id_in_file = No PDB Id in File
-label.couldnt_read_pasted_text = Couldn't read the pasted text {0}
+label.couldnt_read_pasted_text = Couldn''t read the pasted text {0}
 label.error_parsing_text = Error parsing text
 label.input_alignment_from_url = Input Alignment From URL
 label.input_alignment = Input Alignment
-label.couldnt_import_as_vamsas_session = Couldn't import {0} as a new vamsas session.
+label.couldnt_import_as_vamsas_session = Couldn''t import {0} as a new vamsas session.
 label.vamsas_document_import_failed = Vamsas Document Import Failed
 label.couldnt_locate = Could not locate {0}
 label.url_not_found = URL not found
@@ -855,7 +855,7 @@ label.invalid_name = Invalid name
 label.set_proxy_settings = Please set up your proxy settings in the 'Connections' tab of the Preferences window
 label.proxy_authorization_failed = Proxy Authorization Failed
 label.internal_jalview_error = Internal Jalview Error
-label.secondary_structure_prediction_service_couldnt_be_located = The Secondary Structure Prediction Service named {0} at {1} couldn't be located.
+label.secondary_structure_prediction_service_couldnt_be_located = The Secondary Structure Prediction Service named {0} at {1} couldn''t be located.
 label.service_called_is_not_msa_service = The Service called \n{0}\nis not a \nMultiple Sequence Alignment Service\!
 label.msa_service_is_unknown = The Multiple Sequence Alignment Service named {0} is unknown
 label.service_called_is_not_seq_search_service = The Service called \n{0}\nis not a \nSequence Search Service\!
@@ -985,7 +985,7 @@ error.cannot_set_arguments_to_jabaws_param_set = Cannot set arguments to a JabaW
 error.implementation_error_runner_config_not_available = Implementation Error: Runner Config not available for a JABAWS service of type {0} ({1})
 error.implementation_error_cannot_handle_jaba_param = Implementation Error: Cannot handle Jaba parameter object {0}
 error.implementation_error_attempt_to_delete_service_preset = Implementation error: Attempt to delete a service preset!
-error.implementation_error_cannot_locate_oldname_presetname = Implementation error: Can't locate either oldname ({0}) or presetName ({1}in the datastore!"
+error.implementation_error_cannot_locate_oldname_presetname = Implementation error: Can''t locate either oldname ({0}) or presetName ({1}in the datastore!"
 error.implementation_error_jabaws_param_set_only_handled_by = Implementation error: JabaWsParamSets can only be handled by JabaParamStore
 error.cannot_set_source_file_for = Cannot set source file for {0}
 error.mismatch_service_instance_preset = Probable mismatch between service instance and preset!
@@ -993,7 +993,7 @@ error.cannot_set_params_for_ws_preset = Cannot set Parameters for a Jaba Web ser
 error.implementation_error_can_only_instantiate_jaba_param_sets = Implementation error: Can only instantiate Jaba parameter sets
 error.no_aacon_service_found = No AACon service found
 error.implementation_error_couldnt_copy_value_constraint = Implementation error: could not copy ValueConstrain!
-error.couldnt_encode_as_utf8 = Couldn't encode {0} as UTF-8.
+error.couldnt_encode_as_utf8 = Couldn''t encode {0} as UTF-8.
 error.tree_inputtype_not_yet_implemented = Tree InputType not yet implemented
 error.implementation_error_need_to_have_httpresponse = Implementation Error: need to have an HttpResponse to process
 error.dbrefsource_implementation_exception =DBRefSource Implementation Exception
@@ -1049,18 +1049,18 @@ error.implementation_error_reset_called_for_invalid_source = Implementation Erro
 exception.number_of_residues_in_query_sequence_differ_from_prediction = Number of residues in {0} supposed query sequence ({1}\n{2})\ndiffer from number of prediction sites in prediction ({3})
 label.mapped = mapped
 exception.jpredconcide_entry_has_unexpected_number_of_columns = JPredConcise: Entry ({0}) has an unexpected number of columns
-exception.couldnt_parse_concise_annotation_for_prediction = Couldn't parse concise annotation for prediction profile.\n{0}
+exception.couldnt_parse_concise_annotation_for_prediction = Couldn''t parse concise annotation for prediction profile.\n{0}
 exception.newfile = NewickFile\: {0}\n
 label.no_tree_read_in = No Tree read in
-exception.rnaml_couldnt_access_datasource = Couldn't access datasource ({0})
-exception.ranml_couldnt_process_data = Couldn't process data as RNAML file ({0})
+exception.rnaml_couldnt_access_datasource = Couldn''t access datasource ({0})
+exception.ranml_couldnt_process_data = Couldn''t process data as RNAML file ({0})
 exception.ranml_invalid_file = Invalid RNAML file ({0})
 exception.ranml_problem_parsing_data = Problem parsing data as RNAML ({0})
 exception.pfam_no_sequences_found = No sequences found (PFAM input)
 exception.stockholm_invalid_format = This file is not in valid STOCKHOLM format: First line does not contain '# STOCKHOLM'
 exception.couldnt_parse_sequence_line = Could not parse sequence line: {0}
 exception.unknown_annotation_detected = Unknown annotation detected: {0} {1}
-exception.couldnt_store_sequence_mappings = Couldn't store sequence mappings for {0}
+exception.couldnt_store_sequence_mappings = Couldn''t store sequence mappings for {0}
 exception.matrix_too_many_iteration = Too many iterations in {0} (max is {1})
 exception.browser_not_found = Exception in finding browser: {0}
 exception.browser_unable_to_locate = Unable to locate browser: {0}
@@ -1094,7 +1094,7 @@ warn.service_not_supported = Service not supported!
 warn.input_is_too_big = Input is too big!
 warn.invalid_job_param_set = Invalid job parameter set!
 warn.oneseq_msainput_selection = The current selection only contains a single sequence. Do you want to submit all sequences for alignment instead ?   
-info.job_couldnt_be_run_server_doesnt_support_program = Job could not be run because the server doesn't support this program.\n{0}
+info.job_couldnt_be_run_server_doesnt_support_program = Job could not be run because the server doesn''t support this program.\n{0}
 info.job_couldnt_be_run_exceeded_hard_limit = Job could not be run because it exceeded a hard limit on the server.\n{0}
 info.job_couldnt_be_run_incorrect_param_setting = Job could not be run because some of the parameter settings are not supported by the server.\n{0}\nPlease check to make sure you have used the correct parameter set for this service\!\n
 info.no_jobs_ran = No jobs ran
@@ -1346,6 +1346,7 @@ label.backupfiles_confirm_save_file = Confirm save file
 label.backupfiles_confirm_save_file_backupfiles_roll_wrong = Something possibly went wrong with the backups of this file.
 label.backupfiles_confirm_save_new_saved_file_ok = The new saved file seems okay.
 label.backupfiles_confirm_save_new_saved_file_not_ok = The new saved file might not be okay.
+label.continue_operation = Continue operation?
 label.backups = Backups
 label.backup = Backup
 label.backup_files = Backup Files
@@ -1412,3 +1413,7 @@ 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
 label.no_features_to_sort_by = No features to sort by
+label.log_level = Log level
+label.log_level_tooltip = Temporarily set the log level for this console
+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
index 4e0fb1f..707f1ba 100644 (file)
@@ -1341,6 +1341,7 @@ label.backupfiles_confirm_save_file = Confirmar guardar archivo
 label.backupfiles_confirm_save_file_backupfiles_roll_wrong = Posiblemente algo está mal con los archivos de respaldos.
 label.backupfiles_confirm_save_new_saved_file_ok = El nuevo archivo guardado parece estar bien.
 label.backupfiles_confirm_save_new_saved_file_not_ok = El nuevo archivo guardado podría no estar bien.
+label.continue_operation = ¿Continuar operación?
 label.backups = Respaldos
 label.backup = Respaldo
 label.backup_files = Archivos de respaldos
@@ -1407,3 +1408,7 @@ label.include_linked_features = Incluir caracter
 label.include_linked_tooltip = Incluir características de {0}<br>convertidas a coordenadas de secuencia local
 label.features_not_shown = {0} característica(s) no mostradas
 label.no_features_to_sort_by = No hay características para ordenar
+label.log_level = Nivel del registro
+label.log_level_tooltip = Establezca temporalmente el nivel de registro para esta consola
+label.copy_to_clipboard = Copiar en el portapapeles
+label.copy_to_clipboard_tooltip = Copie todo el texto de registro en esta consola al portapapeles del sistema
index 751461f..dbe85fe 100755 (executable)
@@ -27,6 +27,8 @@ import java.io.FileInputStream;
 import java.io.FileOutputStream;
 import java.io.InputStream;
 import java.io.InputStreamReader;
+import java.io.PrintWriter;
+import java.io.StringWriter;
 import java.text.DateFormat;
 import java.text.SimpleDateFormat;
 import java.util.Collections;
@@ -440,8 +442,7 @@ public class Cache
     String jnlpVersion = System.getProperty("jalview.version");
 
     // jnlpVersion will be null if a latest version check for the channel needs
-    // to
-    // be done
+    // to be done
     // Dont do this check if running in headless mode
 
     if (jnlpVersion == null && getDefault("VERSION_CHECK", true)
@@ -1126,11 +1127,15 @@ public class Cache
     appendIfNotNull(sb, "Launcher version: ",
             System.getProperty("launcher_version"), "\n", null);
     LookAndFeel laf = UIManager.getLookAndFeel();
-    String lafName = laf == null?"Not obtained":laf.getName();
-    String lafClass = laf == null?"unknown":laf.getClass().getName();
-    appendIfNotNull(sb, "LookAndFeel: ", lafName+" ("+lafClass+")", "\n", null);
-    // Not displayed in release version ( determined by possible version number regex 9[9.]*9[.-_a9]* )
-    if (Pattern.matches("^\\d[\\d\\.]*\\d[\\.\\-\\w]*$", jalview.bin.Cache.getDefault("VERSION", "TEST"))) {
+    String lafName = laf == null ? "Not obtained" : laf.getName();
+    String lafClass = laf == null ? "unknown" : laf.getClass().getName();
+    appendIfNotNull(sb, "LookAndFeel: ", lafName + " (" + lafClass + ")",
+            "\n", null);
+    // Not displayed in release version ( determined by possible version number
+    // regex 9[9.]*9[.-_a9]* )
+    if (Pattern.matches("^\\d[\\d\\.]*\\d[\\.\\-\\w]*$",
+            jalview.bin.Cache.getDefault("VERSION", "TEST")))
+    {
       appendIfNotNull(sb, "Getdown appdir: ",
               System.getProperty("getdownappdir"), "\n", null);
       appendIfNotNull(sb, "Java home: ", System.getProperty("java.home"),
@@ -1149,4 +1154,12 @@ public class Cache
     // eg 'built from Source' or update channel
     return jalview.bin.Cache.getDefault("INSTALLATION", "unknown");
   }
+
+  public static String getStackTraceString(Throwable t)
+  {
+    StringWriter sw = new StringWriter();
+    PrintWriter pw = new PrintWriter(sw);
+    t.printStackTrace(pw);
+    return sw.toString();
+  }
 }
index b7d8b3a..99580ae 100644 (file)
  */
 package jalview.gui;
 
+import java.awt.BorderLayout;
+import java.awt.Component;
+import java.awt.Rectangle;
+import java.awt.Toolkit;
+import java.awt.datatransfer.Clipboard;
+import java.awt.datatransfer.DataFlavor;
+import java.awt.datatransfer.StringSelection;
+import java.awt.datatransfer.Transferable;
+import java.awt.dnd.DnDConstants;
+import java.awt.dnd.DropTargetDragEvent;
+import java.awt.dnd.DropTargetDropEvent;
+import java.awt.dnd.DropTargetEvent;
+import java.awt.dnd.DropTargetListener;
+import java.awt.event.ActionEvent;
+import java.awt.event.ActionListener;
+import java.awt.event.FocusAdapter;
+import java.awt.event.FocusEvent;
+import java.awt.event.ItemEvent;
+import java.awt.event.ItemListener;
+import java.awt.event.KeyAdapter;
+import java.awt.event.KeyEvent;
+import java.awt.event.MouseEvent;
+import java.awt.print.PageFormat;
+import java.awt.print.PrinterJob;
+import java.beans.PropertyChangeEvent;
+import java.io.File;
+import java.io.FileWriter;
+import java.io.IOException;
+import java.io.PrintWriter;
+import java.net.URL;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Deque;
+import java.util.Enumeration;
+import java.util.Hashtable;
+import java.util.List;
+import java.util.Vector;
+
+import javax.swing.ButtonGroup;
+import javax.swing.JCheckBoxMenuItem;
+import javax.swing.JEditorPane;
+import javax.swing.JInternalFrame;
+import javax.swing.JLayeredPane;
+import javax.swing.JMenu;
+import javax.swing.JMenuItem;
+import javax.swing.JScrollPane;
+import javax.swing.SwingUtilities;
+
 import jalview.analysis.AlignmentSorter;
 import jalview.analysis.AlignmentUtils;
 import jalview.analysis.CrossRef;
@@ -91,6 +139,7 @@ import jalview.schemes.ColourSchemes;
 import jalview.schemes.ResidueColourScheme;
 import jalview.schemes.TCoffeeColourScheme;
 import jalview.util.MessageManager;
+import jalview.util.Platform;
 import jalview.viewmodel.AlignmentViewport;
 import jalview.viewmodel.ViewportRanges;
 import jalview.ws.DBRefFetcher;
@@ -100,53 +149,6 @@ import jalview.ws.jws2.Jws2Discoverer;
 import jalview.ws.jws2.jabaws2.Jws2Instance;
 import jalview.ws.seqfetcher.DbSourceProxy;
 
-import java.awt.BorderLayout;
-import java.awt.Component;
-import java.awt.Rectangle;
-import java.awt.Toolkit;
-import java.awt.datatransfer.Clipboard;
-import java.awt.datatransfer.DataFlavor;
-import java.awt.datatransfer.StringSelection;
-import java.awt.datatransfer.Transferable;
-import java.awt.dnd.DnDConstants;
-import java.awt.dnd.DropTargetDragEvent;
-import java.awt.dnd.DropTargetDropEvent;
-import java.awt.dnd.DropTargetEvent;
-import java.awt.dnd.DropTargetListener;
-import java.awt.event.ActionEvent;
-import java.awt.event.ActionListener;
-import java.awt.event.FocusAdapter;
-import java.awt.event.FocusEvent;
-import java.awt.event.ItemEvent;
-import java.awt.event.ItemListener;
-import java.awt.event.KeyAdapter;
-import java.awt.event.KeyEvent;
-import java.awt.event.MouseEvent;
-import java.awt.print.PageFormat;
-import java.awt.print.PrinterJob;
-import java.beans.PropertyChangeEvent;
-import java.io.File;
-import java.io.FileWriter;
-import java.io.PrintWriter;
-import java.net.URL;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.Deque;
-import java.util.Enumeration;
-import java.util.Hashtable;
-import java.util.List;
-import java.util.Vector;
-
-import javax.swing.ButtonGroup;
-import javax.swing.JCheckBoxMenuItem;
-import javax.swing.JEditorPane;
-import javax.swing.JInternalFrame;
-import javax.swing.JLayeredPane;
-import javax.swing.JMenu;
-import javax.swing.JMenuItem;
-import javax.swing.JScrollPane;
-import javax.swing.SwingUtilities;
-
 /**
  * DOCUMENT ME!
  * 
@@ -1168,7 +1170,7 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
 
       statusBar.setText(MessageManager.formatMessage(
               "label.successfully_saved_to_file_in_format", new Object[]
-              { fileName, format }));
+              { file, format }));
 
     }
     else
@@ -1197,39 +1199,66 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
       else
       {
         // create backupfiles object and get new temp filename destination
+        Cache.log.debug("ALIGNFRAME making backupfiles object for " + file);
         BackupFiles backupfiles = new BackupFiles(file);
 
         try
         {
-          PrintWriter out = new PrintWriter(
-                  new FileWriter(backupfiles.getTempFilePath()));
+          String tempFilePath = backupfiles.getTempFilePath();
+          Cache.log.debug(
+                  "ALIGNFRAME setting PrintWriter to " + tempFilePath);
+          PrintWriter out = new PrintWriter(new FileWriter(tempFilePath));
+
+          Cache.log.debug(
+                  "ALIGNFRAME about to write to temp file " + tempFilePath);
 
           out.print(output);
+          Cache.log.debug("ALIGNFRAME about to close file");
           out.close();
+          Cache.log.debug("ALIGNFRAME closed file");
           this.setTitle(file);
           statusBar.setText(MessageManager.formatMessage(
                   "label.successfully_saved_to_file_in_format", new Object[]
-                  { fileName, format.getName() }));
+                  { file, format.getName() }));
+        } catch (IOException e)
+        {
+          success = false;
+          Cache.log.error(
+                  "ALIGNFRAME Something happened writing the temp file");
+          Cache.log.error(e.getMessage());
+          Cache.log.debug(Cache.getStackTraceString(e));
+
         } catch (Exception ex)
         {
           success = false;
-          ex.printStackTrace();
+          Cache.log.error(
+                  "ALIGNFRAME Something else happened writing the temp file");
+          Cache.log.error(ex.getMessage());
+          Cache.log.debug(Cache.getStackTraceString(ex));
         }
 
         backupfiles.setWriteSuccess(success);
+        Cache.log.debug("ALIGNFRAME writing temp file was "
+                + (success ? "" : "NOT ") + "successful");
         // do the backup file roll and rename the temp file to actual file
+        Cache.log.debug("ALIGNFRAME about to rollBackupsAndRenameTempFile");
         success = backupfiles.rollBackupsAndRenameTempFile();
+        Cache.log.debug("ALIGNFRAME performed rollBackupsAndRenameTempFile "
+                + (success ? "" : "un") + "successfully");
 
       }
     }
 
     if (!success)
     {
-      JvOptionPane.showInternalMessageDialog(this, MessageManager
-              .formatMessage("label.couldnt_save_file", new Object[]
-              { fileName }),
-              MessageManager.getString("label.error_saving_file"),
-              JvOptionPane.WARNING_MESSAGE);
+      if (!Platform.isHeadless())
+      {
+        JvOptionPane.showInternalMessageDialog(this, MessageManager
+                .formatMessage("label.couldnt_save_file", new Object[]
+                { file }),
+                MessageManager.getString("label.error_saving_file"),
+                JvOptionPane.WARNING_MESSAGE);
+      }
     }
 
     return success;
@@ -2736,8 +2765,8 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
 
     if (viewport.getViewName() == null)
     {
-      viewport.setViewName(MessageManager
-              .getString("label.view_name_original"));
+      viewport.setViewName(
+              MessageManager.getString("label.view_name_original"));
     }
 
     /*
@@ -3366,8 +3395,8 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
      * otherwise set the chosen colour scheme (or null for 'None')
      */
     ColourSchemeI cs = ColourSchemes.getInstance().getColourScheme(name,
-            viewport,
-            viewport.getAlignment(), viewport.getHiddenRepSequences());
+            viewport, viewport.getAlignment(),
+            viewport.getHiddenRepSequences());
     changeColour(cs);
   }
 
@@ -5694,6 +5723,7 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
   }
 
   private Rectangle lastFeatureSettingsBounds = null;
+
   @Override
   public void setFeatureSettingsGeometry(Rectangle bounds)
   {
index 4c019a6..a493640 100644 (file)
  */
 package jalview.gui;
 
-import jalview.util.MessageManager;
-
 import java.awt.BorderLayout;
+import java.awt.Color;
 import java.awt.Dimension;
 import java.awt.GraphicsEnvironment;
+import java.awt.GridBagConstraints;
+import java.awt.GridBagLayout;
 import java.awt.Rectangle;
 import java.awt.Toolkit;
+import java.awt.datatransfer.Clipboard;
+import java.awt.datatransfer.StringSelection;
 import java.awt.event.ActionEvent;
 import java.awt.event.ActionListener;
+import java.awt.event.MouseAdapter;
+import java.awt.event.MouseEvent;
 import java.awt.event.WindowAdapter;
 import java.awt.event.WindowEvent;
 import java.awt.event.WindowListener;
@@ -38,12 +43,19 @@ import java.io.PipedOutputStream;
 import java.io.PrintStream;
 
 import javax.swing.JButton;
+import javax.swing.JComboBox;
 import javax.swing.JFrame;
+import javax.swing.JLabel;
+import javax.swing.JPanel;
 import javax.swing.JScrollPane;
 import javax.swing.JTextArea;
 
+import org.apache.log4j.Level;
 import org.apache.log4j.SimpleLayout;
 
+import jalview.bin.Cache;
+import jalview.util.MessageManager;
+
 /**
  * Simple Jalview Java Console. Version 1 - allows viewing of console output
  * after desktop is created. Acquired with thanks from RJHM's site
@@ -88,6 +100,8 @@ public class Console extends WindowAdapter
 
   private int MIN_HEIGHT = 250;
 
+  private JComboBox logLevelCombo = new JComboBox();
+
   public Console()
   {
     // create all components and add them
@@ -115,17 +129,104 @@ public class Console extends WindowAdapter
     // textArea = cpt.getTextArea();
     textArea = new JTextArea();
     textArea.setEditable(false);
-    JButton button = new JButton(MessageManager.getString("action.clear"));
+    JButton clearButton = new JButton(
+            MessageManager.getString("action.clear"));
+    JButton copyToClipboardButton = new JButton(
+            MessageManager.getString("label.copy_to_clipboard"));
+    copyToClipboardButton.addActionListener(new ActionListener()
+    {
+      public void actionPerformed(ActionEvent e)
+      {
+        copyConsoleTextToClipboard();
+      }
+    });
+    copyToClipboardButton.addMouseListener(new MouseAdapter()
+    {
+      private Color bg = textArea.getBackground();
+
+      private Color fg = textArea.getForeground();
+
+      public void mousePressed(MouseEvent e)
+      {
+        textArea.setBackground(textArea.getSelectionColor());
+        textArea.setForeground(textArea.getSelectedTextColor());
+      }
+
+      public void mouseReleased(MouseEvent e)
+      {
+        textArea.setBackground(bg);
+        textArea.setForeground(fg);
+      }
+
+    });
+    copyToClipboardButton.setToolTipText(
+            MessageManager.getString("label.copy_to_clipboard_tooltip"));
+
+    JLabel logLevelLabel = new JLabel(
+            MessageManager.getString("label.log_level") + ":");
+
+    // logLevelCombo.addItem(Level.ALL);
+    logLevelCombo.addItem(Level.TRACE);
+    logLevelCombo.addItem(Level.DEBUG);
+    logLevelCombo.addItem(Level.INFO);
+    logLevelCombo.addItem(Level.WARN);
+    // logLevelCombo.addItem(Level.ERROR);
+    // logLevelCombo.addItem(Level.FATAL);
+    // logLevelCombo.addItem(Level.OFF);
+    setChosenLogLevelCombo();
+    logLevelCombo.addActionListener(new ActionListener()
+    {
+      public void actionPerformed(ActionEvent e)
+      {
+        if (Cache.log != null)
+        {
+          Cache.log.setLevel((Level) logLevelCombo.getSelectedItem());
+        }
+      }
+
+    });
 
     // frame = cpt;
     frame.getContentPane().setLayout(new BorderLayout());
     frame.getContentPane().add(new JScrollPane(textArea),
             BorderLayout.CENTER);
-    frame.getContentPane().add(button, BorderLayout.SOUTH);
+    JPanel southPanel = new JPanel();
+    southPanel.setLayout(new GridBagLayout());
+
+    JPanel logLevelPanel = new JPanel();
+    logLevelPanel.setAlignmentX(JPanel.LEFT_ALIGNMENT);
+    logLevelPanel.add(logLevelLabel);
+    logLevelPanel.add(logLevelCombo);
+    logLevelLabel.setToolTipText(
+            MessageManager.getString("label.log_level_tooltip"));
+    logLevelCombo.setToolTipText(
+            MessageManager.getString("label.log_level_tooltip"));
+
+    GridBagConstraints gbc = new GridBagConstraints();
+    gbc.gridx = 0;
+    gbc.gridy = 0;
+    gbc.gridwidth = 1;
+    gbc.gridheight = 1;
+    gbc.weightx = 0.1;
+    southPanel.add(logLevelPanel, gbc);
+
+    gbc.gridx++;
+    gbc.weightx = 0.8;
+    gbc.fill = GridBagConstraints.HORIZONTAL;
+    southPanel.add(clearButton, gbc);
+
+    gbc.gridx++;
+    gbc.weightx = 0.1;
+    gbc.fill = GridBagConstraints.NONE;
+    southPanel.add(copyToClipboardButton, gbc);
+
+    southPanel.setVisible(true);
+    frame.getContentPane().add(southPanel, BorderLayout.SOUTH);
     frame.setVisible(visible);
     updateConsole = visible;
     frame.addWindowListener(this);
-    button.addActionListener(this);
+    clearButton.addActionListener(this);
+
     if (redirect)
     {
       redirectStreams();
@@ -151,6 +252,50 @@ public class Console extends WindowAdapter
     textAppender.start();
   }
 
+  private void setChosenLogLevelCombo()
+  {
+    Level currentLogLevel = Cache.log == null ? Level.INFO
+            : Cache.log.getLevel();
+    logLevelCombo.setSelectedItem(currentLogLevel);
+    if (!logLevelCombo.getSelectedItem().equals(currentLogLevel)) // currentLogLevel
+                                                                  // not in list
+    {
+      if (currentLogLevel != null && currentLogLevel instanceof Level)
+      {
+        // add new item to list (might be set via .jalview_properties)
+        boolean added = false;
+        for (int i = 0; i < logLevelCombo.getItemCount(); i++)
+        {
+          Level l = (Level) logLevelCombo.getItemAt(i);
+          if (l.isGreaterOrEqual(currentLogLevel))
+          {
+            logLevelCombo.insertItemAt(currentLogLevel, i);
+            added = true;
+            break;
+          }
+        }
+        if (!added) // lower priority than others or some confusion -- add to
+                    // end of list
+        {
+          logLevelCombo.addItem(currentLogLevel);
+        }
+        logLevelCombo.setSelectedItem(currentLogLevel);
+      }
+      else
+      {
+        logLevelCombo.setSelectedItem(Level.INFO);
+      }
+    }
+  }
+
+  private void copyConsoleTextToClipboard()
+  {
+    String consoleText = textArea.getText();
+    StringSelection consoleTextSelection = new StringSelection(consoleText);
+    Clipboard cb = Toolkit.getDefaultToolkit().getSystemClipboard();
+    cb.setContents(consoleTextSelection, null);
+  }
+
   PipedOutputStream pout = null, perr = null;
 
   public void redirectStreams()
@@ -644,12 +789,21 @@ public class Console extends WindowAdapter
     frame.setVisible(selected);
     if (selected == true)
     {
+      setChosenLogLevelCombo();
       redirectStreams();
       updateConsole = true;
       frame.toFront();
     }
     else
     {
+      // reset log level to user preference
+      if (Cache.log != null)
+      {
+        String userLogLevel = Cache.getDefault("logs.Jalview.level",
+                Level.INFO.toString());
+        Cache.log.setLevel(Level.toLevel(userLogLevel));
+      }
+
       unredirectStreams();
       updateConsole = false;
     }
index 0150579..e943b23 100644 (file)
  */
 package jalview.io;
 
-import jalview.bin.Cache;
-import jalview.gui.Desktop;
-import jalview.gui.JvOptionPane;
-import jalview.util.MessageManager;
-
 import java.io.File;
 import java.io.IOException;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.nio.file.StandardCopyOption;
 import java.text.SimpleDateFormat;
 import java.util.ArrayList;
 import java.util.HashMap;
 import java.util.Map;
 import java.util.TreeMap;
 
+import jalview.bin.Cache;
+import jalview.gui.Desktop;
+import jalview.gui.JvOptionPane;
+import jalview.util.MessageManager;
+import jalview.util.Platform;
+
 /*
  * BackupFiles used for manipulating (naming rolling/deleting) backup/version files when an alignment or project file is saved.
  * User configurable options are:
@@ -95,6 +100,10 @@ public class BackupFiles
   private static final SimpleDateFormat sdf = new SimpleDateFormat(
           "yyyy-MM-dd HH:mm:ss");
 
+  private static final String newTempFileSuffix = "_newfile";
+
+  private static final String oldTempFileSuffix = "_oldfile_tobedeleted";
+
   public BackupFiles(String filename)
   {
     this(new File(filename));
@@ -106,7 +115,8 @@ public class BackupFiles
   {
     classInit();
     this.file = file;
-    BackupFilesPresetEntry bfpe = BackupFilesPresetEntry.getSavedBackupEntry();
+    BackupFilesPresetEntry bfpe = BackupFilesPresetEntry
+            .getSavedBackupEntry();
     this.suffix = bfpe.suffix;
     this.noMax = bfpe.keepAll;
     this.max = bfpe.rollMax;
@@ -121,30 +131,47 @@ public class BackupFiles
       {
         String tempfilename = file.getName();
         File tempdir = file.getParentFile();
-        temp = File.createTempFile(tempfilename, TEMP_FILE_EXT + "_newfile",
-                tempdir);
+        Cache.log.debug(
+                "BACKUPFILES [file!=null] attempting to create temp file for "
+                        + tempfilename + " in dir " + tempdir);
+        temp = File.createTempFile(tempfilename,
+                TEMP_FILE_EXT + newTempFileSuffix, tempdir);
+        Cache.log.debug(
+                "BACKUPFILES using temp file " + temp.getAbsolutePath());
       }
       else
       {
+        Cache.log.debug(
+                "BACKUPFILES [file==null] attempting to create default temp file "
+                        + DEFAULT_TEMP_FILE + " with extension "
+                        + TEMP_FILE_EXT);
         temp = File.createTempFile(DEFAULT_TEMP_FILE, TEMP_FILE_EXT);
       }
     } catch (IOException e)
     {
-      System.out.println(
-              "Could not create temp file to save into (IOException)");
+      Cache.log
+              .error("Could not create temp file to save to (IOException)");
+      Cache.log.error(e.getMessage());
+      Cache.log.debug(Cache.getStackTraceString(e));
     } catch (Exception e)
     {
-      System.out.println("Exception ctreating temp file for saving");
+      Cache.log.error("Exception ctreating temp file for saving");
+      Cache.log.debug(Cache.getStackTraceString(e));
     }
     this.setTempFile(temp);
   }
 
   public static void classInit()
   {
-    setEnabled(Cache.getDefault(ENABLED, true));
+    Cache.log.debug("BACKUPFILES classInit");
+    boolean e = Cache.getDefault(ENABLED, true);
+    setEnabled(e);
+    Cache.log.debug("BACKUPFILES " + (e ? "enabled" : "disabled"));
     BackupFilesPresetEntry bfpe = BackupFilesPresetEntry
             .getSavedBackupEntry();
+    Cache.log.debug("BACKUPFILES preset scheme " + bfpe.toString());
     setConfirmDelete(bfpe.confirmDelete);
+    Cache.log.debug("BACKUPFILES confirm delete " + bfpe.confirmDelete);
   }
 
   public static void setEnabled(boolean flag)
@@ -188,9 +215,10 @@ public class BackupFiles
       path = this.getTempFile().getCanonicalPath();
     } catch (IOException e)
     {
-      System.out.println(
+      Cache.log.error(
               "IOException when getting Canonical Path of temp file '"
                       + this.getTempFile().getName() + "'");
+      Cache.log.debug(Cache.getStackTraceString(e));
     }
     return path;
   }
@@ -209,7 +237,7 @@ public class BackupFiles
 
   public boolean renameTempFile()
   {
-    return tempFile.renameTo(file);
+    return moveFileToFile(tempFile, file);
   }
 
   // roll the backupfiles
@@ -226,24 +254,35 @@ public class BackupFiles
             || suffix.length() == 0)
     {
       // nothing to do
+      Cache.log.debug("BACKUPFILES rollBackupFiles nothing to do." + ", "
+              + "filename: " + (file != null ? file.getName() : "null")
+              + ", " + "file exists: " + file.exists() + ", " + "enabled: "
+              + enabled + ", " + "max: " + max + ", " + "suffix: '" + suffix
+              + "'");
       return true;
     }
 
+    Cache.log.debug("BACKUPFILES rollBackupFiles starting");
+
     String dir = "";
     File dirFile;
     try
     {
       dirFile = file.getParentFile();
       dir = dirFile.getCanonicalPath();
+      Cache.log.debug("BACKUPFILES dir: " + dir);
     } catch (Exception e)
     {
-      System.out.println(
+      Cache.log.error(
               "Could not get canonical path for file '" + file + "'");
+      Cache.log.error(e.getMessage());
+      Cache.log.debug(Cache.getStackTraceString(e));
       return false;
     }
     String filename = file.getName();
     String basename = filename;
 
+    Cache.log.debug("BACKUPFILES filename is " + filename);
     boolean ret = true;
     // Create/move backups up one
 
@@ -255,9 +294,13 @@ public class BackupFiles
     File[] backupFiles = dirFile.listFiles(bff);
     int nextIndexNum = 0;
 
+    Cache.log
+            .debug("BACKUPFILES backupFiles.length: " + backupFiles.length);
     if (backupFiles.length == 0)
     {
       // No other backup files. Just need to move existing file to backupfile_1
+      Cache.log.debug(
+              "BACKUPFILES no existing backup files, setting index to 1");
       nextIndexNum = 1;
     }
     else
@@ -270,7 +313,7 @@ public class BackupFiles
       if (reverseOrder)
       {
         // backup style numbering
-
+        Cache.log.debug("BACKUPFILES rolling files in reverse order");
 
         int tempMax = noMax ? -1 : max;
         // noMax == true means no limits
@@ -287,7 +330,7 @@ public class BackupFiles
             tempMax = i;
           }
         }
-        
+
         File previousFile = null;
         File fileToBeDeleted = null;
         for (int n = tempMax; n > 0; n--)
@@ -302,6 +345,7 @@ public class BackupFiles
             // no "oldest" file to delete
             previousFile = backupfile_n;
             fileToBeDeleted = null;
+            Cache.log.debug("BACKUPFILES No oldest file to delete");
             continue;
           }
 
@@ -312,19 +356,23 @@ public class BackupFiles
             File replacementFile = backupfile_n;
             long fileToBeDeletedLMT = fileToBeDeleted.lastModified();
             long replacementFileLMT = replacementFile.lastModified();
+            Cache.log.debug("BACKUPFILES fileToBeDeleted is "
+                    + fileToBeDeleted.getAbsolutePath());
+            Cache.log.debug("BACKUPFILES replacementFile is "
+                    + backupfile_n.getAbsolutePath());
 
             try
             {
               File oldestTempFile = nextTempFile(fileToBeDeleted.getName(),
                       dirFile);
-              
+
               if (fileToBeDeletedLMT > replacementFileLMT)
               {
                 String fileToBeDeletedLMTString = sdf
                         .format(fileToBeDeletedLMT);
                 String replacementFileLMTString = sdf
                         .format(replacementFileLMT);
-                System.out.println("WARNING! I am set to delete backupfile "
+                Cache.log.warn("WARNING! I am set to delete backupfile "
                         + fileToBeDeleted.getName()
                         + " has modification time "
                         + fileToBeDeletedLMTString
@@ -335,6 +383,11 @@ public class BackupFiles
 
                 boolean delete = confirmNewerDeleteFile(fileToBeDeleted,
                         replacementFile, true);
+                Cache.log.debug("BACKUPFILES "
+                        + (delete ? "confirmed" : "not") + " deleting file "
+                        + fileToBeDeleted.getAbsolutePath()
+                        + " which is newer than "
+                        + replacementFile.getAbsolutePath());
 
                 if (delete)
                 {
@@ -343,21 +396,27 @@ public class BackupFiles
                 }
                 else
                 {
-                  fileToBeDeleted.renameTo(oldestTempFile);
+                  Cache.log.debug("BACKUPFILES moving "
+                          + fileToBeDeleted.getAbsolutePath() + " to "
+                          + oldestTempFile.getAbsolutePath());
+                  moveFileToFile(fileToBeDeleted, oldestTempFile);
                 }
               }
               else
               {
-                fileToBeDeleted.renameTo(oldestTempFile);
+                Cache.log.debug("BACKUPFILES going to move "
+                        + fileToBeDeleted.getAbsolutePath() + " to "
+                        + oldestTempFile.getAbsolutePath());
+                moveFileToFile(fileToBeDeleted, oldestTempFile);
                 addDeleteFile(oldestTempFile);
               }
 
             } catch (Exception e)
             {
-              System.out.println(
+              Cache.log.error(
                       "Error occurred, probably making new temp file for '"
                               + fileToBeDeleted.getName() + "'");
-              e.printStackTrace();
+              Cache.log.error(Cache.getStackTraceString(e));
             }
 
             // reset
@@ -372,7 +431,9 @@ public class BackupFiles
           {
             if (previousFile != null)
             {
-              ret = ret && backupfile_n.renameTo(previousFile);
+              // using boolean '&' instead of '&&' as don't want moveFileToFile
+              // attempt to be conditional (short-circuit)
+              ret = ret & moveFileToFile(backupfile_n, previousFile);
             }
           }
 
@@ -382,19 +443,37 @@ public class BackupFiles
         // index to use for the latest backup
         nextIndexNum = 1;
       }
-      else
+      else // not reverse numbering
       {
         // version style numbering (with earliest file deletion if max files
         // reached)
 
         bfTreeMap.values().toArray(backupFiles);
+        StringBuilder bfsb = new StringBuilder();
+        for (int i = 0; i < backupFiles.length; i++)
+        {
+          if (bfsb.length() > 0)
+          {
+            bfsb.append(", ");
+          }
+          bfsb.append(backupFiles[i].getName());
+        }
+        Cache.log.debug("BACKUPFILES backupFiles: " + bfsb.toString());
 
         // noMax == true means keep all backup files
         if ((!noMax) && bfTreeMap.size() >= max)
         {
+          Cache.log.debug("BACKUPFILES noMax: " + noMax + ", " + "max: "
+                  + max + ", " + "bfTreeMap.size(): " + bfTreeMap.size());
           // need to delete some files to keep number of backups to designated
-          // max
-          int numToDelete = bfTreeMap.size() - max + 1;
+          // max.
+          // Note that if the suffix is not numbered then do not delete any
+          // backup files later or we'll delete the new backup file (there can
+          // be only one).
+          int numToDelete = suffix.indexOf(NUM_PLACEHOLDER) > -1
+                  ? bfTreeMap.size() - max + 1
+                  : 0;
+          Cache.log.debug("BACKUPFILES numToDelete: " + numToDelete);
           // the "replacement" file is the latest backup file being kept (it's
           // not replacing though)
           File replacementFile = numToDelete < backupFiles.length
@@ -407,6 +486,9 @@ public class BackupFiles
             File fileToBeDeleted = backupFiles[i];
             boolean delete = true;
 
+            Cache.log.debug(
+                    "BACKUPFILES fileToBeDeleted: " + fileToBeDeleted);
+
             boolean newer = false;
             if (replacementFile != null)
             {
@@ -421,14 +503,13 @@ public class BackupFiles
                 String replacementFileLMTString = sdf
                         .format(replacementFileLMT);
 
-                System.out
-                        .println("WARNING! I am set to delete backupfile '"
-                                + fileToBeDeleted.getName()
-                                + "' has modification time "
+                Cache.log.warn("WARNING! I am set to delete backupfile '"
+                        + fileToBeDeleted.getName()
+                        + "' has modification time "
                         + fileToBeDeletedLMTString
-                                + " which is newer than the oldest backupfile being kept '"
+                        + " which is newer than the oldest backupfile being kept '"
                         + replacementFile.getName()
-                                + "' with modification time "
+                        + "' with modification time "
                         + replacementFileLMTString);
 
                 delete = confirmNewerDeleteFile(fileToBeDeleted,
@@ -437,17 +518,23 @@ public class BackupFiles
                 {
                   // User has confirmed delete -- no need to add it to the list
                   fileToBeDeleted.delete();
+                  Cache.log.debug("BACKUPFILES deleting fileToBeDeleted: "
+                          + fileToBeDeleted);
                   delete = false;
                 }
                 else
                 {
                   // keeping file, nothing to do!
+                  Cache.log.debug("BACKUPFILES keeping fileToBeDeleted: "
+                          + fileToBeDeleted);
                 }
               }
             }
             if (delete)
             {
               addDeleteFile(fileToBeDeleted);
+              Cache.log.debug("BACKUPFILES addDeleteFile(fileToBeDeleted): "
+                      + fileToBeDeleted);
             }
 
           }
@@ -462,10 +549,17 @@ public class BackupFiles
     String latestBackupFilename = dir + File.separatorChar
             + BackupFilenameParts.getBackupFilename(nextIndexNum, basename,
                     suffix, digits);
-    ret |= file.renameTo(new File(latestBackupFilename));
-
+    Cache.log.debug("BACKUPFILES Moving old file [" + file
+            + "] to latestBackupFilename [" + latestBackupFilename + "]");
+    // using boolean '&' instead of '&&' as don't want moveFileToFile attempt to
+    // be conditional (short-circuit)
+    ret = ret & moveFileToFile(file, new File(latestBackupFilename));
+    Cache.log.debug(
+            "BACKUPFILES moving " + file + " to " + latestBackupFilename
+                    + " was " + (ret ? "" : "NOT ") + "successful");
     if (tidyUp)
     {
+      Cache.log.debug("BACKUPFILES tidying up files");
       tidyUpFiles();
     }
 
@@ -521,7 +615,7 @@ public class BackupFiles
         saveFile = nextTempFile(ftbd.getName(), ftbd.getParentFile());
       } catch (Exception e)
       {
-        System.out.println(
+        Cache.log.error(
                 "Error when confirming to keep backup file newer than other backup files.");
         e.printStackTrace();
       }
@@ -529,19 +623,27 @@ public class BackupFiles
               "label.newerdelete_replacement_line", new String[]
               { ftbd.getName(), rf.getName(), ftbdLMT, rfLMT, ftbdSize,
                   rfSize }));
+      // "Backup file\n''{0}''\t(modified {2}, size {4})\nis to be deleted and
+      // replaced by apparently older file \n''{1}''\t(modified {3}, size
+      // {5}).""
       messageSB.append("\n\n");
       messageSB.append(MessageManager.formatMessage(
               "label.confirm_deletion_or_rename", new String[]
               { ftbd.getName(), saveFile.getName() }));
+      // "Confirm deletion of ''{0}'' or rename to ''{1}''?"
       String[] options = new String[] {
           MessageManager.getString("label.delete"),
           MessageManager.getString("label.rename") };
 
-      confirmButton = JvOptionPane.showOptionDialog(Desktop.desktop,
-              messageSB.toString(),
-              MessageManager.getString("label.backupfiles_confirm_delete"),
-              JvOptionPane.YES_NO_OPTION, JvOptionPane.WARNING_MESSAGE,
-              null, options, options[0]);
+      confirmButton = Platform.isHeadless() ? JvOptionPane.YES_OPTION
+              : JvOptionPane.showOptionDialog(Desktop.desktop,
+                      messageSB.toString(),
+                      MessageManager.getString(
+                              "label.backupfiles_confirm_delete"),
+                      // "Confirm delete"
+                      JvOptionPane.YES_NO_OPTION,
+                      JvOptionPane.WARNING_MESSAGE, null, options,
+                      options[0]);
     }
     else
     {
@@ -549,22 +651,29 @@ public class BackupFiles
               .formatMessage("label.newerdelete_line", new String[]
               { ftbd.getName(), rf.getName(), ftbdLMT, rfLMT, ftbdSize,
                   rfSize }));
+      // "Backup file\n''{0}''\t(modified {2}, size {4})\nis to be deleted but
+      // is newer than the oldest remaining backup file \n''{1}''\t(modified
+      // {3}, size {5})."
       messageSB.append("\n\n");
       messageSB.append(MessageManager
               .formatMessage("label.confirm_deletion", new String[]
               { ftbd.getName() }));
+      // "Confirm deletion of ''{0}''?"
       String[] options = new String[] {
           MessageManager.getString("label.delete"),
           MessageManager.getString("label.keep") };
 
-      confirmButton = JvOptionPane.showOptionDialog(Desktop.desktop,
-              messageSB.toString(),
-              MessageManager.getString("label.backupfiles_confirm_delete"),
-              JvOptionPane.YES_NO_OPTION, JvOptionPane.WARNING_MESSAGE,
-              null, options, options[0]);
+      confirmButton = Platform.isHeadless() ? JvOptionPane.YES_OPTION
+              : JvOptionPane.showOptionDialog(Desktop.desktop,
+                      messageSB.toString(),
+                      MessageManager.getString(
+                              "label.backupfiles_confirm_delete"),
+                      // "Confirm delete"
+                      JvOptionPane.YES_NO_OPTION,
+                      JvOptionPane.WARNING_MESSAGE, null, options,
+                      options[0]);
     }
 
-
     // return should be TRUE if file is to be deleted
     return (confirmButton == JvOptionPane.YES_OPTION);
   }
@@ -580,6 +689,8 @@ public class BackupFiles
         messageSB = new StringBuilder();
         messageSB.append(MessageManager
                 .getString("label.backupfiles_confirm_delete_old_files"));
+        // "Delete the following older backup files? (see the Backups tab in
+        // Preferences for more options)"
         for (int i = 0; i < deleteFiles.size(); i++)
         {
           File df = deleteFiles.get(i);
@@ -590,13 +701,17 @@ public class BackupFiles
                   new String[]
                   { sdf.format(df.lastModified()),
                       Long.toString(df.length()) }));
+          // "(modified {0}, size {1})"
         }
 
-        int confirmButton = JvOptionPane.showConfirmDialog(Desktop.desktop,
-                messageSB.toString(),
-                MessageManager
-                        .getString("label.backupfiles_confirm_delete"),
-                JvOptionPane.YES_NO_OPTION, JvOptionPane.WARNING_MESSAGE);
+        int confirmButton = Platform.isHeadless() ? JvOptionPane.YES_OPTION
+                : JvOptionPane.showConfirmDialog(Desktop.desktop,
+                        messageSB.toString(),
+                        MessageManager.getString(
+                                "label.backupfiles_confirm_delete"),
+                        // "Confirm delete"
+                        JvOptionPane.YES_NO_OPTION,
+                        JvOptionPane.WARNING_MESSAGE);
 
         doDelete = (confirmButton == JvOptionPane.YES_OPTION);
       }
@@ -610,8 +725,10 @@ public class BackupFiles
         for (int i = 0; i < deleteFiles.size(); i++)
         {
           File fileToDelete = deleteFiles.get(i);
+          Cache.log.debug(
+                  "BACKUPFILES deleting fileToDelete:" + fileToDelete);
           fileToDelete.delete();
-          System.out.println("DELETING '" + fileToDelete.getName() + "'");
+          Cache.log.warn("deleting '" + fileToDelete.getName() + "'");
         }
       }
 
@@ -621,8 +738,7 @@ public class BackupFiles
   }
 
   private TreeMap<Integer, File> sortBackupFilesAsTreeMap(
-          File[] backupFiles,
-          String basename)
+          File[] backupFiles, String basename)
   {
     // sort the backup files (based on integer found in the suffix) using a
     // precomputed Hashmap for speed
@@ -647,7 +763,7 @@ public class BackupFiles
     boolean rename = false;
     if (write)
     {
-      roll = this.rollBackupFiles(false);
+      roll = this.rollBackupFiles(false); // tidyUpFiles at the end
       rename = this.renameTempFile();
     }
 
@@ -661,7 +777,9 @@ public class BackupFiles
     if (!okay)
     {
       StringBuilder messageSB = new StringBuilder();
-      messageSB.append(MessageManager.getString( "label.backupfiles_confirm_save_file_backupfiles_roll_wrong"));
+      messageSB.append(MessageManager.getString(
+              "label.backupfiles_confirm_save_file_backupfiles_roll_wrong"));
+      // "Something possibly went wrong with the backups of this file."
       if (rename)
       {
         if (messageSB.length() > 0)
@@ -670,6 +788,7 @@ public class BackupFiles
         }
         messageSB.append(MessageManager.getString(
                 "label.backupfiles_confirm_save_new_saved_file_ok"));
+        // "The new saved file seems okay."
       }
       else
       {
@@ -679,13 +798,22 @@ public class BackupFiles
         }
         messageSB.append(MessageManager.getString(
                 "label.backupfiles_confirm_save_new_saved_file_not_ok"));
+        // "The new saved file might not be okay."
       }
-
-      int confirmButton = JvOptionPane.showConfirmDialog(Desktop.desktop,
-              messageSB.toString(),
-              MessageManager
-                      .getString("label.backupfiles_confirm_save_file"),
-              JvOptionPane.OK_OPTION, JvOptionPane.WARNING_MESSAGE);
+      if (messageSB.length() > 0)
+      {
+        messageSB.append("\n");
+      }
+      messageSB
+              .append(MessageManager.getString("label.continue_operation"));
+
+      int confirmButton = Platform.isHeadless() ? JvOptionPane.OK_OPTION
+              : JvOptionPane.showConfirmDialog(Desktop.desktop,
+                      messageSB.toString(),
+                      MessageManager.getString(
+                              "label.backupfiles_confirm_save_file"),
+                      // "Confirm save file"
+                      JvOptionPane.OK_OPTION, JvOptionPane.WARNING_MESSAGE);
       okay = confirmButton == JvOptionPane.OK_OPTION;
     }
     if (okay)
@@ -709,7 +837,7 @@ public class BackupFiles
       dirFile = file.getParentFile();
     } catch (Exception e)
     {
-      System.out.println(
+      Cache.log.error(
               "Could not get canonical path for file '" + file + "'");
       return new TreeMap<>();
     }
@@ -751,13 +879,48 @@ public class BackupFiles
     int pos = deleteFiles.indexOf(fileToBeDeleted);
     if (pos > -1)
     {
+      Cache.log.debug("BACKUPFILES not adding file "
+              + fileToBeDeleted.getAbsolutePath()
+              + " to the delete list (already at index" + pos + ")");
       return true;
     }
     else
     {
+      Cache.log.debug("BACKUPFILES adding file "
+              + fileToBeDeleted.getAbsolutePath() + " to the delete list");
       deleteFiles.add(fileToBeDeleted);
     }
     return ret;
   }
 
+  public static boolean moveFileToFile(File oldFile, File newFile)
+  {
+    boolean ret = false;
+    Path oldPath = Paths.get(oldFile.getAbsolutePath());
+    Path newPath = Paths.get(newFile.getAbsolutePath());
+    try
+    {
+      // delete destination file - not usually necessary but Just In Case...
+      Cache.log.debug("BACKUPFILES deleting " + newFile.getAbsolutePath());
+      newFile.delete();
+      Cache.log.debug("BACKUPFILES moving " + oldFile.getAbsolutePath()
+              + " to " + newFile.getAbsolutePath());
+      Files.move(oldPath, newPath, StandardCopyOption.REPLACE_EXISTING);
+      ret = true;
+      Cache.log.debug("BACKUPFILES move seems to have succeeded");
+    } catch (IOException e)
+    {
+      Cache.log.warn("Could not move file '" + oldPath.toString() + "' to '"
+              + newPath.toString() + "'");
+      Cache.log.error(e.getMessage());
+      Cache.log.debug(Cache.getStackTraceString(e));
+      ret = false;
+    } catch (Exception e)
+    {
+      Cache.log.error(e.getMessage());
+      Cache.log.debug(Cache.getStackTraceString(e));
+      ret = false;
+    }
+    return ret;
+  }
 }
index 69130d0..0734665 100644 (file)
  */
 package jalview.io;
 
-import jalview.bin.Cache;
-import jalview.util.MessageManager;
-
 import java.util.HashMap;
 import java.util.Map;
 import java.util.StringTokenizer;
 
+import jalview.bin.Cache;
+import jalview.util.MessageManager;
+
 public class BackupFilesPresetEntry
 {
 
@@ -135,6 +135,8 @@ public class BackupFilesPresetEntry
   {
     String savedPresetString = Cache
             .getDefault(BackupFilesPresetEntry.SAVEDCONFIG, null);
+    Cache.log.debug("BACKUPFILESPRESETENTRY saved preset string is "
+            + savedPresetString);
     BackupFilesPresetEntry savedPreset = BackupFilesPresetEntry
             .createBackupFilesPresetEntry(savedPresetString);
     if (savedPreset == null)
index b5f9653..9790f79 100644 (file)
  */
 package jalview.ws.sifts;
 
-import jalview.analysis.AlignSeq;
-import jalview.analysis.scoremodels.ScoreMatrix;
-import jalview.analysis.scoremodels.ScoreModels;
-import jalview.api.DBRefEntryI;
-import jalview.api.SiftsClientI;
-import jalview.datamodel.DBRefEntry;
-import jalview.datamodel.DBRefSource;
-import jalview.datamodel.SequenceI;
-import jalview.io.StructureFile;
-import jalview.schemes.ResidueProperties;
-import jalview.structure.StructureMapping;
-import jalview.util.Comparison;
-import jalview.util.DBRefUtils;
-import jalview.util.Format;
-import jalview.xml.binding.sifts.Entry;
-import jalview.xml.binding.sifts.Entry.Entity;
-import jalview.xml.binding.sifts.Entry.Entity.Segment;
-import jalview.xml.binding.sifts.Entry.Entity.Segment.ListMapRegion.MapRegion;
-import jalview.xml.binding.sifts.Entry.Entity.Segment.ListResidue.Residue;
-import jalview.xml.binding.sifts.Entry.Entity.Segment.ListResidue.Residue.CrossRefDb;
-import jalview.xml.binding.sifts.Entry.Entity.Segment.ListResidue.Residue.ResidueDetail;
-
 import java.io.File;
 import java.io.FileInputStream;
 import java.io.FileOutputStream;
@@ -73,6 +51,28 @@ import javax.xml.stream.XMLStreamReader;
 
 import MCview.Atom;
 import MCview.PDBChain;
+import jalview.analysis.AlignSeq;
+import jalview.analysis.scoremodels.ScoreMatrix;
+import jalview.analysis.scoremodels.ScoreModels;
+import jalview.api.DBRefEntryI;
+import jalview.api.SiftsClientI;
+import jalview.datamodel.DBRefEntry;
+import jalview.datamodel.DBRefSource;
+import jalview.datamodel.SequenceI;
+import jalview.io.BackupFiles;
+import jalview.io.StructureFile;
+import jalview.schemes.ResidueProperties;
+import jalview.structure.StructureMapping;
+import jalview.util.Comparison;
+import jalview.util.DBRefUtils;
+import jalview.util.Format;
+import jalview.xml.binding.sifts.Entry;
+import jalview.xml.binding.sifts.Entry.Entity;
+import jalview.xml.binding.sifts.Entry.Entity.Segment;
+import jalview.xml.binding.sifts.Entry.Entity.Segment.ListMapRegion.MapRegion;
+import jalview.xml.binding.sifts.Entry.Entity.Segment.ListResidue.Residue;
+import jalview.xml.binding.sifts.Entry.Entity.Segment.ListResidue.Residue.CrossRefDb;
+import jalview.xml.binding.sifts.Entry.Entity.Segment.ListResidue.Residue.ResidueDetail;
 
 public class SiftsClient implements SiftsClientI
 {
@@ -123,6 +123,7 @@ public class SiftsClient implements SiftsClientI
   private enum CoordinateSys
   {
     UNIPROT("UniProt"), PDB("PDBresnum"), PDBe("PDBe");
+
     private String name;
 
     private CoordinateSys(String name)
@@ -140,6 +141,7 @@ public class SiftsClient implements SiftsClientI
   {
     NAME_SEC_STRUCTURE("nameSecondaryStructure"),
     CODE_SEC_STRUCTURE("codeSecondaryStructure"), ANNOTATION("Annotation");
+
     private String code;
 
     private ResidueDetailType(String code)
@@ -225,7 +227,7 @@ public class SiftsClient implements SiftsClientI
               SiftsSettings.getCacheThresholdInDays()))
       {
         File oldSiftsFile = new File(siftsFileName + "_old");
-        siftsFile.renameTo(oldSiftsFile);
+        BackupFiles.moveFileToFile(siftsFile, oldSiftsFile);
         try
         {
           siftsFile = downloadSiftsFile(pdbId.toLowerCase());
@@ -234,7 +236,7 @@ public class SiftsClient implements SiftsClientI
         } catch (IOException e)
         {
           e.printStackTrace();
-          oldSiftsFile.renameTo(siftsFile);
+          BackupFiles.moveFileToFile(oldSiftsFile, siftsFile);
           return new File(siftsFileName);
         }
       }
@@ -461,7 +463,7 @@ public class SiftsClient implements SiftsClientI
           SequenceI seq, java.io.PrintStream os) throws SiftsException
   {
     List<Integer> omitNonObserved = new ArrayList<>();
-    int nonObservedShiftIndex = 0,pdbeNonObserved=0;
+    int nonObservedShiftIndex = 0, pdbeNonObserved = 0;
     // System.out.println("Generating mappings for : " + entityId);
     Entity entity = null;
     entity = getEntityById(entityId);
@@ -492,7 +494,7 @@ public class SiftsClient implements SiftsClientI
     TreeMap<Integer, String> resNumMap = new TreeMap<Integer, String>();
     List<Segment> segments = entity.getSegment();
     SegmentHelperPojo shp = new SegmentHelperPojo(seq, mapping, resNumMap,
-            omitNonObserved, nonObservedShiftIndex,pdbeNonObserved);
+            omitNonObserved, nonObservedShiftIndex, pdbeNonObserved);
     processSegments(segments, shp);
     try
     {
@@ -514,18 +516,20 @@ public class SiftsClient implements SiftsClientI
     {
       throw new SiftsException("SIFTS mapping failed");
     }
-    // also construct a mapping object between the seq-coord sys and the PDB seq's coord sys
+    // also construct a mapping object between the seq-coord sys and the PDB
+    // seq's coord sys
 
     Integer[] keys = mapping.keySet().toArray(new Integer[0]);
     Arrays.sort(keys);
     seqStart = keys[0];
     seqEnd = keys[keys.length - 1];
-    List<int[]> from=new ArrayList<>(),to=new ArrayList<>();
-    int[]_cfrom=null,_cto=null;
+    List<int[]> from = new ArrayList<>(), to = new ArrayList<>();
+    int[] _cfrom = null, _cto = null;
     String matchedSeq = originalSeq;
-    if (seqStart != UNASSIGNED) // fixme! seqStart can map to -1 for a pdb sequence that starts <-1
+    if (seqStart != UNASSIGNED) // fixme! seqStart can map to -1 for a pdb
+                                // sequence that starts <-1
     {
-      for (int seqps:keys)
+      for (int seqps : keys)
       {
         int pdbpos = mapping.get(seqps)[PDBE_POS];
         if (pdbpos == UNASSIGNED)
@@ -533,19 +537,23 @@ public class SiftsClient implements SiftsClientI
           // not correct - pdbpos might be -1, but leave it for now
           continue;
         }
-        if (_cfrom==null || seqps!=_cfrom[1]+1)
+        if (_cfrom == null || seqps != _cfrom[1] + 1)
         {
-          _cfrom = new int[] { seqps,seqps};
+          _cfrom = new int[] { seqps, seqps };
           from.add(_cfrom);
           _cto = null; // discontinuity
-        } else {
-          _cfrom[1]= seqps;
         }
-        if (_cto==null || pdbpos!=1+_cto[1])
+        else
+        {
+          _cfrom[1] = seqps;
+        }
+        if (_cto == null || pdbpos != 1 + _cto[1])
         {
-          _cto = new int[] { pdbpos,pdbpos};
+          _cto = new int[] { pdbpos, pdbpos };
           to.add(_cto);
-        } else {
+        }
+        else
+        {
           _cto[1] = pdbpos;
         }
       }
@@ -567,8 +575,7 @@ public class SiftsClient implements SiftsClientI
       ;
 
       seqFromPdbMapping = new jalview.datamodel.Mapping(null, _cto, _cfrom,
-              1,
-              1);
+              1, 1);
       pdbStart = mapping.get(seqStart)[PDB_RES_POS];
       pdbEnd = mapping.get(seqEnd)[PDB_RES_POS];
       int orignalSeqStart = seq.getStart();
@@ -699,12 +706,12 @@ public class SiftsClient implements SiftsClientI
         }
         // if (currSeqIndex >= seq.getStart() && currSeqIndex <= seqlength) //
         // true
-                                                                         // numbering
-                                                                         // is
-                                                                         // not
-                                                                         // up
-                                                                         // to
-                                                                         // seq.getEnd()
+        // numbering
+        // is
+        // not
+        // up
+        // to
+        // seq.getEnd()
         {
 
           int resNum = (pdbRefDb == null)
@@ -1044,6 +1051,7 @@ public class SiftsClient implements SiftsClientI
     {
       return pdbeNonObserved;
     }
+
     public SequenceI getSeq()
     {
       return seq;