JAL-3130 Merge of JAL-3130_Java_11_investigations-Ben-2 and updated develop
authorBen Soares <bsoares@dundee.ac.uk>
Tue, 19 Mar 2019 14:58:52 +0000 (14:58 +0000)
committerBen Soares <bsoares@dundee.ac.uk>
Tue, 19 Mar 2019 14:58:52 +0000 (14:58 +0000)
1  2 
authors.props
build-j11.xml
resources/lang/Messages.properties
resources/lang/Messages_es.properties
src/jalview/gui/AlignFrame.java
src/jalview/gui/Desktop.java
src/jalview/io/FileLoader.java
src/jalview/jbgui/GDesktop.java
test/jalview/bin/CommandLineOperations.java

diff --combined authors.props
index 0000000,0000000..3c06708
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,4 @@@
++YEAR=2018
++AUTHORS=J Procter, M Carstairs, B Soares, K Mourao, TC Ofoegbu, AM Waterhouse, J Engelhardt, LM Lui, A Menard, D Barton, N Sherstnev, D Roldan-Martinez, M Clamp, S Searle, G Barton
++AUTHORFNAMES=Jim Procter, Mungo Carstairs, Ben Soares, Kira Mourao, Tochukwu 'Charles' Ofoegbu, Andrew Waterhouse, Jan Engelhardt, Lauren Lui, Anne Menard, Daniel Barton, Natasha Sherstnev, David Roldan-Martinez, Michele Clamp, James Cuff, Steve Searle, David Martin & Geoff Barton
++ 
diff --combined build-j11.xml
      <condition property="java9">
        <equals arg1="${ant.java.version}" arg2="9"/>
      </condition>
+     <!-- Java 10 JVM args -->
+     <condition property="java10">
+       <equals arg1="${ant.java.version}" arg2="10"/>
+     </condition>
+     <!-- Java 11 JVM args -->
+     <condition property="java11">
+       <equals arg1="${ant.java.version}" arg2="11"/>
+     </condition>
+     <echo message="ant.java.version is ${ant.java.version}"/>
  
      <!-- Don't change anything below here unless you know what you are doing! -->
      <!-- Url path for WebStart in JNLP file -->
      <!-- Anne's version needs 1.7 - should rebuild VARNA to java 1.6 for release -->
      <property name="j2sev" value="1.7+" />
      <!-- Java Compilation settings - source and target javac version -->
-     <property name="javac.source" value="1.8" />
-     <property name="javac.target" value="1.8" />
+     <property name="javac.source" value="11" if:set="java11" />
+     <property name="javac.target" value="11" if:set="java11" />
+     <property name="javac.source" value="1.8" unless:set="java11" />
+     <property name="javac.target" value="1.8" unless:set="java11" />
+     <echo message="javac.source is ${javac.source}"/>
+     <echo message="javac.target is ${javac.target}"/>
  
      <!-- Permissions for running Java applets and applications. -->
      <!-- Defaults are those suitable for deploying jalview webstart www.jalview.org -->
  
      <!-- build directory configuration -->
      <property name="libDir" value="lib" />
+     <property name="j11libDir" value="j11lib" />
      <property name="resourceDir" value="resources" />
      <property name="helpDir" value="help" />
      <property name="docDir" value="doc" />
          <include name="*.jar" />
          <include name="**/*.jar" />
        </fileset>
+       <fileset dir="${j11libDir}">
+         <include name="*.jar" />
+         <include name="**/*.jar" />
+       </fileset>
        <fileset dir="${libDir}">
          <include name="*.jar" />
          <include name="**/*.jar" />
          <include name="${jmolJar}" />
          <include name="${varnaJar}" />
        </fileset>
+       <pathelement location="${clover.jar}" if:set="clover.jar"/>
      </path>
      <path id="test.classpath">
        <pathelement path="${outputDir}" />
  
    <target name="build" depends="prepare">
      <!-- not efficient yet. -->
-     <javac source="${javac.source}" target="${javac.target}" srcdir="${sourceDir}" destdir="${outputDir}" debug="${javac.debug}" classpathref="build.classpath">
+     <!-- Echo the build.classpath
+     <pathconvert property="echoClasspath" refid="build.classpath" />
+     <echo message="build.classpath is '${echoClasspath}'" />
+     -->
+     <echo message="javac.target is '${javac.target}'" />
+     <echo message="adding -Xlint:deprecation to javac" if:set="deprecation"/>
+     <javac includeantruntime="false" source="${javac.source}" target="${javac.target}" srcdir="${sourceDir}" destdir="${outputDir}" debug="${javac.debug}" classpathref="build.classpath">
+       <compilerarg value="-Xlint:deprecation" if:set="deprecation" />
        <exclude name="jalview/*applet*" />
        <exclude name="jalview/appletgui/**" />
        <exclude name="com/stevesoft/**" />
    <taskdef resource="testngtasks" classpath="utils/testnglibs/testng.jar" />
  
    <target name="testng" depends="buildTests">
+     <loadfile property="j11modules" srcFile="modules"/>
+     <echo message="j11libDir is '${j11libDir}'" />
+     <echo message="j11modules is '${j11modules}'" />
      <testng outputDir="${reportDir}" haltOnFailure="false" groups="${testng-groups}" mode="testng"
        verbose="2">
        <classpath>
          <pathelement location="${clover.jar}" if:set="clover.jar"/>
          <path refid="test.classpath" />
        </classpath>
+       <jvmarg value="--module-path=${j11libDir}:${java.home}/jmods" if:set="java11"/>
+       <jvmarg value="--add-modules=${j11modules}" if:set="java11"/>
        <jvmarg value="--add-modules=java.se.ee" if:set="java9"/>
        <jvmarg value="--illegal-access=warn" if:set="java9"/>
        <classfileset dir="${testOutputDir}" includes="**/*.class" />
      </testng>
    </target>
  
+   <target name="testngclass" depends="buildTests">
+     <condition property="propsSpecified">
+       <isset property="class.name" />
+     </condition>
+     <fail unless="propsSpecified" message="class.name property not specified."/>
+     <echo message="testng-groups is '${testng-groups}'" />
+     <loadfile property="j11modules" srcFile="modules"/>
+     <testng outputDir="${reportDir}" haltOnFailure="false" groups="${testng-groups}" mode="testng" verbose="2">
+       <classpath>
+         <pathelement location="${testOutputDir}" />
+         <pathelement location="${clover.jar}" if:set="clover.jar"/>
+         <path refid="test.classpath" />
+       </classpath>
+       <jvmarg value="--module-path=${j11libDir}:${java.home}/jmods" if:set="java11"/>
+       <jvmarg value="--add-modules=${j11modules}" if:set="java11"/>
+       <jvmarg value="--add-modules=java.se.ee" if:set="java9"/>
+       <jvmarg value="--illegal-access=warn" if:set="java9"/>
+       <classfileset dir="${testOutputDir}" includes="${class.name}" />
+     </testng>
+   </target>
    <target name="buildindices" depends="init, prepare" unless="help.uptodate">
      <replace value="${JALVIEW_VERSION}">
        <replacetoken><![CDATA[$$Version-Rel$$]]></replacetoken>
    <delete file="in.jar" />
  </target>
  
 +<target name="jaxb-bindings" depends="init" description="Generates JAXB bindings for supported Jalview XML models (needs xjc on the path)">
 +  <delete>
 +    <fileset dir="${sourceDir}/jalview/xml/binding/jalview">
 +      <include name="*.java" />
 +    </fileset>
 +  </delete>
 +  <exec executable="xjc">
 +    <arg value="${schemaDir}/jalview.xsd"/>
 +    <arg value="-d"/>
 +    <arg value="${sourceDir}"/>
 +    <arg value="-p"/>
 +    <arg value="jalview.xml.binding.jalview"/>
 +  </exec>
 +  <delete>
 +    <fileset dir="${sourceDir}/jalview/xml/binding/embl">
 +      <include name="*.java" />
 +    </fileset>
 +  </delete>
 +
 +  <exec executable="xjc">
 +    <arg value="${schemaDir}/embl.xsd"/>
 +    <arg value="-d"/>
 +    <arg value="${sourceDir}"/>
 +    <arg value="-b"/>
 +    <arg value="${schemaDir}/embl_bindings.xml"/>
 +    <arg value="-p"/>
 +    <arg value="jalview.xml.binding.embl"/>
 +  </exec>
 +
 +  <delete>
 +    <fileset dir="${sourceDir}/jalview/xml/binding/uniprot">
 +      <include name="*.java" />
 +    </fileset>
 +  </delete>
 +
 +  <exec executable="xjc">
 +    <arg value="${schemaDir}/uniprot.xsd"/>
 +    <arg value="-d"/>
 +    <arg value="${sourceDir}"/>
 +    <arg value="-p"/>
 +    <arg value="jalview.xml.binding.uniprot"/>
 +  </exec>
 +</target>
 +
  <target name="sourcedist" description="create jalview source distribution" depends="init">
    <delete file="${source.dist.name}" />
    <!-- temporary copy of source to update timestamps -->
@@@ -30,8 -30,8 +30,9 @@@ action.minimize_associated_windows = Mi
  action.close_all = Close all
  action.load_project = Load Project
  action.save_project = Save Project
 +action.save_project_as = Save Project as...
  action.quit = Quit
+ label.quit_jalview = Quit Jalview?
  action.expand_views = Expand Views
  action.gather_views = Gather Views
  action.page_setup = Page Setup...
@@@ -119,8 -119,10 +120,8 @@@ action.select = Selec
  action.new_view = New View
  action.close = Close
  action.add = Add
 -action.save_as_default = Save as default
  action.save_as = Save as...
  action.save = Save
 -action.cancel_fetch = Cancel Fetch
  action.change_font = Change Font
  action.change_font_tree_panel = Change Font (Tree Panel)
  action.colour = Colour
@@@ -139,6 -141,7 +140,6 @@@ action.fetch_db_references = Fetch DB R
  action.view_flanking_regions = Show flanking regions
  label.view_flanking_regions = Show sequence data either side of the subsequences involved in this alignment
  label.structures_manager = Structures Manager
 -label.nickname = Nickname:
  label.url = URL
  label.url\: = URL:
  label.input_file_url = Enter URL or Input File
@@@ -160,6 -163,7 +161,6 @@@ label.current_parameter_set_name = Curr
  label.service_action = Service Action:
  label.post_url = POST URL:
  label.url_suffix = URL Suffix
 -label.sequence_source = Sequence Source
  label.per_seq = per Sequence
  label.result_vertically_separable = Results are vertically separable
  label.amend = Amend
@@@ -169,9 -173,10 +170,9 @@@ label.principal_component_analysis = Pr
  label.average_distance_identity = Average Distance Using % Identity
  label.neighbour_joining_identity = Neighbour Joining Using % Identity
  label.choose_calculation = Choose Calculation
 -label.treecalc_title = {0} Using {1}
 +label.calc_title = {0} Using {1}
  label.tree_calc_av = Average Distance
  label.tree_calc_nj = Neighbour Joining
 -label.select_score_model = Select score model
  label.score_model_pid = % Identity
  label.score_model_blosum62 = BLOSUM62
  label.score_model_pam250 = PAM 250
@@@ -199,7 -204,6 +200,7 @@@ label.colourScheme_purine/pyrimidine = 
  label.colourScheme_nucleotide = Nucleotide
  label.colourScheme_t-coffee_scores = T-Coffee Scores
  label.colourScheme_rna_helices = By RNA Helices
 +label.colourScheme_sequence_id = Sequence ID Colour
  label.blc = BLC
  label.fasta = Fasta
  label.msf = MSF
@@@ -350,6 -354,7 +351,6 @@@ label.status = Statu
  label.channels = Channels
  label.channel_title_item_count = {0} ({1})
  label.blog_item_published_on_date = {0} {1} 
 -label.select_das_service_from_table = Select a DAS service from the table to read a full description here.</font></html>
  label.session_update = Session Update
  label.new_vamsas_session = New Vamsas Session
  action.load_vamsas_session = Load Vamsas Session...
@@@ -367,6 -372,7 +368,6 @@@ label.load_colours = Load Colour
  label.save_colours = Save Colours
  label.load_colours_tooltip = Load feature colours and filters from file
  label.save_colours_tooltip = Save feature colours and filters to file
 -label.fetch_das_features = Fetch DAS Features
  label.selected_database_to_fetch_from = Selected {0} database {1} to fetch from {2} 
  label.database_param = Database: {0}
  label.example = Example
@@@ -404,11 -410,14 +405,11 @@@ label.couldnt_find_pdb_id_in_file = Cou
  label.no_pdb_id_in_file = No PDB Id in File
  label.couldnt_read_pasted_text = Couldn't read the pasted text {0}
  label.error_parsing_text = Error parsing text
 -label.enter_local_das_source = Enter Nickname & URL of Local DAS Source
 -label.you_can_only_edit_or_remove_local_das_sources = You can only edit or remove local DAS Sources!
 -label.public_das_source = Public DAS source - not editable
  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.vamsas_document_import_failed = Vamsas Document Import Failed
 -label.couldnt_locate = Couldn't locate {0}
 +label.couldnt_locate = Could not locate {0}
  label.url_not_found = URL not found
  label.new_sequence_url_link = New sequence URL link
  label.cannot_edit_annotations_in_wrapped_view = Cannot edit annotations in wrapped view
@@@ -420,6 -429,8 +421,6 @@@ label.invalid_url = Invalid URL 
  label.error_loading_file = Error loading file
  label.problems_opening_file = Encountered problems opening {0}!!
  label.file_open_error = File open error
 -label.no_das_sources_selected_warn = No das sources were selected.\nPlease select some sources and\ntry again.
 -label.no_das_sources_selected_title = No DAS Sources Selected
  label.colour_scheme_exists_overwrite = Colour scheme {0} exists.\nContinue saving colour scheme as {1}?"
  label.duplicate_scheme_name = Duplicate scheme name
  label.jalview_new_questionnaire = There is a new Questionnaire available. Would you like to complete it now ?\n
@@@ -492,10 -503,6 +493,10 @@@ label.edit_name_description = Edit Name
  label.create_sequence_feature = Create Sequence Feature...
  label.edit_sequence = Edit Sequence
  label.edit_sequences = Edit Sequences
 +label.insert_gap = Insert 1 gap
 +label.insert_gaps = Insert {0} gaps
 +label.delete_gap = Delete 1 gap
 +label.delete_gaps = Delete {0} gaps
  label.sequence_details = Sequence Details
  label.jmol_help = Jmol Help
  label.chimera_help = Chimera Help
@@@ -616,6 -623,7 +617,6 @@@ label.visual = Visua
  label.connections = Connections
  label.output = Output
  label.editing = Editing
 -label.das_settings = DAS Settings
  label.web_services = Web Services
  label.right_click_to_edit_currently_selected_parameter = Right click to edit currently selected parameter.
  label.let_jmol_manage_structure_colours = Let Jmol manage structure colours
@@@ -631,6 -639,10 +632,6 @@@ label.delete_service_url = Delete Servi
  label.details = Details
  label.options = Options
  label.parameters = Parameters
 -label.available_das_sources = Available DAS Sources
 -label.full_details = Full Details
 -label.authority = Authority
 -label.type = Type
  label.proxy_server = Proxy Server
  label.file_output = File Output
  label.select_input_type = Select input type
@@@ -699,6 -711,9 +700,6 @@@ label.sort_alignment_new_tree = Sort Al
  label.add_sequences = Add Sequences
  label.new_window = New Window
  label.split_window = Split Window
 -label.refresh_available_sources = Refresh Available Sources
 -label.use_registry = Use Registry
 -label.add_local_source = Add Local Source
  label.set_as_default = Set as Default
  label.show_labels = Show labels
  action.background_colour = Background Colour...
@@@ -757,7 -772,7 +758,7 @@@ label.run_with_preset_params = Run {0} 
  label.view_and_change_parameters_before_running_calculation = View and change parameters before running calculation
  label.view_documentation = View documentation
  label.select_return_type = Select return type
 -label.translation_of_params = Translation of {0}
 +label.translation_of_params = Translation of {0} (Table {1})
  label.features_for_params = Features for - {0}
  label.annotations_for_params = Annotations for - {0}
  label.generating_features_for_params = Generating features for - {0}
@@@ -839,6 -854,7 +840,6 @@@ label.multiharmony = Multi-Harmon
  label.unable_start_web_service_analysis = Unable to start web service analysis
  label.job_couldnt_be_started_check_input = The Job couldn't be started. Please check your input, and the Jalview console for any warning messages.
  label.prompt_each_time = Prompt each time
 -label.use_source = Use Source
  label.couldnt_save_project = Couldn't save project
  label.error_whilst_saving_current_state_to = Error whilst saving current state to {0}
  label.error_whilst_loading_project_from = Error whilst loading project from {0}
@@@ -864,6 -880,7 +865,6 @@@ label.error_unsupported_owwner_user_col
  label.save_alignment_to_file = Save Alignment to file
  label.save_features_to_file = Save Features to File
  label.save_annotation_to_file = Save Annotation to File
 -label.no_features_on_alignment = No features found on alignment
  label.save_pdb_file = Save PDB File
  label.save_text_to_file = Save Text to File
  label.save_state = Save State
@@@ -1063,6 -1080,8 +1064,6 @@@ exception.unable_to_create_internet_con
  exception.invocation_target_calling_url = InvocationTargetException while calling openURL: {0}
  exception.illegal_access_calling_url = IllegalAccessException while calling openURL: {0}
  exception.interrupted_launching_browser = InterruptedException while launching browser: {0}
 -exception.das_source_doesnt_support_sequence_command = Source {0} does not support the sequence command.
 -exception.invalid_das_source = Invalid das source: {0}
  exception.ebiembl_retrieval_failed_on = EBI EMBL XML retrieval failed on {0}:{1}
  exception.no_pdb_records_for_chain = No PDB Records for {0} chain {1}
  exception.unexpected_handling_rnaml_translation_for_pdb = Unexpected exception when handling RNAML translation of PDB data
@@@ -1117,6 -1136,10 +1118,6 @@@ status.parsing_results = Parsing result
  status.processing = Processing...
  status.refreshing_web_service_menus = Refreshing Web Service Menus
  status.collecting_job_results = Collecting job results.
 -status.fetching_das_sequence_features = Fetching DAS Sequence Features
 -status.no_das_sources_active = No DAS Sources Active
 -status.das_feature_fetching_cancelled = DAS Feature Fetching Cancelled
 -status.das_feature_fetching_complete = DAS Feature Fetching Complete
  status.fetching_db_refs = Fetching db refs
  status.loading_cached_pdb_entries = Loading Cached PDB Entries
  status.searching_for_pdb_structures = Searching for PDB Structures
@@@ -1139,6 -1162,8 +1140,6 @@@ warn.urls_not_contacted = URLs that cou
  warn.urls_no_jaba = URLs without any JABA Services
  info.validate_jabaws_server = Validate JabaWS Server ?\n(Look in console output for results)
  label.test_server = Test Server?
 -info.you_want_jalview_to_find_uniprot_accessions = Do you want Jalview to find\nUniprot Accession ids for given sequence names?
 -label.find_uniprot_accession_ids = Find Uniprot Accession Ids
  label.new_sequence_fetcher = New Sequence Fetcher
  label.additional_sequence_fetcher = Additional Sequence Fetcher
  label.select_database_retrieval_source = Select Database Retrieval Source
@@@ -1260,6 -1285,7 +1261,6 @@@ label.SEQUENCE_ID_for_DB_ACCESSION1 = P
  label.SEQUENCE_ID_for_DB_ACCESSION2 = URL links using '$SEQUENCE_ID$' for DB accessions now use '$DB_ACCESSION$'.
  label.do_not_display_again = Do not display this message again
  exception.url_cannot_have_duplicate_id = {0} cannot be used as a label for more than one line
 -label.filter = Filter text:
  action.customfilter = Custom only
  action.showall = Show All
  label.insert = Insert:
@@@ -1274,6 -1300,7 +1275,6 @@@ label.edit_sequence_url_link = Edit seq
  warn.name_cannot_be_duplicate = User-defined URL names must be unique and cannot be MIRIAM ids
  label.output_seq_details = Output Sequence Details to list all database references
  label.urllinks = Links
 -label.default_cache_size = Default Cache Size
  action.clear_cached_items = Clear Cached Items
  label.togglehidden = Show hidden regions
  label.quality_descr = Alignment Quality based on Blosum62 scores
@@@ -1326,6 -1353,7 +1327,6 @@@ label.colour_by_text = Colour by tex
  label.graduated_colour = Graduated Colour
  label.by_text_of = By text of
  label.by_range_of = By range of
 -label.filters_tooltip = Click to set or amend filters
  label.or = Or
  label.and = And
  label.sequence_feature_colours = Sequence Feature Colours
@@@ -1336,60 -1364,3 +1337,60 @@@ label.most_bound_molecules = Most Boun
  label.most_polymer_residues = Most Polymer Residues
  label.cached_structures = Cached Structures
  label.free_text_search = Free Text Search
 +label.backupfiles_confirm_delete = Confirm delete
 +label.backupfiles_confirm_delete_old_files = Delete the following older backup files? (see the Backups tab in Preferences for more options)
 +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.backups = Backups
 +label.backup = Backup
 +label.backup_files = Backup Files
 +label.enable_backupfiles = Enable backup files
 +label.backup_filename_strategy = Backup filename strategy
 +label.append_to_filename = Append to filename (%n is replaced by the backup number)
 +label.append_to_filename_tooltip = %n in the text will be replaced by the backup number. The text will appear after the filename. See the summary box above.
 +label.index_digits = Number of digits to use for the backup number (%n)
 +label.summary_of_backups_scheme = Summary of backup scheme
 +label.increment_index = Increase appended text numbers - newest file has largest number.
 +label.reverse_roll = "Roll" appended text numbers - newest backup file is always number 1.
 +label.keep_files = Deleting old backup files
 +label.keep_all_backup_files = Do not delete old backup files
 +label.keep_only_this_number_of_backup_files = Keep only this number of most recent backup files
 +label.autodelete_old_backup_files = Autodelete old backup files:
 +label.always_ask = Always ask
 +label.auto_delete = Automatically delete
 +label.filename = filename
 +label.braced_oldest = (oldest)
 +label.braced_newest = (most recent)
 +label.configuration = Configuration
 +label.configure_feature_tooltip = Click to configure variable colour or filters
 +label.schemes = Schemes
 +label.customise = Customise
 +label.default = Default
 +label.single_file = Single backup
 +label.keep_all_versions = Keep all versions
 +label.rolled_backups = Rolled backup files
 +label.previously_saved_scheme = Previously saved scheme
 +label.no_backup_files = NO BACKUP FILES
 +label.include_backup_files = Include backup files
 +label.cancel_changes = Cancel changes
 +label.warning_confirm_change_reverse = Warning!\nIf you change the increment/decrement of the backup filename number, without changing the suffix or number of digits,\nthis may cause loss of backup files created with the previous backup filename scheme.\nAre you sure you wish to do this?
 +label.change_increment_decrement = Change increment/decrement?
 +label.was_previous = was {0}
 +label.newerdelete_replacement_line = 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}).
 +label.confirm_deletion_or_rename = Confirm deletion of ''{0}'' or rename to ''{1}''?
 +label.newerdelete_line = 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}).
 +label.confirm_deletion = Confirm deletion of ''{0}''?
 +label.delete = Delete
 +label.rename = Rename
 +label.keep = Keep
 +label.file_info = (modified {0}, size {1})
 +label.annotation_name = Annotation Name
 +label.annotation_description = Annotation Description 
 +label.edit_annotation_name_description = Edit Annotation Name/Description
 +label.alignment = alignment
 +label.pca = PCA
 +label.create_image_of = Create {0} image of {1}
 +label.click_to_edit = Click to edit, right-click for menu
 +label.by_annotation_tooltip = Annotation Colour is configured from the main Colour menu
@@@ -30,8 -30,8 +30,9 @@@ action.minimize_associated_windows = Mi
  action.close_all = Cerrar todo
  action.load_project = Cargar proyecto
  action.save_project = Guardar proyecto
 +action.save_project_as = Guardar proyecto como...
  action.quit = Salir
+ label.quit_jalview = Salir Javliew?
  action.expand_views = Expandir vistas
  action.gather_views = Capturar vistas
  action.page_setup = Configuración de la página
@@@ -116,8 -116,10 +117,8 @@@ action.select = Selecciona
  action.new_view = Nueva vista
  action.close = Cerrar
  action.add = Añadir
 -action.save_as_default = Guardar como por defecto
  action.save_as = Guardar como
  action.save = Guardar
 -action.cancel_fetch = Cancelar búsqueda
  action.change_font = Cambiar Fuente
  action.change_font_tree_panel = Cambiar fuente (panel del Ã¡rbol)
  action.colour = Color
@@@ -136,6 -138,7 +137,6 @@@ action.fetch_db_references = Recuperar 
  action.view_flanking_regions = Mostrar flancos
  label.view_flanking_regions = Mostrar los datos de la secuencia a ambos lados de las subsecuencias implicadas en este alineamiento
  label.structures_manager = Administrar estructuras
 -label.nickname = Sobrenombre:
  label.url\: = URL:
  label.url = URL 
  label.input_file_url = Introducir URL en el fichero de entrada
@@@ -157,6 -160,7 +158,6 @@@ label.current_parameter_set_name = Nomb
  label.service_action = Acción de servicio:
  label.post_url = POST URL: 
  label.url_suffix = URL Sufijo
 -label.sequence_source = Fuente de la secuencia
  label.per_seq = por secuencia
  label.result_vertically_separable = Los resultados son separables verticalmente
  label.amend = Modificar
@@@ -166,9 -170,10 +167,9 @@@ label.principal_component_analysis = An
  label.average_distance_identity = Distancia Media Usando % de Identidad
  label.neighbour_joining_identity = Unir vecinos utilizando % de Identidad
  label.choose_calculation = Elegir el cálculo
 -label.treecalc_title = {0} utilizando {1}
 +label.calc_title = {0} utilizando {1}
  label.tree_calc_av = Distancia media
  label.tree_calc_nj = Unir vecinos
 -label.select_score_model = Selecciones modelo de puntuación
  label.score_model_pid = % Identidad
  label.score_model_blosum62 = BLOSUM62
  label.score_model_pam250 = PAM 250
@@@ -195,7 -200,6 +196,7 @@@ label.colourScheme_purine/pyrimidine = 
  label.colourScheme_nucleotide = Nucleótido
  label.colourScheme_t-coffee_scores = Puntuación del T-Coffee
  label.colourScheme_rna_helices = Por hélices de RNA
 +label.colourScheme_sequence_id = Color de ID de secuencia
  label.blc = BLC
  label.fasta = Fasta
  label.msf = MSF
@@@ -319,6 -323,7 +320,6 @@@ label.status =  [Estado
  label.channels = Canales
  label.channel_title_item_count = {0} ({1})
  label.blog_item_published_on_date = {0} {1} 
 -label.select_das_service_from_table = Seleccionar servicio DAS de la tabla para leer una descripción completa aquí.
  label.session_update = Actualizar sesión
  label.new_vamsas_session = Nueva sesión Vamsas
  action.save_vamsas_session = Guardar Sesión Vamsas
@@@ -335,6 -340,7 +336,6 @@@ label.load_colours = Cargar colore
  label.save_colours = Guardar colores
  label.load_colours_tooltip = Cargar colores y filtros desde fichero
  label.save_colours_tooltip = Guardar colores y filtros en fichero
 -label.fetch_das_features = Recuperar funciones DAS
  label.selected_database_to_fetch_from = Seleccionada {0} Base de datos {1} para buscar de {2} 
  label.database_param = Base de datos: {0}
  label.example = Ejemplo
@@@ -371,6 -377,9 +372,6 @@@ label.couldnt_find_pdb_id_in_file = No 
  label.no_pdb_id_in_file = No hay un Id PDB en el fichero
  label.couldnt_read_pasted_text = No se pudo leer el texto pegado {0}
  label.error_parsing_text = Error analizando el texto
 -label.enter_local_das_source = Intruduzca el Nickname & URL de la fuente DAS local
 -label.you_can_only_edit_or_remove_local_das_sources = Sólo puedes editar o eliminar fuentes DAS locales!
 -label.public_das_source = Fuente pública DAS - no editable
  label.input_alignment_from_url = Alineamiento de entrada desde URL
  label.input_alignment = Alineamiento de entrada
  label.couldnt_import_as_vamsas_session = No se pudo importar {0} como una nueva sesión Vamsas.
@@@ -387,6 -396,8 +388,6 @@@ label.invalid_url = URL Invalido
  label.error_loading_file = Error al cargar el fichero
  label.problems_opening_file = Encontrados problemas al abrir el fichero {0}!!
  label.file_open_error = Error al abrir el fichero
 -label.no_das_sources_selected_warn = No han sido seleccionadas fuentes DAS.\nPor favor, seleccione algunas fuentes y\npruebe de nuevo.
 -label.no_das_sources_selected_title = No han sido seleccionadas fuentes DAS
  label.colour_scheme_exists_overwrite = El esquema de colores {0} ya existe.\nContinuar guardando el esquema de colores como {1}?
  label.duplicate_scheme_name = Duplicar nombre de esquema
  label.jalview_new_questionnaire = Hay un nuevo cuestionario disponible. Querr\u00EDa completarlo ahora ?\n
@@@ -458,10 -469,6 +459,10 @@@ label.edit_name_description = Editar no
  label.create_sequence_feature = Crear función de secuencia
  label.edit_sequence = Editar secuencia
  label.edit_sequences = Editar secuencias
 +label.insert_gap = Insertar 1 hueco
 +label.insert_gaps = Insertar {0} huecos
 +label.delete_gap = Borrar 1 hueco
 +label.delete_gaps = Borrar {0} huecos
  label.sequence_details = Detalles de la secuencia
  label.jmol_help = Ayuda de Jmol
  # Todos/Todas is gender-sensitive, but currently only used for feminine (cadena / anotación)! 
@@@ -571,6 -578,7 +572,6 @@@ label.visual = Visua
  label.connections = Conexiones
  label.output = Salida
  label.editing = Edición
 -label.das_settings = Configuración DAS
  label.web_services = Servicios web
  label.right_click_to_edit_currently_selected_parameter = Haga clic en el botón derecho para editar el parámetro seleccionado actualmente.
  label.let_jmol_manage_structure_colours = Permitir que Jmol gestione la estructuras cromáticas
@@@ -583,6 -591,10 +584,6 @@@ label.delete_service_url = Borrar la UR
  label.details = Detalles
  label.options = Opciones
  label.parameters = Paramétros
 -label.available_das_sources = Fuentes DAS disponibles
 -label.full_details = Detalles completos
 -label.authority = Autoridad
 -label.type = Tipo
  label.proxy_server = Servidor proxy
  label.file_output = Fichero de salida
  label.select_input_type = Seleccionar el tipo de entrada
@@@ -645,6 -657,9 +646,6 @@@ label.get_cross_refs = Obtener referenc
  label.sort_alignment_new_tree = Alinear el alineamiento con el nuevo Ã¡rbol
  label.add_sequences = Añadir secuencias
  label.new_window = Nueva ventana
 -label.refresh_available_sources = Refrescar las fuentes disponibles
 -label.use_registry = Utilizar el registro
 -label.add_local_source = Añadir fuente local
  label.set_as_default = Establecer por defecto
  label.show_labels = Mostrar etiquetas
  label.associate_nodes_with = Asociar nodos con
@@@ -686,7 -701,7 +687,7 @@@ label.run_with_preset_params = Ejecuta
  label.view_and_change_parameters_before_running_calculation = Ver y cambiar los parámetros antes de lanzar el cálculo
  label.view_documentation = Ver documentación
  label.select_return_type = Seleccionar el tipo de retorno
 -label.translation_of_params = Traducción de {0}
 +label.translation_of_params = Traducción de {0} (Tabla {1})
  label.features_for_params = Características de - {0}
  label.annotations_for_params = Anotaciones de - {0}
  label.generating_features_for_params = Generando características de - {0}
@@@ -764,6 -779,7 +765,6 @@@ label.multiharmony = Multi-Harmon
  label.unable_start_web_service_analysis = No es posible iniciar el servicio web de análisis
  label.job_couldnt_be_started_check_input = El trabajo no puede arrancarse. Por favor, compruebe los parámetros de entrada y los mensajes de advertencia de la consola de Jalview.
  label.prompt_each_time = Preguntar siempre
 -label.use_source = Fuente
  label.couldnt_save_project = No es posible guardar el proyecto
  label.error_whilst_saving_current_state_to = Error mientras se guardaba el estado a {0}
  label.error_whilst_loading_project_from = Error cargando el proyecto desde  {0}
@@@ -789,6 -805,7 +790,6 @@@ label.error_unsupported_owwner_user_col
  label.save_alignment_to_file = Guardar Alineamiento en fichero
  label.save_features_to_file = Guardar Características en un fichero
  label.save_annotation_to_file = Guardar Anotación en un fichero
 -label.no_features_on_alignment = No se han encontrado características en el alineamiento
  label.save_pdb_file = Guardar fichero PDB 
  label.save_text_to_file = Guardar Texto en un fichero
  label.save_state = Guardar estado
@@@ -988,6 -1005,8 +989,6 @@@ exception.unable_to_create_internet_con
  exception.invocation_target_calling_url = InvocationTargetException mientras se invocaba openURL: {0}
  exception.illegal_access_calling_url = IllegalAccessException mientras se invocaba openURL: {0}
  exception.interrupted_launching_browser = InterruptedException mientras se lanzaba el navegador: {0}
 -exception.das_source_doesnt_support_sequence_command = La fuente {0} no soporta el comando sequence.
 -exception.invalid_das_source = Fuente DAS no válida: {0}
  exception.ebiembl_retrieval_failed_on = La recuperación de datos EBI EMBL XML ha fallado en {0}:{1}
  exception.no_pdb_records_for_chain = No se han encontrado registros {0} para la cadena {1}
  exception.unexpected_handling_rnaml_translation_for_pdb = Excepcion inesperada cuando se traducían a RNAML los datos PDB
@@@ -1039,6 -1058,10 +1040,6 @@@ status.parsing_results = Parseando resu
  status.processing = Procesando...
  status.refreshing_web_service_menus = Refrescando los menús de servicios web
  status.collecting_job_results = Recolectando los resultados de los trabajos.
 -status.fetching_das_sequence_features = Recuperando las características DAS de las secuencias
 -status.no_das_sources_active = No existe ninguna fuente DAS activa
 -status.das_feature_fetching_cancelled = Recuperación de características DAS cancelada
 -status.das_feature_fetching_complete = Recuperación de características DAS completada
  status.fetching_db_refs = Recuperando db refs
  label.font_doesnt_have_letters_defined = La fuente no tiene letras definidas\npor lo que no puede emplease\ncon datos de alineamientos
  label.font_too_small = Tamaño de la letra es demasiado pequeña
@@@ -1055,6 -1078,8 +1056,6 @@@ warn.server_didnt_pass_validation = El 
  warn.url_must_contain = La URL de la secuencia debe contener $SEQUENCE_ID$, $DB_ACCESSION$ o un regex
  info.validate_jabaws_server = \u00BFValidar el servidor JabaWS?\n(Consulte la consola de salida para obtener los resultados)
  label.test_server = Â¿Probar servidor?
 -info.you_want_jalview_to_find_uniprot_accessions = \u00BFDesea que Jalview encuentre\nUniprot Accession ids para los nombres de secuencias dados?
 -label.find_uniprot_accession_ids = Buscar Uniprot Accession Ids
  label.new_sequence_fetcher = Añadir recuperador de secuencias
  label.additional_sequence_fetcher = Recuperador de secuencia adicional
  label.select_database_retrieval_source = Seleccionar fuente de recuperación de bases de datos
@@@ -1261,6 -1286,7 +1262,6 @@@ label.SEQUENCE_ID_for_DB_ACCESSION1 = P
  label.SEQUENCE_ID_for_DB_ACCESSION2 = URL enlaza usando '$SEQUENCE_ID$' para accesiones DB ahora usar '$DB_ACCESSION$'.
  label.do_not_display_again = No mostrar este mensaje de nuevo
  exception.url_cannot_have_duplicate_id = {0} no puede ser usada como etiqueta en más de un enlace
 -label.filter = Filtrar texto:
  action.customfilter = Sólo personalizado
  action.showall = Mostrar todo
  label.insert = Insertar:
@@@ -1275,6 -1301,7 +1276,6 @@@ label.edit_sequence_url_link = Editar l
  warn.name_cannot_be_duplicate = Los nombres URL definidos por el usuario deben ser Ãºnicos y no pueden ser ids de MIRIAM
  label.output_seq_details = Seleccionar Detalles de la secuencia para ver todas
  label.urllinks = Enlaces
 -label.default_cache_size = Tamaño del caché por defecto
  action.clear_cached_items = Borrar elementos en caché
  label.quality_descr = Calidad de alineamiento basándose en puntuación Blosum62
  label.conservation_descr = Conservación del alineamiento total menos de {0}% huecos
@@@ -1327,6 -1354,7 +1328,6 @@@ label.colour_by_text = Colorear por tex
  label.graduated_colour = Color graduado
  label.by_text_of = Por texto de
  label.by_range_of = Por rango de
 -label.filters_tooltip = Haga clic para configurar o modificar los filtros
  label.or = O
  label.and = Y
  label.sequence_feature_colours = Colores de características de las secuencias
@@@ -1337,60 -1365,3 +1338,60 @@@ label.most_bound_molecules = Más Molécu
  label.most_polymer_residues = Más Residuos de Polímeros
  label.cached_structures = Estructuras en Caché
  label.free_text_search = Búsqueda de texto libre
 +label.backupfiles_confirm_delete = Confirmar borrar
 +label.backupfiles_confirm_delete_old_files = Â¿Borrar los siguientes archivos? (ver la pestaña 'Copias' de la ventana de Preferencias para más opciones)
 +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.backups = Respaldos
 +label.backup = Respaldo
 +label.backup_files = Archivos de respaldos
 +label.enable_backupfiles = Habilitar archivos de respaldos
 +label.backup_filename_strategy = Estrategia de nombres de archivo de respaldos
 +label.append_to_filename = Adjuntar texto (%n es reemplazado por el número de respaldo)
 +label.append_to_filename_tooltip = %n en el texto será reemplazado por el número de respaldo. El texto será después del nombre del archivo. Vea el cuadro de resumen arriba.
 +label.index_digits = Número de dígitos a utilizar para el número de respaldo.
 +label.summary_of_backups_scheme = Resumen del esquema de copias de seguridad
 +label.increment_index = Aumente los números de texto adjuntos: el archivo más nuevo tiene el número más grande
 +label.reverse_roll = Ciclos de texto adjuntos: el respaldo más reciente es siempre el número 1
 +label.keep_files = Borrando los respaldos antiguos
 +label.keep_all_backup_files = No borrar respaldos antiguas
 +label.keep_only_this_number_of_backup_files = Mantenga solo este número de respaldos más recientes
 +label.autodelete_old_backup_files = Borrer automáticamente respaldos antiguos:
 +label.always_ask = Pregunta siempre
 +label.auto_delete = Borrer automáticamente
 +label.filename = nombre_de_archivo
 +label.braced_oldest = (mas antiguo)
 +label.braced_newest = (mas nuevo)
 +label.configuration = Configuración
 +label.configure_feature_tooltip = Haga clic para configurar el color o los filtros
 +label.schemes = Esquemas
 +label.customise = Personalizado
 +label.default = Defecto
 +label.single_file = Solo uno respaldo
 +label.keep_all_versions = Mantener todas las versiones
 +label.rolled_backups = Ciclos respaldos
 +label.previously_saved_scheme = Esquema previamente guardado
 +label.no_backup_files = NO ARCHIVOS DE RESPALDOS
 +label.include_backup_files = Incluir archivos de respaldos
 +label.cancel_changes = Cancelar cambios
 +label.warning_confirm_change_reverse = Â¡Advertencia!\nSi cambia el incremento/decremento del número de archivos de respaldos, sin cambiar el sufijo o número de dígitos,\nesto puede causar la pérdida de los archivos de respaldos creados con el esquema anterior de nombre de archivo de respaldos.\n¿Está seguro de que desea hacer esto?
 +label.change_increment_decrement = Â¿Cambiar de incremento/decremento?
 +label.was_previous = era {0}
 +label.newerdelete_replacement_line = El archivo de respaldo\n''{0}''\t(modificado {2}, tamaño {4})\nserá borrado y reemplazarse por un archivo aparentemente más antiguo\n''{1}''\t(modificado {3}, tamaño {5}).
 +label.confirm_deletion_or_rename = Confirmar borrar ''{0}'', o cambiar el nombre a ''{1}''?
 +label.newerdelete_line = El archivo de respaldo\n''{0}''\t(modificado {2}, tamaño {4})\nserá borrado pero es mas nuevo que el archivo de respaldo restante más antiguo\n''{1}''\t(modified {3}, size {5}).
 +label.confirm_deletion = Confirmar eliminar ''{0}''?
 +label.delete = Borrar
 +label.rename = Cambiar
 +label.keep = Mantener
 +label.file_info = (modificado {0}, tamaño {1})
 +label.annotation_name = Nombre de la anotación
 +label.annotation_description = Descripción de la anotación 
 +label.edit_annotation_name_description = Editar el nombre/descripción de la anotación
 +label.alignment = alineamiento
 +label.pca = ACP
 +label.create_image_of = Crear imagen {0} de {1}
 +label.click_to_edit = Haga clic para editar, clic en el botón derecho para ver el menú  
 +label.by_annotation_tooltip = El color de anotación se configura desde el menú principal de colores
@@@ -24,7 -24,6 +24,7 @@@ import jalview.analysis.AlignmentSorter
  import jalview.analysis.AlignmentUtils;
  import jalview.analysis.CrossRef;
  import jalview.analysis.Dna;
 +import jalview.analysis.GeneticCodeI;
  import jalview.analysis.ParseProperties;
  import jalview.analysis.SequenceIdMatcher;
  import jalview.api.AlignExportSettingI;
@@@ -65,7 -64,6 +65,7 @@@ import jalview.gui.ColourMenuHelper.Col
  import jalview.gui.ViewSelectionMenu.ViewSetProvider;
  import jalview.io.AlignmentProperties;
  import jalview.io.AnnotationFile;
 +import jalview.io.BackupFiles;
  import jalview.io.BioJsHTMLOutput;
  import jalview.io.DataSourceType;
  import jalview.io.FileFormat;
@@@ -136,7 -134,6 +136,7 @@@ 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;
@@@ -966,11 -963,6 +966,11 @@@ public class AlignFrame extends GAlignF
      return progressBar.operationInProgress();
    }
  
 +  /**
 +   * Sets the text of the status bar. Note that setting a null or empty value
 +   * will cause the status bar to be hidden, with possibly undesirable flicker
 +   * of the screen layout.
 +   */
    @Override
    public void setStatus(String text)
    {
        }
        else
        {
 +        // create backupfiles object and get new temp filename destination
 +        BackupFiles backupfiles = new BackupFiles(file);
 +
          try
          {
 -          // PrintWriter out = new PrintWriter(new FileWriter(file));
 -          PrintWriter out = new PrintWriter(new FileWriter(file), true);
 +          PrintWriter out = new PrintWriter(
 +                  new FileWriter(backupfiles.getTempFilePath()));
  
+           // TESTING code here
+           boolean TESTING = true;
+           if (TESTING)
+           {
+             out.print("; TESTSTART\n");
+             int count = 20;
+             for (int i = 0; i < count; i++)
+             {
+               // Thread.sleep(1000);
+               out.println("; TEST: " + (count - 1 - i));
+             }
+           }
            out.print(output);
+           if (TESTING)
+           {
+             out.print("; TESTEND\n");
+           }
            out.close();
            this.setTitle(file);
            statusBar.setText(MessageManager.formatMessage(
            success = false;
            ex.printStackTrace();
          }
 +
 +        backupfiles.setWriteSuccess(success);
 +        // do the backup file roll and rename the temp file to actual file
 +        success = backupfiles.rollBackupsAndRenameTempFile();
 +
        }
      }
  
    @Override
    public void selectAllSequenceMenuItem_actionPerformed(ActionEvent e)
    {
 -    SequenceGroup sg = new SequenceGroup();
 -
 -    for (int i = 0; i < viewport.getAlignment().getSequences().size(); i++)
 -    {
 -      sg.addSequence(viewport.getAlignment().getSequenceAt(i), false);
 -    }
 +    SequenceGroup sg = new SequenceGroup(
 +            viewport.getAlignment().getSequences());
  
      sg.setEndRes(viewport.getAlignment().getWidth() - 1);
      viewport.setSelectionGroup(sg);
 +    viewport.isSelectionGroupChanged(true);
      viewport.sendSelection();
      // JAL-2034 - should delegate to
      // alignPanel to decide if overview needs
  
      if (viewport.getViewName() == null)
      {
 -      viewport.setViewName(
 -              MessageManager.getString("label.view_name_original"));
 +      viewport.setViewName(MessageManager
 +              .getString("label.view_name_original"));
      }
  
      /*
      newap.av.setRedoList(viewport.getRedoList());
  
      /*
 +     * copy any visualisation settings that are not saved in the project
 +     */
 +    newap.av.setColourAppliesToAllGroups(
 +            viewport.getColourAppliesToAllGroups());
 +
 +    /*
       * Views share the same mappings; need to deregister any new mappings
       * created by copyAlignPanel, and register the new reference to the shared
       * mappings
      viewport.setFollowHighlight(state);
      if (state)
      {
 -      alignPanel.scrollToPosition(viewport.getSearchResults(), false);
 +      alignPanel.scrollToPosition(viewport.getSearchResults());
      }
    }
  
      viewport.expandColSelection(sg, false);
      viewport.hideAllSelectedSeqs();
      viewport.hideSelectedColumns();
 +    alignPanel.updateLayout();
      alignPanel.paintAlignment(true, true);
      viewport.sendSelection();
    }
    public void hideSelColumns_actionPerformed(ActionEvent e)
    {
      viewport.hideSelectedColumns();
 +    alignPanel.updateLayout();
      alignPanel.paintAlignment(true, true);
      viewport.sendSelection();
    }
       * otherwise set the chosen colour scheme (or null for 'None')
       */
      ColourSchemeI cs = ColourSchemes.getInstance().getColourScheme(name,
 +            viewport,
              viewport.getAlignment(), viewport.getHiddenRepSequences());
      changeColour(cs);
    }
     * frame's DNA sequences to their aligned protein (amino acid) equivalents.
     */
    @Override
 -  public void showTranslation_actionPerformed(ActionEvent e)
 +  public void showTranslation_actionPerformed(GeneticCodeI codeTable)
    {
      AlignmentI al = null;
      try
      {
        Dna dna = new Dna(viewport, viewport.getViewAsVisibleContigs(true));
  
 -      al = dna.translateCdna();
 +      al = dna.translateCdna(codeTable);
      } catch (Exception ex)
      {
        jalview.bin.Cache.log.error(
        af.setFileFormat(this.currentFileFormat);
        final String newTitle = MessageManager
                .formatMessage("label.translation_of_params", new Object[]
 -              { this.getTitle() });
 +              { this.getTitle(), codeTable.getId() });
        af.setTitle(newTitle);
        if (Cache.getDefault(Preferences.ENABLE_SPLIT_FRAME, true))
        {
              int assocfiles = 0;
              if (filesmatched.size() > 0)
              {
-               boolean autoAssociate = Cache.getDefault("AUTOASSOCIATE_PDBANDSEQS", false);
+               boolean autoAssociate = Cache
+                       .getDefault("AUTOASSOCIATE_PDBANDSEQS", false);
                if (!autoAssociate)
                {
                  String msg = MessageManager.formatMessage(
      {
        PaintRefresher.Refresh(this, viewport.getSequenceSetId());
        alignPanel.updateAnnotation();
 -      alignPanel.paintAlignment(true, true);
 +      alignPanel.paintAlignment(true,
 +              viewport.needToUpdateStructureViews());
      }
    }
  
      colourMenu.add(textColour);
      colourMenu.addSeparator();
  
 -    ColourMenuHelper.addMenuItems(colourMenu, this, viewport.getAlignment(),
 -            false);
 +    ButtonGroup bg = ColourMenuHelper.addMenuItems(colourMenu, this,
 +            viewport.getAlignment(), false);
  
 +    colourMenu.add(annotationColour);
 +    bg.add(annotationColour);
      colourMenu.addSeparator();
      colourMenu.add(conservationMenuItem);
      colourMenu.add(modifyConservation);
      colourMenu.add(abovePIDThreshold);
      colourMenu.add(modifyPID);
 -    colourMenu.add(annotationColour);
  
      ColourSchemeI colourScheme = viewport.getGlobalColourScheme();
      ColourMenuHelper.setColourSelected(colourMenu, colourScheme);
   */
  package jalview.gui;
  
- import static jalview.util.UrlConstants.SEQUENCE_ID;
  import jalview.api.AlignViewportI;
  import jalview.api.AlignmentViewPanel;
  import jalview.bin.Cache;
  import jalview.bin.Jalview;
 +import jalview.io.BackupFiles;
  import jalview.io.DataSourceType;
  import jalview.io.FileFormat;
  import jalview.io.FileFormatException;
@@@ -64,6 -61,14 +62,14 @@@ import java.awt.datatransfer.Clipboard
  import java.awt.datatransfer.ClipboardOwner;
  import java.awt.datatransfer.DataFlavor;
  import java.awt.datatransfer.Transferable;
+ import java.awt.desktop.AboutEvent;
+ import java.awt.desktop.AboutHandler;
+ import java.awt.desktop.PreferencesEvent;
+ import java.awt.desktop.PreferencesHandler;
+ import java.awt.desktop.QuitEvent;
+ import java.awt.desktop.QuitHandler;
+ import java.awt.desktop.QuitResponse;
+ import java.awt.desktop.QuitStrategy;
  import java.awt.dnd.DnDConstants;
  import java.awt.dnd.DropTargetDragEvent;
  import java.awt.dnd.DropTargetDropEvent;
@@@ -82,9 -87,11 +88,11 @@@ import java.beans.PropertyChangeListene
  import java.io.BufferedInputStream;
  import java.io.File;
  import java.io.FileOutputStream;
+ import java.io.FileWriter;
  import java.io.IOException;
  import java.net.URL;
  import java.util.ArrayList;
+ import java.util.HashMap;
  import java.util.Hashtable;
  import java.util.List;
  import java.util.ListIterator;
@@@ -107,10 -114,10 +115,10 @@@ import javax.swing.JCheckBox
  import javax.swing.JComboBox;
  import javax.swing.JComponent;
  import javax.swing.JDesktopPane;
  import javax.swing.JInternalFrame;
  import javax.swing.JLabel;
  import javax.swing.JMenuItem;
+ import javax.swing.JOptionPane;
  import javax.swing.JPanel;
  import javax.swing.JPopupMenu;
  import javax.swing.JProgressBar;
@@@ -146,6 -153,10 +154,10 @@@ public class Desktop extends jalview.jb
  
    private static final String EXPERIMENTAL_FEATURES = "EXPERIMENTAL_FEATURES";
  
+   private static final String CONFIRM_KEYBOARD_QUIT = "CONFIRM_KEYBOARD_QUIT";
+   public static HashMap<String, FileWriter> savingFiles = new HashMap<>();
    private JalviewChangeSupport changeSupport = new JalviewChangeSupport();
  
    /**
  
    private File projectFile;
  
+   private static boolean setAPQHandlers = false;
    /**
     * @param listener
     * @see jalview.gui.JalviewChangeSupport#addJalviewPropertyChangeListener(java.beans.PropertyChangeListener)
  
      doConfigureStructurePrefs();
      setTitle("Jalview " + jalview.bin.Cache.getProperty("VERSION"));
-     setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
+     /*
+     if (!Platform.isAMac())
+     {
+       // this.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
+     }
+     else
+     {
+      this.setDefaultCloseOperation(WindowConstants.DO_NOTHING_ON_CLOSE);
+     }
+     */
+     // flagging this test to avoid unnecessary reflection
+     if (!setAPQHandlers)
+     {
+       // see if the Quit, About and Preferences handlers are available
+       Class desktopClass = java.awt.Desktop.class;
+       java.awt.Desktop hdesktop = java.awt.Desktop.getDesktop();
+       try
+       {
+         if (Platform.isAMac())
+         {
+           if (desktopClass.getDeclaredMethod("setAboutHandler",
+                   new Class[]
+                   { AboutHandler.class }) != null)
+           {
+             hdesktop.setAboutHandler(new AboutHandler()
+             {
+               @Override
+               public void handleAbout(AboutEvent e)
+               {
+                 aboutMenuItem_actionPerformed(null);
+               }
+             });
+           }
+           if (desktopClass.getDeclaredMethod("setPreferencesHandler",
+                   new Class[]
+                   { PreferencesHandler.class }) != null)
+           {
+             hdesktop.setPreferencesHandler(new PreferencesHandler()
+             {
+               @Override
+               public void handlePreferences(PreferencesEvent e)
+               {
+                 preferences_actionPerformed(null);
+               }
+             });
+           }
+           if (desktopClass.getDeclaredMethod("setQuitHandler",
+                   new Class[]
+                   { QuitHandler.class }) != null)
+           {
+             hdesktop.setQuitHandler(new QuitHandler()
+             {
+               @Override
+               public void handleQuitRequestWith(QuitEvent e, QuitResponse r)
+               {
+                 boolean confirmQuit = jalview.bin.Cache
+                         .getDefault(CONFIRM_KEYBOARD_QUIT, true);
+                 int n;
+                 if (confirmQuit)
+                 {
+                   n = JOptionPane.showConfirmDialog(null,
+                           MessageManager.getString("label.quit_jalview"),
+                           MessageManager.getString("action.quit"),
+                           JOptionPane.OK_CANCEL_OPTION,
+                           JOptionPane.PLAIN_MESSAGE, null);
+                 }
+                 else
+                 {
+                   n = JOptionPane.OK_OPTION;
+                 }
+                 if (n == JOptionPane.OK_OPTION)
+                 {
+                   System.out.println("Shortcut Quit confirmed by user");
+                   quit();
+                   r.performQuit(); // probably won't reach this line, but just
+                                    // in
+                                    // case
+                 }
+                 else
+                 {
+                   r.cancelQuit();
+                   System.out.println("Shortcut Quit cancelled by user");
+                 }
+               }
+             });
+             hdesktop.setQuitStrategy(QuitStrategy.CLOSE_ALL_WINDOWS);
+           }
+         }
+       } catch (NoSuchMethodException e)
+       {
+         System.out.println(
+                 "NoSuchMethodException when looking for About, Preferences, Quit Handlers");
+         e.printStackTrace();
+       }
+       setAPQHandlers = true;
+     }
+     addWindowListener(new WindowAdapter()
+     {
+       @Override
+       public void windowClosing(WindowEvent ev)
+       {
+         quit();
+       }
+     });
      boolean selmemusage = jalview.bin.Cache.getDefault("SHOW_MEMUSAGE",
              false);
      boolean showjconsole = jalview.bin.Cache.getDefault("SHOW_JAVA_CONSOLE",
              false);
      desktop = new MyDesktopPane(selmemusage);
      showMemusage.setSelected(selmemusage);
      desktop.setBackground(Color.white);
      getContentPane().setLayout(new BorderLayout());
      // alternate config - have scrollbars - see notes in JAL-153
      // JScrollPane sp = new JScrollPane();
    {
      String fileFormat = Cache.getProperty("DEFAULT_FILE_FORMAT");
      JalviewFileChooser chooser = JalviewFileChooser
 -            .forRead(Cache.getProperty("LAST_DIRECTORY"), fileFormat);
 +            .forRead(Cache.getProperty("LAST_DIRECTORY"), fileFormat, true);
  
      chooser.setFileView(new JalviewFileView());
      chooser.setDialogTitle(
    @Override
    public void quit()
    {
+     System.out.println("********** Desktop.quit()");
+     System.out.println(savingFiles.toString());
      Dimension screen = Toolkit.getDefaultToolkit().getScreenSize();
      jalview.bin.Cache.setProperty("SCREENGEOMETRY_WIDTH",
              screen.width + "");
    @Override
    public void saveState_actionPerformed()
    {
 -    JalviewFileChooser chooser = new JalviewFileChooser("jvp",
 -            "Jalview Project");
 +    saveState_actionPerformed(false);
 +  }
  
 -    chooser.setFileView(new JalviewFileView());
 -    chooser.setDialogTitle(MessageManager.getString("label.save_state"));
 +  public void saveState_actionPerformed(boolean saveAs)
 +  {
 +    java.io.File projectFile = getProjectFile();
 +    // autoSave indicates we already have a file and don't need to ask
 +    boolean autoSave = projectFile != null && !saveAs
 +            && BackupFiles.getEnabled();
  
 -    int value = chooser.showSaveDialog(this);
 +    // System.out.println("autoSave="+autoSave+", projectFile='"+projectFile+"',
 +    // saveAs="+saveAs+", Backups
 +    // "+(BackupFiles.getEnabled()?"enabled":"disabled"));
  
 -    if (value == JalviewFileChooser.APPROVE_OPTION)
 +    boolean approveSave = false;
 +    if (!autoSave)
      {
 -      final Desktop me = this;
 -      final java.io.File choice = chooser.getSelectedFile();
 -      setProjectFile(choice);
 +      JalviewFileChooser chooser = new JalviewFileChooser("jvp",
 +              "Jalview Project");
  
 +      chooser.setFileView(new JalviewFileView());
 +      chooser.setDialogTitle(MessageManager.getString("label.save_state"));
 +
 +      int value = chooser.showSaveDialog(this);
 +
 +      if (value == JalviewFileChooser.APPROVE_OPTION)
 +      {
 +        projectFile = chooser.getSelectedFile();
 +        setProjectFile(projectFile);
 +        approveSave = true;
 +      }
 +    }
 +
 +    if (approveSave || autoSave)
 +    {
 +      final Desktop me = this;
 +      final java.io.File chosenFile = projectFile;
        new Thread(new Runnable()
        {
          @Override
            // TODO: refactor to Jalview desktop session controller action.
            setProgressBar(MessageManager.formatMessage(
                    "label.saving_jalview_project", new Object[]
 -                  { choice.getName() }), choice.hashCode());
 +                  { chosenFile.getName() }), chosenFile.hashCode());
            jalview.bin.Cache.setProperty("LAST_DIRECTORY",
 -                  choice.getParent());
 +                  chosenFile.getParent());
            // TODO catch and handle errors for savestate
            // TODO prevent user from messing with the Desktop whilst we're saving
            try
            {
 -            new Jalview2XML().saveState(choice);
 +            BackupFiles backupfiles = new BackupFiles(chosenFile);
 +
 +            new Jalview2XML().saveState(backupfiles.getTempFile());
 +
 +            backupfiles.setWriteSuccess(true);
 +            backupfiles.rollBackupsAndRenameTempFile();
            } catch (OutOfMemoryError oom)
            {
 -            new OOMWarning(
 -                    "Whilst saving current state to " + choice.getName(),
 -                    oom);
 +            new OOMWarning("Whilst saving current state to "
 +                    + chosenFile.getName(), oom);
            } catch (Exception ex)
            {
 -            Cache.log.error(
 -                    "Problems whilst trying to save to " + choice.getName(),
 -                    ex);
 +            Cache.log.error("Problems whilst trying to save to "
 +                    + chosenFile.getName(), ex);
              JvOptionPane.showMessageDialog(me,
                      MessageManager.formatMessage(
                              "label.error_whilst_saving_current_state_to",
                              new Object[]
 -                            { choice.getName() }),
 +                            { chosenFile.getName() }),
                      MessageManager.getString("label.couldnt_save_project"),
                      JvOptionPane.WARNING_MESSAGE);
            }
 -          setProgressBar(null, choice.hashCode());
 +          setProgressBar(null, chosenFile.hashCode());
          }
        }).start();
      }
    }
  
 +  @Override
 +  public void saveAsState_actionPerformed(ActionEvent e)
 +  {
 +    saveState_actionPerformed(true);
 +  }
 +
    private void setProjectFile(File choice)
    {
      this.projectFile = choice;
          "Jalview Project (old)" };
      JalviewFileChooser chooser = new JalviewFileChooser(
              Cache.getProperty("LAST_DIRECTORY"), suffix, desc,
 -            "Jalview Project");
 +            "Jalview Project", true, true); // last two booleans: allFiles,
 +                                            // allowBackupFiles
      chooser.setFileView(new JalviewFileView());
      chooser.setDialogTitle(MessageManager.getString("label.restore_state"));
  
            while (li.hasNext())
            {
              String link = li.next();
-             if (link.contains(SEQUENCE_ID)
+             if (link.contains(jalview.util.UrlConstants.SEQUENCE_ID)
                      && !UrlConstants.isDefaultString(link))
              {
                check = true;
@@@ -193,6 -193,9 +193,9 @@@ public class FileLoader implements Runn
          Thread.sleep(500);
        } catch (Exception ex)
        {
+         System.out.println(
+                 "Exception caught while waiting for FileLoader thread");
+         ex.printStackTrace();
        }
      }
  
                alignFrame.getViewport()
                        .applyFeaturesStyle(proxyColourScheme);
              }
 -            alignFrame.statusBar.setText(MessageManager.formatMessage(
 +            alignFrame.setStatus(MessageManager.formatMessage(
                      "label.successfully_loaded_file", new String[]
                      { title }));
  
@@@ -76,8 -76,6 +76,8 @@@ public class GDesktop extends JFram
  
    JMenuItem saveState = new JMenuItem();
  
 +  JMenuItem saveAsState = new JMenuItem();
 +
    JMenuItem loadState = new JMenuItem();
  
    JMenu inputMenu = new JMenu();
          saveState_actionPerformed();
        }
      });
 +    saveAsState.setText(MessageManager.getString("action.save_project_as"));
 +    saveAsState.addActionListener(new ActionListener()
 +    {
 +      @Override
 +      public void actionPerformed(ActionEvent e)
 +      {
 +        saveAsState_actionPerformed(e);
 +      }
 +    });
      loadState.setText(MessageManager.getString("action.load_project"));
      loadState.addActionListener(new ActionListener()
      {
      FileMenu.add(inputSequence);
      FileMenu.addSeparator();
      FileMenu.add(saveState);
 +    FileMenu.add(saveAsState);
      FileMenu.add(loadState);
      FileMenu.addSeparator();
      FileMenu.add(quit);
      VamsasMenu.add(vamsasImport);
      VamsasMenu.add(vamsasSave);
      VamsasMenu.add(vamsasStop);
-     toolsMenu.add(preferences);
+     if (!Platform.isAMac())
+     {
+       toolsMenu.add(preferences);
+     }
      toolsMenu.add(showMemusage);
      toolsMenu.add(showConsole);
      toolsMenu.add(showNews);
     */
    protected void quit()
    {
+     System.out.println("********** GDesktop.quit()");
    }
  
    /**
    {
    }
  
 +  public void saveAsState_actionPerformed(ActionEvent e)
 +  {
 +  }
 +
 +  /**
 +   * DOCUMENT ME!
 +   * 
 +   * @param e
 +   *          DOCUMENT ME!
 +   */
    public void loadState_actionPerformed()
    {
    }
@@@ -48,7 -48,8 +48,8 @@@ public class CommandLineOperation
      JvOptionPane.setMockResponse(JvOptionPane.CANCEL_OPTION);
    }
  
-   private static final int TEST_TIMEOUT = 9000; // Note longer timeout needed on
+   private static final int TEST_TIMEOUT = 9000; // Note longer timeout needed
+                                                 // on
                                                  // full test run than on
                                                  // individual tests
  
      }
      return classpath;
    }
    private Worker jalviewDesktopRunner(boolean withAwt, String cmd,
            int timeout)
    {
      // Note: JAL-3065 - don't include quotes for lib/* because the arguments are
      // not expanded by the shell
      String classpath = getClassPath();
-     String _cmd = "java "
-             + (withAwt ? "-Djava.awt.headless=true" : "")
+     String _cmd = "java " + (withAwt ? "-Djava.awt.headless=true" : "")
              + " -classpath " + classpath + " jalview.bin.Jalview ";
      Process ls2_proc = null;
      Worker worker = null;
    }
  
    @Test(
-     groups = { "Functional" },
+     groups =
+     { "Functional", "testben" },
      dataProvider = "headlessModeOutputOperationsData")
    public void testHeadlessModeOutputOperations(String harg, String type,
            String fileName, boolean withAWT, int expectedMinFileSize,
      File file = new File(fileName);
      Worker worker = jalviewDesktopRunner(withAWT, cmd, timeout);
  
-     FileAssert.assertFile(file, "Didn't create an output" + type
-             + " file.[" + harg + "]");
-     FileAssert.assertMinLength(new File(fileName), expectedMinFileSize);
+     FileAssert.assertFile(file,
+             "Didn't create an output" + type + " file.[" + harg + "]");
+     // System.out.println( "File '" + file.getName() + "' has size " +
+     // file.length());
+     // FileAssert.assertMinLength(new File(fileName), expectedMinFileSize);
+     FileAssert.assertMinLength(file, expectedMinFileSize);
      if (worker != null && worker.exit == null)
      {
        worker.interrupt();
        Thread.currentThread().interrupt();
        worker.process.destroy();
-       Assert.fail("Jalview did not exit after "
-               + type
+       Assert.fail("Jalview did not exit after " + type
                + " generation (try running test again to verify - timeout at "
-               + SETUP_TIMEOUT + "ms). ["
-               + harg + "]");
+               + timeout + "ms). [" + harg + "]");
      }
      new File(fileName).delete();
    }
              "Failed command : -props File" },
          { "CMD [-sortbytree] executed successfully!",
              "Failed command : -sortbytree" },
-         {
-             "CMD [-jabaws http://www.compbio.dundee.ac.uk/jabaws] executed successfully!",
+         { "CMD [-jabaws http://www.compbio.dundee.ac.uk/jabaws] executed successfully!",
              "Failed command : -jabaws http://www.compbio.dundee.ac.uk/jabaws" },
          { "CMD [-open examples/uniref50.fa] executed successfully!",
              "Failed command : -open examples/uniref50.fa" },
          { "CMD [-nosortbytree] executed successfully!",
              "Failed command : -nosortbytree" },
 -        { "CMD [-dasserver nickname=www.test.com] executed successfully!",
 -            "Failed command : -dasserver nickname=www.test.com" },
 -        { "CMD [-features examples/testdata/plantfdx.features]  executed successfully!",
 +        {
 +            "CMD [-features examples/testdata/plantfdx.features]  executed successfully!",
              "Failed command : -features examples/testdata/plantfdx.features" },
-         {
-             "CMD [-annotations examples/testdata/plantfdx.annotations] executed successfully!",
+         { "CMD [-annotations examples/testdata/plantfdx.annotations] executed successfully!",
              "Failed command : -annotations examples/testdata/plantfdx.annotations" },
-         {
-             "CMD [-tree examples/testdata/uniref50_test_tree] executed successfully!",
+         { "CMD [-tree examples/testdata/uniref50_test_tree] executed successfully!",
              "Failed command : -tree examples/testdata/uniref50_test_tree" },
          // non headless mode input operations
          { "CMD [-nousagestats] executed successfully!",
              "Failed command : -nousagestats" },
          { "CMD [-noquestionnaire] executed successfully!",
 -            "Failed command : -noquestionnaire nickname=www.test.com" } };
 +            "Failed command : -noquestionnaire" } };
  
    }
  
          { "headless -open examples/uniref50.fa", " -html",
              "test_uniref50_out.html", true, MINFILESIZE_BIG, TEST_TIMEOUT },
          { "headless -open examples/uniref50.fa", " -fasta",
-             "test_uniref50_out.mfa", true, MINFILESIZE_SMALL, TEST_TIMEOUT },
+             "test_uniref50_out.mfa", true, MINFILESIZE_SMALL,
+             TEST_TIMEOUT },
          { "headless -open examples/uniref50.fa", " -clustal",
-             "test_uniref50_out.aln", true, MINFILESIZE_SMALL, TEST_TIMEOUT },
+             "test_uniref50_out.aln", true, MINFILESIZE_SMALL,
+             TEST_TIMEOUT },
          { "headless -open examples/uniref50.fa", " -msf",
-             "test_uniref50_out.msf", true, MINFILESIZE_SMALL, TEST_TIMEOUT },
+             "test_uniref50_out.msf", true, MINFILESIZE_SMALL,
+             TEST_TIMEOUT },
          { "headless -open examples/uniref50.fa", " -pileup",
-             "test_uniref50_out.aln", true, MINFILESIZE_SMALL, TEST_TIMEOUT },
+             "test_uniref50_out.aln", true, MINFILESIZE_SMALL,
+             TEST_TIMEOUT },
          { "headless -open examples/uniref50.fa", " -pir",
-             "test_uniref50_out.pir", true, MINFILESIZE_SMALL, TEST_TIMEOUT },
+             "test_uniref50_out.pir", true, MINFILESIZE_SMALL,
+             TEST_TIMEOUT },
          { "headless -open examples/uniref50.fa", " -pfam",
-             "test_uniref50_out.pfam", true, MINFILESIZE_SMALL, TEST_TIMEOUT },
+             "test_uniref50_out.pfam", true, MINFILESIZE_SMALL,
+             TEST_TIMEOUT },
          { "headless -open examples/uniref50.fa", " -blc",
-             "test_uniref50_out.blc", true, MINFILESIZE_SMALL, TEST_TIMEOUT },
+             "test_uniref50_out.blc", true, MINFILESIZE_SMALL,
+             TEST_TIMEOUT },
          { "headless -open examples/uniref50.fa", " -jalview",
-             "test_uniref50_out.jvp", true, MINFILESIZE_SMALL, TEST_TIMEOUT }, };
+             "test_uniref50_out.jvp", true, MINFILESIZE_SMALL,
+             TEST_TIMEOUT }, };
    }
  }