Merge branch 'feature/JAL-3127_seqidChainshading' into merge/JAL-3127
authorgmungoc <g.m.carstairs@dundee.ac.uk>
Mon, 11 Mar 2019 11:37:58 +0000 (11:37 +0000)
committergmungoc <g.m.carstairs@dundee.ac.uk>
Mon, 11 Mar 2019 11:37:58 +0000 (11:37 +0000)
Conflicts:
src/jalview/gui/Jalview2XML.java
src/jalview/gui/Jalview2XML_V1.java
test/jalview/io/Jalview2xmlTests.java

14 files changed:
1  2 
resources/lang/Messages.properties
resources/lang/Messages_es.properties
src/jalview/bin/Jalview.java
src/jalview/gui/AlignFrame.java
src/jalview/gui/AlignViewport.java
src/jalview/gui/AlignmentPanel.java
src/jalview/gui/AnnotationColourChooser.java
src/jalview/gui/PopupMenu.java
src/jalview/gui/TreeCanvas.java
src/jalview/project/Jalview2XML.java
src/jalview/schemes/AnnotationColourGradient.java
src/jalview/viewmodel/AlignmentViewport.java
test/jalview/project/Jalview2xmlTests.java
test/jalview/schemes/AnnotationColourGradientTest.java

@@@ -30,7 -30,6 +30,7 @@@ 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
  action.expand_views = Expand Views
  action.gather_views = Gather Views
@@@ -119,8 -118,10 +119,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 -140,7 +139,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 -162,7 +160,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 -172,10 +169,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,6 -203,7 +199,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
@@@ -349,6 -354,7 +350,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...
@@@ -366,6 -372,7 +367,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
@@@ -403,11 -410,14 +404,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
@@@ -419,6 -429,8 +420,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
@@@ -491,10 -503,6 +492,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
@@@ -615,6 -623,7 +616,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
@@@ -630,6 -639,10 +631,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
@@@ -698,6 -711,9 +699,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...
@@@ -756,7 -772,7 +757,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}
@@@ -838,6 -854,7 +839,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}
@@@ -863,6 -880,7 +864,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
@@@ -1062,6 -1080,8 +1063,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
@@@ -1116,6 -1136,10 +1117,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
@@@ -1138,6 -1162,8 +1139,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
@@@ -1259,6 -1285,7 +1260,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:
@@@ -1273,6 -1300,7 +1274,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
@@@ -1325,6 -1353,7 +1326,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
@@@ -1335,60 -1364,3 +1336,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,7 -30,6 +30,7 @@@ 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
  action.expand_views = Expandir vistas
  action.gather_views = Capturar vistas
@@@ -116,8 -115,10 +116,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 -137,7 +136,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 -159,7 +157,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 -169,10 +166,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,6 -199,7 +195,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
@@@ -318,6 -323,7 +319,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
@@@ -334,6 -340,7 +335,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
@@@ -370,6 -377,9 +371,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.
@@@ -386,6 -396,8 +387,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
@@@ -457,10 -469,6 +458,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)! 
@@@ -570,6 -578,7 +571,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
@@@ -582,6 -591,10 +583,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
@@@ -644,6 -657,9 +645,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
@@@ -685,7 -701,7 +686,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}
@@@ -763,6 -779,7 +764,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}
@@@ -788,6 -805,7 +789,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
@@@ -987,6 -1005,8 +988,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
@@@ -1038,6 -1058,10 +1039,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
@@@ -1054,6 -1078,8 +1055,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
@@@ -1260,6 -1286,7 +1261,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:
@@@ -1274,6 -1301,7 +1275,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
@@@ -1326,6 -1354,7 +1327,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
@@@ -1336,60 -1365,3 +1337,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
@@@ -391,7 -391,10 +391,7 @@@ public class Jalvie
      FileFormatI format = null;
      DataSourceType protocol = null;
      FileLoader fileLoader = new FileLoader(!headless);
 -    Vector<String> getFeatures = null; // vector of das source nicknames to
 -                                       // fetch
 -    // features from
 -    // loading is done.
 +
      String groovyscript = null; // script to execute after all loading is
      // completed one way or another
      // extract groovy argument and execute if necessary
            data.replaceAll("%20", " ");
  
            ColourSchemeI cs = ColourSchemeProperty
-                   .getColourScheme(af.getViewport().getAlignment(), data);
+                   .getColourScheme(af.getViewport(),
+                           af.getViewport().getAlignment(), data);
  
            if (cs != null)
            {
          // TODO - load PDB structure(s) to alignment JAL-629
          // (associate with identical sequence in alignment, or a specified
          // sequence)
 -
 -        getFeatures = checkDasArguments(aparser);
 -        if (af != null && getFeatures != null)
 -        {
 -          FeatureFetcher ff = startFeatureFetching(getFeatures);
 -          if (ff != null)
 -          {
 -            while (!ff.allFinished() || af.operationInProgress())
 -            {
 -              // wait around until fetching is finished.
 -              try
 -              {
 -                Thread.sleep(100);
 -              } catch (Exception e)
 -              {
 -
 -              }
 -            }
 -          }
 -          getFeatures = null; // have retrieved features - forget them now.
 -        }
          if (groovyscript != null)
          {
            // Execute the groovy script after we've done all the rendering stuff
  
        startUpAlframe = fileLoader.LoadFileWaitTillLoaded(file, protocol,
                format);
 -      getFeatures = checkDasArguments(aparser);
        // extract groovy arguments before anything else.
      }
 -    // If the user has specified features to be retrieved,
 -    // or a groovy script to be executed, do them if they
 -    // haven't been done already
 -    // fetch features for the default alignment
 -    if (getFeatures != null)
 -    {
 -      if (startUpAlframe != null)
 -      {
 -        startFeatureFetching(getFeatures);
 -      }
 -    }
 +
      // Once all other stuff is done, execute any groovy scripts (in order)
      if (groovyscript != null)
      {
                      // (quote the 'PROPERTY=VALUE' pair to ensure spaces are
                      // passed in correctly)"
                      + "-jabaws URL\tSpecify URL for Jabaws services (e.g. for a local installation).\n"
 -                    + "-dasserver nickname=URL\tAdd and enable a das server with given nickname\n\t\t\t(alphanumeric or underscores only) for retrieval of features for all alignments.\n"
 -                    + "\t\t\tSources that also support the sequence command may be specified by prepending the URL with sequence:\n"
 -                    + "\t\t\t e.g. sequence:http://localdas.somewhere.org/das/source)\n"
                      + "-fetchfrom nickname\tQuery nickname for features for the alignments and display them.\n"
                      // +
                      // "-vdoc vamsas-document\tImport vamsas document into new
      }
    }
  
 -  /**
 -   * Check commandline for any das server definitions or any fetchfrom switches
 -   * 
 -   * @return vector of DAS source nicknames to retrieve from
 -   */
 -  private static Vector<String> checkDasArguments(ArgsParser aparser)
 -  {
 -    Vector<String> source = null;
 -    String data;
 -    String locsources = Cache.getProperty(Cache.DAS_LOCAL_SOURCE);
 -    while ((data = aparser.getValue("dasserver", true)) != null)
 -    {
 -      String nickname = null;
 -      String url = null;
 -      int pos = data.indexOf('=');
 -      // determine capabilities
 -      if (pos > 0)
 -      {
 -        nickname = data.substring(0, pos);
 -      }
 -      url = data.substring(pos + 1);
 -      if (url != null && (url.startsWith("http:")
 -              || url.startsWith("sequence:http:")))
 -      {
 -        if (nickname == null)
 -        {
 -          nickname = url;
 -        }
 -        if (locsources == null)
 -        {
 -          locsources = "";
 -        }
 -        else
 -        {
 -          locsources += "\t";
 -        }
 -        locsources = locsources + nickname + "|" + url;
 -        System.err.println(
 -                "NOTE! dasserver parameter not yet really supported (got args of "
 -                        + nickname + "|" + url);
 -        if (source == null)
 -        {
 -          source = new Vector<>();
 -        }
 -        source.addElement(nickname);
 -      }
 -      System.out.println(
 -              "CMD [-dasserver " + data + "] executed successfully!");
 -    } // loop until no more server entries are found.
 -    if (locsources != null && locsources.indexOf('|') > -1)
 -    {
 -      Cache.log.debug("Setting local source list in properties file to:\n"
 -              + locsources);
 -      Cache.setProperty(Cache.DAS_LOCAL_SOURCE, locsources);
 -    }
 -    while ((data = aparser.getValue("fetchfrom", true)) != null)
 -    {
 -      System.out.println("adding source '" + data + "'");
 -      if (source == null)
 -      {
 -        source = new Vector<>();
 -      }
 -      source.addElement(data);
 -    }
 -    return source;
 -  }
 -
 -  /**
 -   * start a feature fetcher for every alignment frame
 -   * 
 -   * @param dasSources
 -   */
 -  private FeatureFetcher startFeatureFetching(
 -          final Vector<String> dasSources)
 -  {
 -    FeatureFetcher ff = new FeatureFetcher();
 -    AlignFrame afs[] = Desktop.getAlignFrames();
 -    if (afs == null || afs.length == 0)
 -    {
 -      return null;
 -    }
 -    for (int i = 0; i < afs.length; i++)
 -    {
 -      ff.addFetcher(afs[i], dasSources);
 -    }
 -    return ff;
 -  }
 -
    public static boolean isHeadlessMode()
    {
      String isheadless = System.getProperty("java.awt.headless");
@@@ -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;
@@@ -736,9 -733,9 +736,9 @@@ public class AlignFrame extends GAlignF
  
      int aSize = alignPanels.size();
  
 -    tabbedPane.setVisible(aSize > 1 || ap.av.viewName != null);
 +    tabbedPane.setVisible(aSize > 1 || ap.av.getViewName() != null);
  
 -    if (aSize == 1 && ap.av.viewName == null)
 +    if (aSize == 1 && ap.av.getViewName() == null)
      {
        this.getContentPane().add(ap, BorderLayout.CENTER);
      }
  
        expandViews.setEnabled(true);
        gatherViews.setEnabled(true);
 -      tabbedPane.addTab(ap.av.viewName, ap);
 +      tabbedPane.addTab(ap.av.getViewName(), ap);
  
        ap.setVisible(false);
      }
      gatherViews.setEnabled(true);
      tabbedPane.setVisible(true);
      AlignmentPanel first = alignPanels.get(0);
 -    tabbedPane.addTab(first.av.viewName, first);
 +    tabbedPane.addTab(first.av.getViewName(), first);
      this.getContentPane().add(tabbedPane, BorderLayout.CENTER);
    }
  
     * @param av
     *          AlignViewport
     */
 -  void setMenusFromViewport(AlignViewport av)
 +  public void setMenusFromViewport(AlignViewport av)
    {
      padGapsMenuitem.setSelected(av.isPadGaps());
      colourTextMenuItem.setSelected(av.isShowColourText());
      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)
    {
                  shortName.lastIndexOf(java.io.File.separatorChar) + 1);
        }
  
 -      success = new Jalview2XML().saveAlignment(this, file, shortName);
 +      success = new jalview.project.Jalview2XML().saveAlignment(this, file,
 +              shortName);
  
        statusBar.setText(MessageManager.formatMessage(
                "label.successfully_saved_to_file_in_format", new Object[]
        }
        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(backupfiles.getTempFilePath()));
  
            out.print(output);
            out.close();
            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
      /*
       * Create a new AlignmentPanel (with its own, new Viewport)
       */
 -    AlignmentPanel newap = new Jalview2XML().copyAlignPanel(alignPanel);
 +    AlignmentPanel newap = new jalview.project.Jalview2XML()
 +            .copyAlignPanel(alignPanel);
      if (!copyAnnotation)
      {
        /*
  
      newap.av.setGatherViewsHere(false);
  
 -    if (viewport.viewName == null)
 +    if (viewport.getViewName() == null)
      {
 -      viewport.viewName = 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
        newap.refresh(true); // adjust layout of annotations
      }
  
 -    newap.av.viewName = getNewViewName(viewTitle);
 +    newap.av.setViewName(getNewViewName(viewTitle));
  
      addAlignmentPanel(newap, true);
      newap.alignmentChanged();
        if (comp instanceof AlignmentPanel)
        {
          AlignmentPanel ap = (AlignmentPanel) comp;
 -        if (!existingNames.contains(ap.av.viewName))
 +        if (!existingNames.contains(ap.av.getViewName()))
          {
 -          existingNames.add(ap.av.viewName);
 +          existingNames.add(ap.av.getViewName());
          }
        }
      }
      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);
    }
  
      frameTitle += " from ";
  
 -    if (viewport.viewName != null)
 +    if (viewport.getViewName() != null)
      {
 -      frameTitle += viewport.viewName + " of ";
 +      frameTitle += viewport.getViewName() + " of ";
      }
  
      frameTitle += this.title;
     * 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))
        {
  
        if (reply != null)
        {
 -        viewport.viewName = reply;
 +        viewport.setViewName(reply);
          // TODO warn if reply is in getExistingViewNames()?
          tabbedPane.setTitleAt(tabbedPane.getSelectedIndex(), reply);
        }
      {
        PaintRefresher.Refresh(this, viewport.getSequenceSetId());
        alignPanel.updateAnnotation();
-       alignPanel.paintAlignment(true, true);
+       alignPanel.paintAlignment(true,
+               viewport.needToUpdateStructureViews());
      }
    }
  
     */
    public List<? extends AlignmentViewPanel> getAlignPanels()
    {
 -    return alignPanels == null ? Arrays.asList(alignPanel) : alignPanels;
 +    // alignPanels is never null
 +    // return alignPanels == null ? Arrays.asList(alignPanel) : alignPanels;
 +    return alignPanels;
    }
  
    /**
      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);
@@@ -79,7 -79,7 +79,7 @@@ public class AlignViewport extends Alig
  
    private Rectangle explodedGeometry;
  
 -  String viewName;
 +  private String viewName;
  
    /*
     * Flag set true on the view that should 'gather' multiple views of the same
                ResidueColourScheme.NONE);
      }
      ColourSchemeI colourScheme = ColourSchemeProperty
-             .getColourScheme(alignment, schemeName);
+             .getColourScheme(this, alignment, schemeName);
      residueShading = new ResidueShader(colourScheme);
  
      if (colourScheme instanceof UserColourScheme)
      {
        residueShading.setConsensus(hconsensus);
      }
 +    setColourAppliesToAllGroups(true);
    }
  
    boolean validCharWidth;
      AlignFrame newAlignFrame = new AlignFrame(al, AlignFrame.DEFAULT_WIDTH,
              AlignFrame.DEFAULT_HEIGHT);
      newAlignFrame.setTitle(title);
 -    newAlignFrame.statusBar.setText(MessageManager
 +    newAlignFrame.setStatus(MessageManager
              .formatMessage("label.successfully_loaded_file", new Object[]
              { title }));
  
      }
      fr.setTransparency(featureSettings.getTransparency());
    }
 +
 +  public String getViewName()
 +  {
 +    return viewName;
 +  }
 +
 +  public void setViewName(String viewName)
 +  {
 +    this.viewName = viewName;
 +  }
  }
@@@ -328,12 -328,12 +328,12 @@@ public class AlignmentPanel extends GAl
    }
  
    /**
 -   * Highlight the given results on the alignment.
 +   * Highlight the given results on the alignment
     * 
     */
    public void highlightSearchResults(SearchResultsI results)
    {
 -    boolean scrolled = scrollToPosition(results, 0, true, false);
 +    boolean scrolled = scrollToPosition(results, 0, false);
  
      boolean noFastPaint = scrolled && av.getWrapAlignment();
  
     * (if any)
     * 
     * @param searchResults
 -   * @param redrawOverview
     * @return
     */
 -  public boolean scrollToPosition(SearchResultsI searchResults,
 -          boolean redrawOverview)
 +  public boolean scrollToPosition(SearchResultsI searchResults)
    {
 -    return scrollToPosition(searchResults, 0, redrawOverview, false);
 +    return scrollToPosition(searchResults, 0, false);
    }
  
    /**
     * @param verticalOffset
     *          if greater than zero, allows scrolling to a position below the
     *          first displayed sequence
 -   * @param redrawOverview
 -   *          - when set, the overview will be recalculated (takes longer)
     * @param centre
     *          if true, try to centre the search results horizontally in the view
     * @return
     */
    protected boolean scrollToPosition(SearchResultsI results,
 -          int verticalOffset, boolean redrawOverview, boolean centre)
 +          int verticalOffset, boolean centre)
    {
      int startv, endv, starts, ends;
      ViewportRanges ranges = av.getRanges();
        scrollNeeded = ranges.scrollToWrappedVisible(start);
      }
  
 -    paintAlignment(redrawOverview, false);
 +    paintAlignment(false, false);
  
      return scrollNeeded;
    }
      addNotify();
      // TODO: many places call this method and also paintAlignment with various
      // different settings. this means multiple redraws are triggered...
-     paintAlignment(true, false);
+     paintAlignment(true, av.needToUpdateStructureViews());
    }
  
    /**
      }
      else
      {
 -      int width = av.getAlignment().getWidth();
 +      int width = av.getAlignment().getVisibleWidth();
        int height = av.getAlignment().getHeight();
  
 -      if (av.hasHiddenColumns())
 -      {
 -        // reset the width to exclude hidden columns
 -        width = av.getAlignment().getHiddenColumns()
 -                .absoluteToVisibleColumn(width);
 -      }
 -
        hextent = getSeqPanel().seqCanvas.getWidth() / av.getCharWidth();
        vextent = getSeqPanel().seqCanvas.getHeight() / av.getCharHeight();
  
  
      final int totalSeq = (pageHeight - scaleHeight) / charHeight - 1;
  
 -    final int alignmentWidth = av.getAlignment().getWidth();
 -    final int pagesWide = (alignmentWidth / totalRes) + 1;
 +    final int alignmentWidth = av.getAlignment().getVisibleWidth();
 +    int pagesWide = (alignmentWidth / totalRes) + 1;
  
      final int startRes = (pageIndex % pagesWide) * totalRes;
      final int endRes = Math.min(startRes + totalRes - 1,
  
      int idWidth = getVisibleIdWidth(false);
  
 -    int maxwidth = av.getAlignment().getWidth();
 -    if (av.hasHiddenColumns())
 -    {
 -      maxwidth = av.getAlignment().getHiddenColumns()
 -              .absoluteToVisibleColumn(maxwidth) - 1;
 -    }
 +    int maxwidth = av.getAlignment().getVisibleWidth();
  
      int resWidth = getSeqPanel().seqCanvas
              .getWrappedCanvasWidth(pageWidth - idWidth);
  
    public AlignmentDimension getAlignmentDimension()
    {
 -    int maxwidth = av.getAlignment().getWidth();
 -    if (av.hasHiddenColumns())
 -    {
 -      maxwidth = av.getAlignment().getHiddenColumns()
 -              .absoluteToVisibleColumn(maxwidth);
 -    }
 +    int maxwidth = av.getAlignment().getVisibleWidth();
  
      int height = ((av.getAlignment().getHeight() + 1) * av.getCharHeight())
              + getScalePanel().getHeight();
    @Override
    public String getViewName()
    {
 -    return av.viewName;
 +    return av.getViewName();
    }
  
    /**
     */
    protected void scrollToCentre(SearchResultsI sr, int verticalOffset)
    {
 -    scrollToPosition(sr, verticalOffset, true, true);
 +    scrollToPosition(sr, verticalOffset, true);
    }
  
    /**
@@@ -317,7 -317,7 +317,7 @@@ public class AnnotationColourChooser ex
    @Override
    public void reset()
    {
 -    av.setGlobalColourScheme(oldcs);
 +    this.ap.alignFrame.changeColour(oldcs);
      if (av.getAlignment().getGroups() != null)
      {
  
  
      acg.setThresholdIsMinMax(thresholdIsMin.isSelected());
  
 -    av.setGlobalColourScheme(acg);
 +    this.ap.alignFrame.changeColour(acg);
  
      if (av.getAlignment().getGroups() != null)
      {
            continue;
          }
          sg.setColourScheme(
-                 acg.getInstance(sg, ap.av.getHiddenRepSequences()));
+                 acg.getInstance(av, sg));
        }
      }
    }
      super.sliderDragReleased();
      ap.paintAlignment(true, true);
    }
 -
  }
@@@ -46,7 -46,6 +46,7 @@@ import jalview.schemes.Blosum62ColourSc
  import jalview.schemes.ColourSchemeI;
  import jalview.schemes.ColourSchemes;
  import jalview.schemes.PIDColourScheme;
 +import jalview.schemes.ResidueColourScheme;
  import jalview.util.GroupUrlLink;
  import jalview.util.GroupUrlLink.UrlStringTooLongException;
  import jalview.util.MessageManager;
@@@ -69,13 -68,11 +69,13 @@@ import java.util.SortedMap
  import java.util.TreeMap;
  import java.util.Vector;
  
 +import javax.swing.ButtonGroup;
  import javax.swing.JCheckBoxMenuItem;
  import javax.swing.JColorChooser;
  import javax.swing.JMenu;
  import javax.swing.JMenuItem;
  import javax.swing.JPopupMenu;
 +import javax.swing.JRadioButtonMenuItem;
  
  /**
   * DOCUMENT ME!
@@@ -95,8 -92,6 +95,8 @@@ public class PopupMenu extends JPopupMe
  
    protected JCheckBoxMenuItem conservationMenuItem = new JCheckBoxMenuItem();
  
 +  protected JRadioButtonMenuItem annotationColour;
 +
    protected JMenuItem modifyConservation = new JMenuItem();
  
    AlignmentPanel ap;
          }
        }
      }
 -    // for the case when no sequences are even visible
 +
 +    /*
 +     * offer 'Reveal All'
 +     * - in the IdPanel (seq not null) if any sequence is hidden
 +     * - in the IdPanel or SeqPanel if all sequences are hidden (seq is null)
 +     */
      if (alignPanel.av.hasHiddenRows())
      {
 +      boolean addOption = seq != null;
 +      if (!addOption && alignPanel.av.getAlignment().getHeight() == 0)
 +      {
 +        addOption = true;
 +      }
 +      if (addOption)
        {
          menuItem = new JMenuItem(
                  MessageManager.getString("action.reveal_all"));
              }
            }
          });
 -
          add(menuItem);
        }
      }
        }
      });
  
 +    annotationColour = new JRadioButtonMenuItem(
 +            MessageManager.getString("action.by_annotation"));
 +    annotationColour.setName(ResidueColourScheme.ANNOTATION_COLOUR);
 +    annotationColour.setEnabled(false);
 +    annotationColour.setToolTipText(
 +            MessageManager.getString("label.by_annotation_tooltip"));
 +
      modifyConservation.setText(MessageManager
              .getString("label.modify_conservation_threshold"));
      modifyConservation.addActionListener(new ActionListener()
      colourMenu.add(textColour);
      colourMenu.addSeparator();
  
 -    ColourMenuHelper.addMenuItems(colourMenu, this, sg, false);
 +    ButtonGroup bg = ColourMenuHelper.addMenuItems(colourMenu, this, sg,
 +            false);
 +    bg.add(annotationColour);
 +    colourMenu.add(annotationColour);
  
      colourMenu.addSeparator();
      colourMenu.add(conservationMenuItem);
       * switch to the chosen colour scheme (or null for None)
       */
      ColourSchemeI colourScheme = ColourSchemes.getInstance()
-             .getColourScheme(colourSchemeName, sg,
+             .getColourScheme(colourSchemeName, ap.av, sg,
                      ap.av.getHiddenRepSequences());
      sg.setColourScheme(colourScheme);
      if (colourScheme instanceof Blosum62ColourScheme
@@@ -28,11 -28,8 +28,8 @@@ import jalview.datamodel.SequenceGroup
  import jalview.datamodel.SequenceI;
  import jalview.datamodel.SequenceNode;
  import jalview.schemes.ColourSchemeI;
- import jalview.schemes.ColourSchemeProperty;
- import jalview.schemes.UserColourScheme;
  import jalview.structure.SelectionSource;
  import jalview.util.Format;
- import jalview.util.MappingUtils;
  import jalview.util.MessageManager;
  
  import java.awt.Color;
@@@ -80,9 -77,9 +77,9 @@@ public class TreeCanvas extends JPanel 
  
    TreePanel tp;
  
 -  AlignViewport av;
 +  private AlignViewport av;
  
 -  AlignmentPanel ap;
 +  private AlignmentPanel ap;
  
    Font font;
  
  
    int offy;
  
 -  float threshold;
 +  private float threshold;
  
    String longestName;
  
    {
      this.tp = tp;
      this.av = ap.av;
 -    this.ap = ap;
 +    this.setAssociatedPanel(ap);
      font = av.getFont();
      scrollPane = scroller;
      addMouseListener(this);
        return;
      }
  
-     if ((node.left() == null) && (node.right() == null)) // TODO: internal node
+     node.color = c;
+     if (node.element() instanceof SequenceI)
      {
-       node.color = c;
-       if (node.element() instanceof SequenceI)
+       final SequenceI seq = (SequenceI) node.element();
+       AlignmentPanel[] aps = getAssociatedPanels();
+       if (aps != null)
        {
-         AlignmentPanel[] aps = getAssociatedPanels();
-         if (aps != null)
+         for (int a = 0; a < aps.length; a++)
          {
-           for (int a = 0; a < aps.length; a++)
-           {
-             final SequenceI seq = (SequenceI) node.element();
-             aps[a].av.setSequenceColour(seq, c);
-           }
+           aps[a].av.setSequenceColour(seq, c);
          }
        }
      }
-     else
-     {
-       node.color = c;
-       setColor((SequenceNode) node.left(), c);
-       setColor((SequenceNode) node.right(), c);
-     }
+     setColor((SequenceNode) node.left(), c);
+     setColor((SequenceNode) node.right(), c);
    }
  
    /**
      if (col != null)
      {
        setColor(highlightNode, col);
 -      PaintRefresher.Refresh(tp, ap.av.getSequenceSetId());
 +      PaintRefresher.Refresh(tp, getAssociatedPanel().av.getSequenceSetId());
        repaint();
      }
    }
      if (ob instanceof SequenceI)
      {
        treeSelectionChanged((Sequence) ob);
 -      PaintRefresher.Refresh(tp, ap.av.getSequenceSetId());
 +      PaintRefresher.Refresh(tp, getAssociatedPanel().av.getSequenceSetId());
        repaint();
        av.sendSelection();
        return;
                      .deleteAllGroups();
              aps[a].av.getCodingComplement().clearSequenceColours();
            }
+           aps[a].av.setUpdateStructures(true);
          }
          colourGroups(groups);
  
          }
        }
  
 -      PaintRefresher.Refresh(tp, ap.av.getSequenceSetId());
 +      PaintRefresher.Refresh(tp, getAssociatedPanel().av.getSequenceSetId());
        repaint();
      }
  
        }
  
        ColourSchemeI cs = null;
-       SequenceGroup sg = new SequenceGroup(sequences, null, cs, true, true,
+       SequenceGroup _sg = new SequenceGroup(sequences, null, cs, true, true,
                false, 0, av.getAlignment().getWidth() - 1);
  
-       if (av.getGlobalColourScheme() != null)
-       {
-         if (av.getGlobalColourScheme() instanceof UserColourScheme)
-         {
-           cs = new UserColourScheme(
-                   ((UserColourScheme) av.getGlobalColourScheme())
-                           .getColours());
-         }
-         else
-         {
-           cs = ColourSchemeProperty.getColourScheme(sg, ColourSchemeProperty
-                   .getColourName(av.getGlobalColourScheme()));
-         }
-         // cs is null if shading is an annotationColourGradient
-         // if (cs != null)
-         // {
-         // cs.setThreshold(av.getViewportColourScheme().getThreshold(),
-         // av.isIgnoreGapsConsensus());
-         // }
-       }
-       sg.setColourScheme(cs);
-       sg.getGroupColourScheme().setThreshold(
-               av.getResidueShading().getThreshold(),
-               av.isIgnoreGapsConsensus());
-       // sg.recalcConservation();
-       sg.setName("JTreeGroup:" + sg.hashCode());
-       sg.setIdColour(col);
+       _sg.setName("JTreeGroup:" + _sg.hashCode());
+       _sg.setIdColour(col);
  
        for (int a = 0; a < aps.length; a++)
        {
-         if (aps[a].av.getGlobalColourScheme() != null
-                 && aps[a].av.getResidueShading().conservationApplied())
-         {
-           Conservation c = new Conservation("Group", sg.getSequences(null),
-                   sg.getStartRes(), sg.getEndRes());
-           c.calculate();
-           c.verdict(false, aps[a].av.getConsPercGaps());
-           sg.cs.setConservation(c);
-         }
+         SequenceGroup sg = new SequenceGroup(_sg);
+         AlignViewport viewport = aps[a].av;
  
-         aps[a].av.getAlignment().addGroup(new SequenceGroup(sg));
-         // TODO can we push all of the below into AlignViewportI?
-         final AlignViewportI codingComplement = aps[a].av
-                 .getCodingComplement();
-         if (codingComplement != null)
+         // Propagate group colours in each view
+         if (viewport.getGlobalColourScheme() != null)
          {
-           SequenceGroup mappedGroup = MappingUtils.mapSequenceGroup(sg, av,
-                   codingComplement);
-           if (mappedGroup.getSequences().size() > 0)
+           cs = viewport.getGlobalColourScheme().getInstance(viewport, sg);
+           sg.setColourScheme(cs);
+           sg.getGroupColourScheme().setThreshold(
+                   viewport.getResidueShading().getThreshold(),
+                   viewport.isIgnoreGapsConsensus());
+           if (viewport.getResidueShading().conservationApplied())
            {
-             codingComplement.getAlignment().addGroup(mappedGroup);
-             for (SequenceI seq : mappedGroup.getSequences())
-             {
-               codingComplement.setSequenceColour(seq, col.brighter());
-             }
+             Conservation c = new Conservation("Group",
+                     sg.getSequences(null), sg.getStartRes(),
+                     sg.getEndRes());
+             c.calculate();
+             c.verdict(false, viewport.getConsPercGaps());
+             sg.cs.setConservation(c);
            }
          }
+         // indicate that associated structure views will need an update
+         viewport.setUpdateStructures(true);
+         // propagate structure view update and sequence group to complement view
+         viewport.addSequenceGroup(sg);
        }
      }
  
-     // notify the panel(s) to redo any group specific stuff.
+     // notify the panel(s) to redo any group specific stuff
+     // also updates structure views if necessary
      for (int a = 0; a < aps.length; a++)
      {
        aps[a].updateAnnotation();
-       // TODO: JAL-868 - need to ensure view colour change message is broadcast
-       // to any Jmols listening in
        final AlignViewportI codingComplement = aps[a].av
                .getCodingComplement();
        if (codingComplement != null)
      }
      else
      {
 -      return new AlignmentPanel[] { ap };
 +      return new AlignmentPanel[] { getAssociatedPanel() };
      }
    }
 +
 +  public AlignmentPanel getAssociatedPanel()
 +  {
 +    return ap;
 +  }
 +
 +  public void setAssociatedPanel(AlignmentPanel ap)
 +  {
 +    this.ap = ap;
 +  }
 +
 +  public AlignViewport getViewport()
 +  {
 +    return av;
 +  }
 +
 +  public void setViewport(AlignViewport av)
 +  {
 +    this.av = av;
 +  }
 +
 +  public float getThreshold()
 +  {
 +    return threshold;
 +  }
 +
 +  public void setThreshold(float threshold)
 +  {
 +    this.threshold = threshold;
 +  }
 +
 +  public boolean isApplyToAllViews()
 +  {
 +    return this.applyToAllViews;
 +  }
 +
 +  public void setApplyToAllViews(boolean applyToAllViews)
 +  {
 +    this.applyToAllViews = applyToAllViews;
 +  }
  }
   * along with Jalview.  If not, see <http://www.gnu.org/licenses/>.
   * The Jalview Authors are detailed in the 'AUTHORS' file.
   */
 -package jalview.gui;
 +package jalview.project;
 +
 +import static jalview.math.RotatableMatrix.Axis.X;
 +import static jalview.math.RotatableMatrix.Axis.Y;
 +import static jalview.math.RotatableMatrix.Axis.Z;
  
  import jalview.analysis.Conservation;
 +import jalview.analysis.PCA;
 +import jalview.analysis.scoremodels.ScoreModels;
 +import jalview.analysis.scoremodels.SimilarityParams;
  import jalview.api.FeatureColourI;
  import jalview.api.ViewStyleI;
 +import jalview.api.analysis.ScoreModelI;
 +import jalview.api.analysis.SimilarityParamsI;
  import jalview.api.structures.JalviewStructureDisplayI;
  import jalview.bin.Cache;
  import jalview.datamodel.AlignedCodonFrame;
@@@ -40,7 -31,6 +40,7 @@@ import jalview.datamodel.AlignmentAnnot
  import jalview.datamodel.AlignmentI;
  import jalview.datamodel.GraphLine;
  import jalview.datamodel.PDBEntry;
 +import jalview.datamodel.Point;
  import jalview.datamodel.RnaViewerModel;
  import jalview.datamodel.SequenceFeature;
  import jalview.datamodel.SequenceGroup;
@@@ -52,29 -42,49 +52,29 @@@ import jalview.datamodel.features.Featu
  import jalview.datamodel.features.FeatureMatcherSet;
  import jalview.datamodel.features.FeatureMatcherSetI;
  import jalview.ext.varna.RnaModel;
 +import jalview.gui.AlignFrame;
 +import jalview.gui.AlignViewport;
 +import jalview.gui.AlignmentPanel;
 +import jalview.gui.AppVarna;
 +import jalview.gui.ChimeraViewFrame;
 +import jalview.gui.Desktop;
 +import jalview.gui.FeatureRenderer;
 +import jalview.gui.JvOptionPane;
 +import jalview.gui.OOMWarning;
 +import jalview.gui.PCAPanel;
 +import jalview.gui.PaintRefresher;
 +import jalview.gui.SplitFrame;
 +import jalview.gui.StructureViewer;
  import jalview.gui.StructureViewer.ViewerType;
 +import jalview.gui.StructureViewerBase;
 +import jalview.gui.TreePanel;
 +import jalview.io.BackupFiles;
  import jalview.io.DataSourceType;
  import jalview.io.FileFormat;
 +import jalview.io.NewickFile;
 +import jalview.math.Matrix;
 +import jalview.math.MatrixI;
  import jalview.renderer.ResidueShaderI;
 -import jalview.schemabinding.version2.AlcodMap;
 -import jalview.schemabinding.version2.AlcodonFrame;
 -import jalview.schemabinding.version2.Annotation;
 -import jalview.schemabinding.version2.AnnotationColours;
 -import jalview.schemabinding.version2.AnnotationElement;
 -import jalview.schemabinding.version2.CalcIdParam;
 -import jalview.schemabinding.version2.CompoundMatcher;
 -import jalview.schemabinding.version2.DBRef;
 -import jalview.schemabinding.version2.Features;
 -import jalview.schemabinding.version2.Group;
 -import jalview.schemabinding.version2.HiddenColumns;
 -import jalview.schemabinding.version2.JGroup;
 -import jalview.schemabinding.version2.JSeq;
 -import jalview.schemabinding.version2.JalviewModel;
 -import jalview.schemabinding.version2.JalviewModelSequence;
 -import jalview.schemabinding.version2.MapListFrom;
 -import jalview.schemabinding.version2.MapListTo;
 -import jalview.schemabinding.version2.Mapping;
 -import jalview.schemabinding.version2.MappingChoice;
 -import jalview.schemabinding.version2.MatchCondition;
 -import jalview.schemabinding.version2.MatcherSet;
 -import jalview.schemabinding.version2.OtherData;
 -import jalview.schemabinding.version2.PdbentryItem;
 -import jalview.schemabinding.version2.Pdbids;
 -import jalview.schemabinding.version2.Property;
 -import jalview.schemabinding.version2.RnaViewer;
 -import jalview.schemabinding.version2.SecondaryStructure;
 -import jalview.schemabinding.version2.Sequence;
 -import jalview.schemabinding.version2.SequenceSet;
 -import jalview.schemabinding.version2.SequenceSetProperties;
 -import jalview.schemabinding.version2.Setting;
 -import jalview.schemabinding.version2.StructureState;
 -import jalview.schemabinding.version2.ThresholdLine;
 -import jalview.schemabinding.version2.Tree;
 -import jalview.schemabinding.version2.UserColours;
 -import jalview.schemabinding.version2.Viewport;
 -import jalview.schemabinding.version2.types.ColourThreshTypeType;
 -import jalview.schemabinding.version2.types.FeatureMatcherByType;
 -import jalview.schemabinding.version2.types.NoValueColour;
  import jalview.schemes.AnnotationColourGradient;
  import jalview.schemes.ColourSchemeI;
  import jalview.schemes.ColourSchemeProperty;
@@@ -90,7 -100,6 +90,7 @@@ import jalview.util.StringUtils
  import jalview.util.jarInputStreamProvider;
  import jalview.util.matcher.Condition;
  import jalview.viewmodel.AlignmentViewport;
 +import jalview.viewmodel.PCAModel;
  import jalview.viewmodel.ViewportRanges;
  import jalview.viewmodel.seqfeatures.FeatureRendererSettings;
  import jalview.viewmodel.seqfeatures.FeaturesDisplayed;
@@@ -100,56 -109,8 +100,56 @@@ import jalview.ws.jws2.jabaws2.Jws2Inst
  import jalview.ws.params.ArgumentI;
  import jalview.ws.params.AutoCalcSetting;
  import jalview.ws.params.WsParamSetI;
 +import jalview.xml.binding.jalview.AlcodonFrame;
 +import jalview.xml.binding.jalview.AlcodonFrame.AlcodMap;
 +import jalview.xml.binding.jalview.Annotation;
 +import jalview.xml.binding.jalview.Annotation.ThresholdLine;
 +import jalview.xml.binding.jalview.AnnotationColourScheme;
 +import jalview.xml.binding.jalview.AnnotationElement;
 +import jalview.xml.binding.jalview.DoubleMatrix;
 +import jalview.xml.binding.jalview.DoubleVector;
 +import jalview.xml.binding.jalview.Feature;
 +import jalview.xml.binding.jalview.Feature.OtherData;
 +import jalview.xml.binding.jalview.FeatureMatcherSet.CompoundMatcher;
 +import jalview.xml.binding.jalview.FilterBy;
 +import jalview.xml.binding.jalview.JalviewModel;
 +import jalview.xml.binding.jalview.JalviewModel.FeatureSettings;
 +import jalview.xml.binding.jalview.JalviewModel.FeatureSettings.Group;
 +import jalview.xml.binding.jalview.JalviewModel.FeatureSettings.Setting;
 +import jalview.xml.binding.jalview.JalviewModel.JGroup;
 +import jalview.xml.binding.jalview.JalviewModel.JSeq;
 +import jalview.xml.binding.jalview.JalviewModel.JSeq.Pdbids;
 +import jalview.xml.binding.jalview.JalviewModel.JSeq.Pdbids.StructureState;
 +import jalview.xml.binding.jalview.JalviewModel.JSeq.RnaViewer;
 +import jalview.xml.binding.jalview.JalviewModel.JSeq.RnaViewer.SecondaryStructure;
 +import jalview.xml.binding.jalview.JalviewModel.PcaViewer;
 +import jalview.xml.binding.jalview.JalviewModel.PcaViewer.Axis;
 +import jalview.xml.binding.jalview.JalviewModel.PcaViewer.SeqPointMax;
 +import jalview.xml.binding.jalview.JalviewModel.PcaViewer.SeqPointMin;
 +import jalview.xml.binding.jalview.JalviewModel.PcaViewer.SequencePoint;
 +import jalview.xml.binding.jalview.JalviewModel.Tree;
 +import jalview.xml.binding.jalview.JalviewModel.UserColours;
 +import jalview.xml.binding.jalview.JalviewModel.Viewport;
 +import jalview.xml.binding.jalview.JalviewModel.Viewport.CalcIdParam;
 +import jalview.xml.binding.jalview.JalviewModel.Viewport.HiddenColumns;
 +import jalview.xml.binding.jalview.JalviewUserColours;
 +import jalview.xml.binding.jalview.JalviewUserColours.Colour;
 +import jalview.xml.binding.jalview.MapListType.MapListFrom;
 +import jalview.xml.binding.jalview.MapListType.MapListTo;
 +import jalview.xml.binding.jalview.Mapping;
 +import jalview.xml.binding.jalview.NoValueColour;
 +import jalview.xml.binding.jalview.ObjectFactory;
 +import jalview.xml.binding.jalview.PcaDataType;
 +import jalview.xml.binding.jalview.Pdbentry.Property;
 +import jalview.xml.binding.jalview.Sequence;
 +import jalview.xml.binding.jalview.Sequence.DBRef;
 +import jalview.xml.binding.jalview.SequenceSet;
 +import jalview.xml.binding.jalview.SequenceSet.SequenceSetProperties;
 +import jalview.xml.binding.jalview.ThresholdType;
 +import jalview.xml.binding.jalview.VAMSAS;
  
  import java.awt.Color;
 +import java.awt.Font;
  import java.awt.Rectangle;
  import java.io.BufferedReader;
  import java.io.DataInputStream;
@@@ -162,14 -123,12 +162,14 @@@ import java.io.InputStreamReader
  import java.io.OutputStreamWriter;
  import java.io.PrintWriter;
  import java.lang.reflect.InvocationTargetException;
 +import java.math.BigInteger;
  import java.net.MalformedURLException;
  import java.net.URL;
  import java.util.ArrayList;
  import java.util.Arrays;
  import java.util.Collections;
  import java.util.Enumeration;
 +import java.util.GregorianCalendar;
  import java.util.HashMap;
  import java.util.HashSet;
  import java.util.Hashtable;
@@@ -187,14 -146,9 +187,14 @@@ import java.util.jar.JarOutputStream
  
  import javax.swing.JInternalFrame;
  import javax.swing.SwingUtilities;
 -
 -import org.exolab.castor.xml.Marshaller;
 -import org.exolab.castor.xml.Unmarshaller;
 +import javax.xml.bind.JAXBContext;
 +import javax.xml.bind.JAXBElement;
 +import javax.xml.bind.Marshaller;
 +import javax.xml.datatype.DatatypeConfigurationException;
 +import javax.xml.datatype.DatatypeFactory;
 +import javax.xml.datatype.XMLGregorianCalendar;
 +import javax.xml.stream.XMLInputFactory;
 +import javax.xml.stream.XMLStreamReader;
  
  /**
   * Write out the current jalview desktop state as a Jalview XML stream.
@@@ -214,12 -168,6 +214,12 @@@ public class Jalview2XM
  
    private static final String UTF_8 = "UTF-8";
  
 +  /**
 +   * prefix for recovering datasets for alignments with multiple views where
 +   * non-existent dataset IDs were written for some views
 +   */
 +  private static final String UNIQSEQSETID = "uniqueSeqSetId.";
 +
    // use this with nextCounter() to make unique names for entities
    private int counter = 0;
  
    private Map<RnaModel, String> rnaSessions = new HashMap<>();
  
    /**
 +   * A helper method for safely using the value of an optional attribute that
 +   * may be null if not present in the XML. Answers the boolean value, or false
 +   * if null.
 +   * 
 +   * @param b
 +   * @return
 +   */
 +  public static boolean safeBoolean(Boolean b)
 +  {
 +    return b == null ? false : b.booleanValue();
 +  }
 +
 +  /**
 +   * A helper method for safely using the value of an optional attribute that
 +   * may be null if not present in the XML. Answers the integer value, or zero
 +   * if null.
 +   * 
 +   * @param i
 +   * @return
 +   */
 +  public static int safeInt(Integer i)
 +  {
 +    return i == null ? 0 : i.intValue();
 +  }
 +
 +  /**
 +   * A helper method for safely using the value of an optional attribute that
 +   * may be null if not present in the XML. Answers the float value, or zero if
 +   * null.
 +   * 
 +   * @param f
 +   * @return
 +   */
 +  public static float safeFloat(Float f)
 +  {
 +    return f == null ? 0f : f.floatValue();
 +  }
 +
 +  /**
     * create/return unique hash string for sq
     * 
     * @param sq
    public void saveState(File statefile)
    {
      FileOutputStream fos = null;
 +
      try
      {
 +
        fos = new FileOutputStream(statefile);
 +
        JarOutputStream jout = new JarOutputStream(fos);
        saveState(jout);
 +      fos.close();
  
      } catch (Exception e)
      {
 +      Cache.log.error("Couln't write Jalview state to " + statefile, e);
        // TODO: inform user of the problem - they need to know if their data was
        // not saved !
        if (errorMessage == null)
        {
 -        errorMessage = "Couldn't write Jalview Archive to output file '"
 +        errorMessage = "Did't write Jalview Archive to output file '"
                  + statefile + "' - See console error log for details";
        }
        else
        {
 -        errorMessage += "(output file was '" + statefile + "')";
 +        errorMessage += "(Didn't write Jalview Archive to output file '"
 +                + statefile + ")";
        }
        e.printStackTrace();
      } finally
  
          String shortName = makeFilename(af, shortNames);
  
 -        int ap, apSize = af.alignPanels.size();
 +        int apSize = af.getAlignPanels().size();
  
 -        for (ap = 0; ap < apSize; ap++)
 +        for (int ap = 0; ap < apSize; ap++)
          {
 -          AlignmentPanel apanel = af.alignPanels.get(ap);
 +          AlignmentPanel apanel = (AlignmentPanel) af.getAlignPanels()
 +                  .get(ap);
            String fileName = apSize == 1 ? shortName : ap + shortName;
            if (!fileName.endsWith(".xml"))
            {
    {
      try
      {
 -      FileOutputStream fos = new FileOutputStream(jarFile);
 +      // create backupfiles object and get new temp filename destination
 +      BackupFiles backupfiles = new BackupFiles(jarFile);
 +      FileOutputStream fos = new FileOutputStream(
 +              backupfiles.getTempFilePath());
 +
        JarOutputStream jout = new JarOutputStream(fos);
        List<AlignFrame> frames = new ArrayList<>();
  
        }
        ;
        jout.close();
 -      return true;
 +      boolean success = true;
 +
 +      backupfiles.setWriteSuccess(success);
 +      success = backupfiles.rollBackupsAndRenameTempFile();
 +
 +      return success;
      } catch (Exception ex)
      {
        errorMessage = "Couldn't Write alignment view to Jalview Archive - see error output for details";
      AlignViewport av = ap.av;
      ViewportRanges vpRanges = av.getRanges();
  
 -    JalviewModel object = new JalviewModel();
 -    object.setVamsasModel(new jalview.schemabinding.version2.VamsasModel());
 +    final ObjectFactory objectFactory = new ObjectFactory();
 +    JalviewModel object = objectFactory.createJalviewModel();
 +    object.setVamsasModel(new VAMSAS());
  
 -    object.setCreationDate(new java.util.Date(System.currentTimeMillis()));
 +    // object.setCreationDate(new java.util.Date(System.currentTimeMillis()));
 +    try
 +    {
 +      GregorianCalendar c = new GregorianCalendar();
 +      DatatypeFactory datatypeFactory = DatatypeFactory.newInstance();
 +      XMLGregorianCalendar now = datatypeFactory.newXMLGregorianCalendar(c);// gregorianCalendar);
 +      object.setCreationDate(now);
 +    } catch (DatatypeConfigurationException e)
 +    {
 +      System.err.println("error writing date: " + e.toString());
 +    }
      object.setVersion(
              jalview.bin.Cache.getDefault("VERSION", "Development Build"));
  
  
      SequenceSet vamsasSet = new SequenceSet();
      Sequence vamsasSeq;
 -    JalviewModelSequence jms = new JalviewModelSequence();
 +    // JalviewModelSequence jms = new JalviewModelSequence();
  
      vamsasSet.setGapChar(jal.getGapCharacter() + "");
  
          SequenceSetProperties ssp = new SequenceSetProperties();
          ssp.setKey(key);
          ssp.setValue(jal.getProperties().get(key).toString());
 -        vamsasSet.addSequenceSetProperties(ssp);
 +        // vamsasSet.addSequenceSetProperties(ssp);
 +        vamsasSet.getSequenceSetProperties().add(ssp);
        }
      }
  
          else
          {
            vamsasSeq = createVamsasSequence(id, jds);
 -          vamsasSet.addSequence(vamsasSeq);
 +//          vamsasSet.addSequence(vamsasSeq);
 +          vamsasSet.getSequence().add(vamsasSeq);
            vamsasSetIds.put(id, vamsasSeq);
            seqRefIds.put(id, jds);
          }
              {
                if (reps[h] != jds)
                {
 -                jseq.addHiddenSequences(rjal.findIndex(reps[h]));
 +                // jseq.addHiddenSequences(rjal.findIndex(reps[h]));
 +                jseq.getHiddenSequences().add(rjal.findIndex(reps[h]));
                }
              }
            }
  
        // TODO: omit sequence features from each alignment view's XML dump if we
        // are storing dataset
 -      List<jalview.datamodel.SequenceFeature> sfs = jds
 -              .getSequenceFeatures();
 +      List<SequenceFeature> sfs = jds.getSequenceFeatures();
        for (SequenceFeature sf : sfs)
        {
 -        Features features = new Features();
 +        // Features features = new Features();
 +        Feature features = new Feature();
  
          features.setBegin(sf.getBegin());
          features.setEnd(sf.getEnd());
              OtherData keyValue = new OtherData();
              keyValue.setKey("LINK_" + l);
              keyValue.setValue(sf.links.elementAt(l).toString());
 -            features.addOtherData(keyValue);
 +            // features.addOtherData(keyValue);
 +            features.getOtherData().add(keyValue);
            }
          }
          if (sf.otherDetails != null)
                  otherData.setKey(key);
                  otherData.setKey2(subAttribute.getKey());
                  otherData.setValue(subAttribute.getValue().toString());
 -                features.addOtherData(otherData);
 +                // features.addOtherData(otherData);
 +                features.getOtherData().add(otherData);
                }
              }
              else
                OtherData otherData = new OtherData();
                otherData.setKey(key);
                otherData.setValue(value.toString());
 -              features.addOtherData(otherData);
 +              // features.addOtherData(otherData);
 +              features.getOtherData().add(otherData);
              }
            }
          }
  
 -        jseq.addFeatures(features);
 +        // jseq.addFeatures(features);
 +        jseq.getFeatures().add(features);
        }
  
        if (jdatasq.getAllPDBEntries() != null)
        {
 -        Enumeration en = jdatasq.getAllPDBEntries().elements();
 +        Enumeration<PDBEntry> en = jdatasq.getAllPDBEntries().elements();
          while (en.hasMoreElements())
          {
            Pdbids pdb = new Pdbids();
 -          jalview.datamodel.PDBEntry entry = (jalview.datamodel.PDBEntry) en
 -                  .nextElement();
 +          jalview.datamodel.PDBEntry entry = en.nextElement();
  
            String pdbId = entry.getId();
            pdb.setId(pdbId);
            Enumeration<String> props = entry.getProperties();
            if (props.hasMoreElements())
            {
 -            PdbentryItem item = new PdbentryItem();
 +            // PdbentryItem item = new PdbentryItem();
              while (props.hasMoreElements())
              {
                Property prop = new Property();
                String key = props.nextElement();
                prop.setName(key);
                prop.setValue(entry.getProperty(key).toString());
 -              item.addProperty(prop);
 +              // item.addProperty(prop);
 +              pdb.getProperty().add(prop);
              }
 -            pdb.addPdbentryItem(item);
 +            // pdb.addPdbentryItem(item);
            }
  
 -          jseq.addPdbids(pdb);
 +          // jseq.addPdbids(pdb);
 +          jseq.getPdbids().add(pdb);
          }
        }
  
        saveRnaViewers(jout, jseq, jds, viewIds, ap, storeDS);
  
 -      jms.addJSeq(jseq);
 +      // jms.addJSeq(jseq);
 +      object.getJSeq().add(jseq);
      }
  
      if (!storeDS && av.hasHiddenRows())
              alcmap.setDnasq(seqHash(dnas[m]));
              alcmap.setMapping(
                      createVamsasMapping(pmaps[m], dnas[m], null, false));
 -            alc.addAlcodMap(alcmap);
 +            // alc.addAlcodMap(alcmap);
 +            alc.getAlcodMap().add(alcmap);
              hasMap = true;
            }
            if (hasMap)
            {
 -            vamsasSet.addAlcodonFrame(alc);
 +            // vamsasSet.addAlcodonFrame(alc);
 +            vamsasSet.getAlcodonFrame().add(alc);
            }
          }
          // TODO: delete this ? dead code from 2.8.3->2.9 ?
            {
              TreePanel tp = (TreePanel) frames[t];
  
 -            if (tp.treeCanvas.av.getAlignment() == jal)
 +            if (tp.getTreeCanvas().getViewport().getAlignment() == jal)
              {
 -              Tree tree = new Tree();
 +              JalviewModel.Tree tree = new JalviewModel.Tree();
                tree.setTitle(tp.getTitle());
                tree.setCurrentTree((av.getCurrentTree() == tp.getTree()));
                tree.setNewick(tp.getTree().print());
 -              tree.setThreshold(tp.treeCanvas.threshold);
 +              tree.setThreshold(tp.getTreeCanvas().getThreshold());
  
                tree.setFitToWindow(tp.fitToWindow.getState());
                tree.setFontName(tp.getTreeFont().getName());
                tree.setXpos(tp.getX());
                tree.setYpos(tp.getY());
                tree.setId(makeHashCode(tp, null));
 -              jms.addTree(tree);
 +              tree.setLinkToAllViews(
 +                      tp.getTreeCanvas().isApplyToAllViews());
 +
 +              // jms.addTree(tree);
 +              object.getTree().add(tree);
              }
            }
          }
        }
      }
  
 +    /*
 +     * save PCA viewers
 +     */
 +    if (!storeDS && Desktop.desktop != null)
 +    {
 +      for (JInternalFrame frame : Desktop.desktop.getAllFrames())
 +      {
 +        if (frame instanceof PCAPanel)
 +        {
 +          PCAPanel panel = (PCAPanel) frame;
 +          if (panel.getAlignViewport().getAlignment() == jal)
 +          {
 +            savePCA(panel, object);
 +          }
 +        }
 +      }
 +    }
 +
      // SAVE ANNOTATIONS
      /**
       * store forward refs from an annotationRow to any groups
              if (colourScheme instanceof jalview.schemes.UserColourScheme)
              {
                jGroup.setColour(
 -                      setUserColourScheme(colourScheme, userColours, jms));
 +                      setUserColourScheme(colourScheme, userColours,
 +                              object));
              }
              else
              {
              jGroup.setColour("AnnotationColourGradient");
              jGroup.setAnnotationColours(constructAnnotationColours(
                      (jalview.schemes.AnnotationColourGradient) colourScheme,
 -                    userColours, jms));
 +                    userColours, object));
            }
            else if (colourScheme instanceof jalview.schemes.UserColourScheme)
            {
              jGroup.setColour(
 -                    setUserColourScheme(colourScheme, userColours, jms));
 +                    setUserColourScheme(colourScheme, userColours, object));
            }
            else
            {
          jGroup.setNormaliseSequenceLogo(sg.isNormaliseSequenceLogo());
          for (SequenceI seq : sg.getSequences())
          {
 -          jGroup.addSeq(seqHash(seq));
 +          // jGroup.addSeq(seqHash(seq));
 +          jGroup.getSeq().add(seqHash(seq));
          }
        }
  
 -      jms.setJGroup(groups);
 +      //jms.setJGroup(groups);
 +      Object group;
 +      for (JGroup grp : groups)
 +      {
 +        object.getJGroup().add(grp);
 +      }
      }
      if (!storeDS)
      {
        {
          view.setComplementId(av.getCodingComplement().getViewId());
        }
 -      view.setViewName(av.viewName);
 +      view.setViewName(av.getViewName());
        view.setGatheredViews(av.isGatherViewsHere());
  
        Rectangle size = ap.av.getExplodedGeometry();
        if (av.getGlobalColourScheme() instanceof jalview.schemes.UserColourScheme)
        {
          view.setBgColour(setUserColourScheme(av.getGlobalColourScheme(),
 -                userColours, jms));
 +                userColours, object));
        }
        else if (av
                .getGlobalColourScheme() instanceof jalview.schemes.AnnotationColourGradient)
        {
 -        AnnotationColours ac = constructAnnotationColours(
 +        AnnotationColourScheme ac = constructAnnotationColours(
                  (jalview.schemes.AnnotationColourGradient) av
                          .getGlobalColourScheme(),
 -                userColours, jms);
 +                userColours, object);
  
          view.setAnnotationColours(ac);
          view.setBgColour("AnnotationColourGradient");
            view.setConsThreshold(vcs.getConservationInc());
            if (cs instanceof jalview.schemes.UserColourScheme)
            {
 -            view.setBgColour(setUserColourScheme(cs, userColours, jms));
 +            view.setBgColour(setUserColourScheme(cs, userColours, object));
            }
          }
          view.setPidThreshold(vcs.getThreshold());
  
        view.setConservationSelected(av.getConservationSelected());
        view.setPidSelected(av.getAbovePIDThreshold());
 -      view.setFontName(av.font.getName());
 -      view.setFontSize(av.font.getSize());
 -      view.setFontStyle(av.font.getStyle());
 +      final Font font = av.getFont();
 +      view.setFontName(font.getName());
 +      view.setFontSize(font.getSize());
 +      view.setFontStyle(font.getStyle());
        view.setScaleProteinAsCdna(av.getViewStyle().isScaleProteinAsCdna());
        view.setRenderGaps(av.isRenderGaps());
        view.setShowAnnotation(av.isShowAnnotation());
        view.setIgnoreGapsinConsensus(av.isIgnoreGapsConsensus());
        if (av.getFeaturesDisplayed() != null)
        {
 -        jalview.schemabinding.version2.FeatureSettings fs = new jalview.schemabinding.version2.FeatureSettings();
 +        FeatureSettings fs = new FeatureSettings();
  
          FeatureRenderer fr = ap.getSeqPanel().seqCanvas
                  .getFeatureRenderer();
          {
            for (String featureType : renderOrder)
            {
 -            Setting setting = new Setting();
 +            FeatureSettings.Setting setting = new FeatureSettings.Setting();
              setting.setType(featureType);
  
              /*
                setting.setColourByLabel(fcol.isColourByLabel());
                if (fcol.isColourByAttribute())
                {
 -                setting.setAttributeName(fcol.getAttributeName());
 +                String[] attName = fcol.getAttributeName();
 +                setting.getAttributeName().add(attName[0]);
 +                if (attName.length > 1)
 +                {
 +                  setting.getAttributeName().add(attName[1]);
 +                }
                }
                setting.setAutoScale(fcol.isAutoScaled());
                setting.setThreshold(fcol.getThreshold());
              {
                setting.setOrder(rorder);
              }
 -            fs.addSetting(setting);
 +            /// fs.addSetting(setting);
 +            fs.getSetting().add(setting);
              settingsAdded.addElement(featureType);
            }
          }
            g.setName(grp);
            g.setDisplay(((Boolean) fr.checkGroupVisibility(grp, false))
                            .booleanValue());
 -          fs.addGroup(g);
 +          // fs.addGroup(g);
 +          fs.getGroup().add(g);
            groupsAdded.addElement(grp);
          }
 -        jms.setFeatureSettings(fs);
 +        // jms.setFeatureSettings(fs);
 +        object.setFeatureSettings(fs);
        }
  
        if (av.hasHiddenColumns())
              HiddenColumns hc = new HiddenColumns();
              hc.setStart(region[0]);
              hc.setEnd(region[1]);
 -            view.addHiddenColumns(hc);
 +            // view.addHiddenColumns(hc);
 +            view.getHiddenColumns().add(hc);
            }
          }
        }
              // Some calcIds have no parameters.
              if (cidp != null)
              {
 -              view.addCalcIdParam(cidp);
 +              // view.addCalcIdParam(cidp);
 +              view.getCalcIdParam().add(cidp);
              }
            }
          }
        }
  
 -      jms.addViewport(view);
 +      // jms.addViewport(view);
 +      object.getViewport().add(view);
      }
 -    object.setJalviewModelSequence(jms);
 -    object.getVamsasModel().addSequenceSet(vamsasSet);
 +    // object.setJalviewModelSequence(jms);
 +    // object.getVamsasModel().addSequenceSet(vamsasSet);
 +    object.getVamsasModel().getSequenceSet().add(vamsasSet);
  
      if (jout != null && fileName != null)
      {
          jout.putNextEntry(entry);
          PrintWriter pout = new PrintWriter(
                  new OutputStreamWriter(jout, UTF_8));
 -        Marshaller marshaller = new Marshaller(pout);
 -        marshaller.marshal(object);
 +        JAXBContext jaxbContext = JAXBContext
 +                .newInstance(JalviewModel.class);
 +        Marshaller jaxbMarshaller = jaxbContext.createMarshaller();
 +
 +        // output pretty printed
 +        // jaxbMarshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
 +        jaxbMarshaller.marshal(
 +                new ObjectFactory().createJalviewModel(object), pout);
 +
 +        // jaxbMarshaller.marshal(object, pout);
 +        // marshaller.marshal(object);
          pout.flush();
          jout.closeEntry();
        } catch (Exception ex)
        {
          // TODO: raise error in GUI if marshalling failed.
 +        System.err.println("Error writing Jalview project");
          ex.printStackTrace();
        }
      }
    }
  
    /**
 +   * Writes PCA viewer attributes and computed values to an XML model object and
 +   * adds it to the JalviewModel. Any exceptions are reported by logging.
 +   */
 +  protected void savePCA(PCAPanel panel, JalviewModel object)
 +  {
 +    try
 +    {
 +      PcaViewer viewer = new PcaViewer();
 +      viewer.setHeight(panel.getHeight());
 +      viewer.setWidth(panel.getWidth());
 +      viewer.setXpos(panel.getX());
 +      viewer.setYpos(panel.getY());
 +      viewer.setTitle(panel.getTitle());
 +      PCAModel pcaModel = panel.getPcaModel();
 +      viewer.setScoreModelName(pcaModel.getScoreModelName());
 +      viewer.setXDim(panel.getSelectedDimensionIndex(X));
 +      viewer.setYDim(panel.getSelectedDimensionIndex(Y));
 +      viewer.setZDim(panel.getSelectedDimensionIndex(Z));
 +      viewer.setBgColour(
 +              panel.getRotatableCanvas().getBackgroundColour().getRGB());
 +      viewer.setScaleFactor(panel.getRotatableCanvas().getScaleFactor());
 +      float[] spMin = panel.getRotatableCanvas().getSeqMin();
 +      SeqPointMin spmin = new SeqPointMin();
 +      spmin.setXPos(spMin[0]);
 +      spmin.setYPos(spMin[1]);
 +      spmin.setZPos(spMin[2]);
 +      viewer.setSeqPointMin(spmin);
 +      float[] spMax = panel.getRotatableCanvas().getSeqMax();
 +      SeqPointMax spmax = new SeqPointMax();
 +      spmax.setXPos(spMax[0]);
 +      spmax.setYPos(spMax[1]);
 +      spmax.setZPos(spMax[2]);
 +      viewer.setSeqPointMax(spmax);
 +      viewer.setShowLabels(panel.getRotatableCanvas().isShowLabels());
 +      viewer.setLinkToAllViews(
 +              panel.getRotatableCanvas().isApplyToAllViews());
 +      SimilarityParamsI sp = pcaModel.getSimilarityParameters();
 +      viewer.setIncludeGaps(sp.includeGaps());
 +      viewer.setMatchGaps(sp.matchGaps());
 +      viewer.setIncludeGappedColumns(sp.includeGappedColumns());
 +      viewer.setDenominateByShortestLength(sp.denominateByShortestLength());
 +
 +      /*
 +       * sequence points on display
 +       */
 +      for (jalview.datamodel.SequencePoint spt : pcaModel
 +              .getSequencePoints())
 +      {
 +        SequencePoint point = new SequencePoint();
 +        point.setSequenceRef(seqHash(spt.getSequence()));
 +        point.setXPos(spt.coord.x);
 +        point.setYPos(spt.coord.y);
 +        point.setZPos(spt.coord.z);
 +        viewer.getSequencePoint().add(point);
 +      }
 +
 +      /*
 +       * (end points of) axes on display
 +       */
 +      for (Point p : panel.getRotatableCanvas().getAxisEndPoints())
 +      {
 +
 +        Axis axis = new Axis();
 +        axis.setXPos(p.x);
 +        axis.setYPos(p.y);
 +        axis.setZPos(p.z);
 +        viewer.getAxis().add(axis);
 +      }
 +
 +      /*
 +       * raw PCA data (note we are not restoring PCA inputs here -
 +       * alignment view, score model, similarity parameters)
 +       */
 +      PcaDataType data = new PcaDataType();
 +      viewer.setPcaData(data);
 +      PCA pca = pcaModel.getPcaData();
 +
 +      DoubleMatrix pm = new DoubleMatrix();
 +      saveDoubleMatrix(pca.getPairwiseScores(), pm);
 +      data.setPairwiseMatrix(pm);
 +
 +      DoubleMatrix tm = new DoubleMatrix();
 +      saveDoubleMatrix(pca.getTridiagonal(), tm);
 +      data.setTridiagonalMatrix(tm);
 +
 +      DoubleMatrix eigenMatrix = new DoubleMatrix();
 +      data.setEigenMatrix(eigenMatrix);
 +      saveDoubleMatrix(pca.getEigenmatrix(), eigenMatrix);
 +
 +      object.getPcaViewer().add(viewer);
 +    } catch (Throwable t)
 +    {
 +      Cache.log.error("Error saving PCA: " + t.getMessage());
 +    }
 +  }
 +
 +  /**
 +   * Stores values from a matrix into an XML element, including (if present) the
 +   * D or E vectors
 +   * 
 +   * @param m
 +   * @param xmlMatrix
 +   * @see #loadDoubleMatrix(DoubleMatrix)
 +   */
 +  protected void saveDoubleMatrix(MatrixI m, DoubleMatrix xmlMatrix)
 +  {
 +    xmlMatrix.setRows(m.height());
 +    xmlMatrix.setColumns(m.width());
 +    for (int i = 0; i < m.height(); i++)
 +    {
 +      DoubleVector row = new DoubleVector();
 +      for (int j = 0; j < m.width(); j++)
 +      {
 +        row.getV().add(m.getValue(i, j));
 +      }
 +      xmlMatrix.getRow().add(row);
 +    }
 +    if (m.getD() != null)
 +    {
 +      DoubleVector dVector = new DoubleVector();
 +      for (double d : m.getD())
 +      {
 +        dVector.getV().add(d);
 +      }
 +      xmlMatrix.setD(dVector);
 +    }
 +    if (m.getE() != null)
 +    {
 +      DoubleVector eVector = new DoubleVector();
 +      for (double e : m.getE())
 +      {
 +        eVector.getV().add(e);
 +      }
 +      xmlMatrix.setE(eVector);
 +    }
 +  }
 +
 +  /**
 +   * Loads XML matrix data into a new Matrix object, including the D and/or E
 +   * vectors (if present)
 +   * 
 +   * @param mData
 +   * @return
 +   * @see Jalview2XML#saveDoubleMatrix(MatrixI, DoubleMatrix)
 +   */
 +  protected MatrixI loadDoubleMatrix(DoubleMatrix mData)
 +  {
 +    int rows = mData.getRows();
 +    double[][] vals = new double[rows][];
 +
 +    for (int i = 0; i < rows; i++)
 +    {
 +      List<Double> dVector = mData.getRow().get(i).getV();
 +      vals[i] = new double[dVector.size()];
 +      int dvi = 0;
 +      for (Double d : dVector)
 +      {
 +        vals[i][dvi++] = d;
 +      }
 +    }
 +
 +    MatrixI m = new Matrix(vals);
 +
 +    if (mData.getD() != null)
 +    {
 +      List<Double> dVector = mData.getD().getV();
 +      double[] vec = new double[dVector.size()];
 +      int dvi = 0;
 +      for (Double d : dVector)
 +      {
 +        vec[dvi++] = d;
 +      }
 +      m.setD(vec);
 +    }
 +    if (mData.getE() != null)
 +    {
 +      List<Double> dVector = mData.getE().getV();
 +      double[] vec = new double[dVector.size()];
 +      int dvi = 0;
 +      for (Double d : dVector)
 +      {
 +        vec[dvi++] = d;
 +      }
 +      m.setE(vec);
 +    }
 +
 +    return m;
 +  }
 +
 +  /**
     * Save any Varna viewers linked to this sequence. Writes an rnaViewer element
     * for each viewer, with
     * <ul>
            rna.setHeight(varna.getHeight());
            rna.setDividerLocation(varna.getDividerLocation());
            rna.setSelectedRna(varna.getSelectedIndex());
 -          jseq.addRnaViewer(rna);
 +          // jseq.addRnaViewer(rna);
 +          jseq.getRnaViewer().add(rna);
  
            /*
             * Store each Varna panel's state once in the project per sequence.
                ss.setViewerState(jarEntryName);
                ss.setGapped(model.gapped);
                ss.setTitle(model.title);
 -              rna.addSecondaryStructure(ss);
 +              // rna.addSecondaryStructure(ss);
 +              rna.getSecondaryStructure().add(ss);
              }
            }
          }
            state.setColourwithAlignPanel(viewFrame.isUsedforcolourby(ap));
            state.setColourByJmol(viewFrame.isColouredByViewer());
            state.setType(viewFrame.getViewerType().toString());
 -          pdb.addStructureState(state);
 +          // pdb.addStructureState(state);
 +          pdb.getStructureState().add(state);
          }
        }
      }
    }
  
    /**
 -   * Populates the AnnotationColours xml for save. This captures the settings of
 -   * the options in the 'Colour by Annotation' dialog.
 +   * Populates the AnnotationColourScheme xml for save. This captures the
 +   * settings of the options in the 'Colour by Annotation' dialog.
     * 
     * @param acg
     * @param userColours
 -   * @param jms
 +   * @param jm
     * @return
     */
 -  private AnnotationColours constructAnnotationColours(
 +  private AnnotationColourScheme constructAnnotationColours(
            AnnotationColourGradient acg, List<UserColourScheme> userColours,
 -          JalviewModelSequence jms)
 +          JalviewModel jm)
    {
 -    AnnotationColours ac = new AnnotationColours();
 +    AnnotationColourScheme ac = new AnnotationColourScheme();
      ac.setAboveThreshold(acg.getAboveThreshold());
      ac.setThreshold(acg.getAnnotationThreshold());
      // 2.10.2 save annotationId (unique) not annotation label
      if (acg.getBaseColour() instanceof UserColourScheme)
      {
        ac.setColourScheme(
 -              setUserColourScheme(acg.getBaseColour(), userColours, jms));
 +              setUserColourScheme(acg.getBaseColour(), userColours, jm));
      }
      else
      {
        {
          for (String pr : annotation.getProperties())
          {
 -          Property prop = new Property();
 +          jalview.xml.binding.jalview.Annotation.Property prop = new jalview.xml.binding.jalview.Annotation.Property();
            prop.setName(pr);
            prop.setValue(annotation.getProperty(pr));
 -          an.addProperty(prop);
 +          // an.addProperty(prop);
 +          an.getProperty().add(prop);
          }
        }
  
              ae.setColour(annotation.annotations[a].colour.getRGB());
            }
  
 -          an.addAnnotationElement(ae);
 +          // an.addAnnotationElement(ae);
 +          an.getAnnotationElement().add(ae);
            if (annotation.autoCalculated)
            {
              // only write one non-null entry into the annotation row -
        {
          // skip autocalculated annotation - these are only provided for
          // alignments
 -        vamsasSet.addAnnotation(an);
 +        // vamsasSet.addAnnotation(an);
 +        vamsasSet.getAnnotation().add(an);
        }
      }
  
      {
        CalcIdParam vCalcIdParam = new CalcIdParam();
        vCalcIdParam.setCalcId(calcId);
 -      vCalcIdParam.addServiceURL(settings.getServiceURI());
 +      // vCalcIdParam.addServiceURL(settings.getServiceURI());
 +      vCalcIdParam.getServiceURL().add(settings.getServiceURI());
        // generic URI allowing a third party to resolve another instance of the
        // service used for this calculation
 -      for (String urls : settings.getServiceURLs())
 +      for (String url : settings.getServiceURLs())
        {
 -        vCalcIdParam.addServiceURL(urls);
 +        // vCalcIdParam.addServiceURL(urls);
 +        vCalcIdParam.getServiceURL().add(url);
        }
        vCalcIdParam.setVersion("1.0");
        if (settings.getPreset() != null)
    {
      if (calcIdParam.getVersion().equals("1.0"))
      {
 +      final String[] calcIds = calcIdParam.getServiceURL().toArray(new String[0]);
        Jws2Instance service = Jws2Discoverer.getDiscoverer()
 -              .getPreferredServiceFor(calcIdParam.getServiceURL());
 +              .getPreferredServiceFor(calcIds);
        if (service != null)
        {
          WsParamSetI parmSet = null;
          {
            parmSet = service.getParamStore().parseServiceParameterFile(
                    calcIdParam.getName(), calcIdParam.getDescription(),
 -                  calcIdParam.getServiceURL(),
 +                  calcIds,
                    calcIdParam.getParameters().replace("|\\n|", "\n"));
          } catch (IOException x)
          {
                    jds, recurse);
            dbref.setMapping(mp);
          }
 -        vamsasSeq.addDBRef(dbref);
 +        // vamsasSeq.addDBRef(dbref);
 +        vamsasSeq.getDBRef().add(dbref);
        }
      }
      return vamsasSeq;
          MapListFrom mfrom = new MapListFrom();
          mfrom.setStart(range[0]);
          mfrom.setEnd(range[1]);
 -        mp.addMapListFrom(mfrom);
 +        // mp.addMapListFrom(mfrom);
 +        mp.getMapListFrom().add(mfrom);
        }
        r = mlst.getToRanges();
        for (int[] range : r)
          MapListTo mto = new MapListTo();
          mto.setStart(range[0]);
          mto.setEnd(range[1]);
 -        mp.addMapListTo(mto);
 +        // mp.addMapListTo(mto);
 +        mp.getMapListTo().add(mto);
        }
 -      mp.setMapFromUnit(mlst.getFromRatio());
 -      mp.setMapToUnit(mlst.getToRatio());
 +      mp.setMapFromUnit(BigInteger.valueOf(mlst.getFromRatio()));
 +      mp.setMapToUnit(BigInteger.valueOf(mlst.getToRatio()));
        if (jmp.getTo() != null)
        {
 -        MappingChoice mpc = new MappingChoice();
 +        // MappingChoice mpc = new MappingChoice();
  
          // check/create ID for the sequence referenced by getTo()
  
          {
            jmpid = seqHash(ps = parentseq);
          }
 -        mpc.setDseqFor(jmpid);
 -        if (!seqRefIds.containsKey(mpc.getDseqFor()))
 +        // mpc.setDseqFor(jmpid);
 +        mp.setDseqFor(jmpid);
 +        if (!seqRefIds.containsKey(jmpid))
          {
            jalview.bin.Cache.log.debug("creatign new DseqFor ID");
 -          seqRefIds.put(mpc.getDseqFor(), ps);
 +          seqRefIds.put(jmpid, ps);
          }
          else
          {
            jalview.bin.Cache.log.debug("reusing DseqFor ID");
          }
  
 -        mp.setMappingChoice(mpc);
 +        // mp.setMappingChoice(mpc);
        }
      }
      return mp;
    }
  
    String setUserColourScheme(jalview.schemes.ColourSchemeI cs,
 -          List<UserColourScheme> userColours, JalviewModelSequence jms)
 +          List<UserColourScheme> userColours, JalviewModel jm)
    {
      String id = null;
      jalview.schemes.UserColourScheme ucs = (jalview.schemes.UserColourScheme) cs;
      {
        // actually create the scheme's entry in the XML model
        java.awt.Color[] colours = ucs.getColours();
 -      jalview.schemabinding.version2.UserColours uc = new jalview.schemabinding.version2.UserColours();
 -      jalview.schemabinding.version2.UserColourScheme jbucs = new jalview.schemabinding.version2.UserColourScheme();
 +      UserColours uc = new UserColours();
 +      // UserColourScheme jbucs = new UserColourScheme();
 +      JalviewUserColours jbucs = new JalviewUserColours();
  
        for (int i = 0; i < colours.length; i++)
        {
 -        jalview.schemabinding.version2.Colour col = new jalview.schemabinding.version2.Colour();
 +        Colour col = new Colour();
          col.setName(ResidueProperties.aa[i]);
          col.setRGB(jalview.util.Format.getHexString(colours[i]));
 -        jbucs.addColour(col);
 +        // jbucs.addColour(col);
 +        jbucs.getColour().add(col);
        }
        if (ucs.getLowerCaseColours() != null)
        {
          colours = ucs.getLowerCaseColours();
          for (int i = 0; i < colours.length; i++)
          {
 -          jalview.schemabinding.version2.Colour col = new jalview.schemabinding.version2.Colour();
 +          Colour col = new Colour();
            col.setName(ResidueProperties.aa[i].toLowerCase());
            col.setRGB(jalview.util.Format.getHexString(colours[i]));
 -          jbucs.addColour(col);
 +          // jbucs.addColour(col);
 +          jbucs.getColour().add(col);
          }
        }
  
        uc.setId(id);
        uc.setUserColourScheme(jbucs);
 -      jms.addUserColours(uc);
 +      // jm.addUserColours(uc);
 +      jm.getUserColours().add(uc);
      }
  
      return id;
    }
  
    jalview.schemes.UserColourScheme getUserColourScheme(
 -          JalviewModelSequence jms, String id)
 +          JalviewModel jm, String id)
    {
 -    UserColours[] uc = jms.getUserColours();
 +    List<UserColours> uc = jm.getUserColours();
      UserColours colours = null;
 -
 +/*
      for (int i = 0; i < uc.length; i++)
      {
        if (uc[i].getId().equals(id))
        {
          colours = uc[i];
 -
 +        break;
 +      }
 +    }
 +*/
 +    for (UserColours c : uc)
 +    {
 +      if (c.getId().equals(id))
 +      {
 +        colours = c;
          break;
        }
      }
      for (int i = 0; i < 24; i++)
      {
        newColours[i] = new java.awt.Color(Integer.parseInt(
 -              colours.getUserColourScheme().getColour(i).getRGB(), 16));
 +              // colours.getUserColourScheme().getColour(i).getRGB(), 16));
 +              colours.getUserColourScheme().getColour().get(i).getRGB(),
 +              16));
      }
  
      jalview.schemes.UserColourScheme ucs = new jalview.schemes.UserColourScheme(
              newColours);
  
 -    if (colours.getUserColourScheme().getColourCount() > 24)
 +    if (colours.getUserColourScheme().getColour().size()/*Count()*/ > 24)
      {
        newColours = new java.awt.Color[23];
        for (int i = 0; i < 23; i++)
        {
          newColours[i] = new java.awt.Color(Integer.parseInt(
 -                colours.getUserColourScheme().getColour(i + 24).getRGB(),
 +                colours.getUserColourScheme().getColour().get(i + 24)
 +                        .getRGB(),
                  16));
        }
        ucs.setLowerCaseColours(newColours);
     * flag to control whether the Jalview2XML_V1 parser should be deferred to if
     * exceptions are raised during project XML parsing
     */
 -  public boolean attemptversion1parse = true;
 +  public boolean attemptversion1parse = false;
  
    /**
     * Load a jalview project archive from a jar file
  
        jarInputStreamProvider jprovider = createjarInputStreamProvider(file);
        af = loadJalviewAlign(jprovider);
 -      af.setMenusForViewport();
 -
 +      if (af != null)
 +      {
 +        af.setMenusForViewport();
 +      }
      } catch (MalformedURLException e)
      {
        errorMessage = "Invalid URL format for '" + file + "'";
          if (jarentry != null && jarentry.getName().endsWith(".xml"))
          {
            InputStreamReader in = new InputStreamReader(jin, UTF_8);
 -          JalviewModel object = new JalviewModel();
 +          // JalviewModel object = new JalviewModel();
  
 +          JAXBContext jc = JAXBContext
 +                  .newInstance("jalview.xml.binding.jalview");
 +          XMLStreamReader streamReader = XMLInputFactory.newInstance()
 +                  .createXMLStreamReader(jin);
 +          javax.xml.bind.Unmarshaller um = jc.createUnmarshaller();
 +          JAXBElement<JalviewModel> jbe = um
 +                  .unmarshal(streamReader, JalviewModel.class);
 +          JalviewModel object = jbe.getValue();
 +
 +          /*
            Unmarshaller unmar = new Unmarshaller(object);
            unmar.setValidation(false);
            object = (JalviewModel) unmar.unmarshal(in);
 +          */
            if (true) // !skipViewport(object))
            {
              _af = loadFromObject(object, file, true, jprovider);
 -            if (_af != null && object.getJalviewModelSequence()
 -                    .getViewportCount() > 0)
 +            if (_af != null && object.getViewport().size() > 0)
 +            // getJalviewModelSequence().getViewportCount() > 0)
              {
                if (af == null)
                {
                  // store a reference to the first view
                  af = _af;
                }
 -              if (_af.viewport.isGatherViewsHere())
 +              if (_af.getViewport().isGatherViewsHere())
                {
                  // if this is a gathered view, keep its reference since
                  // after gathering views, only this frame will remain
                  af = _af;
 -                gatherToThisFrame.put(_af.viewport.getSequenceSetId(), _af);
 +                gatherToThisFrame.put(_af.getViewport().getSequenceSetId(),
 +                        _af);
                }
                // Save dataset to register mappings once all resolved
 -              importedDatasets.put(af.viewport.getAlignment().getDataset(),
 -                      af.viewport.getAlignment().getDataset());
 +              importedDatasets.put(
 +                      af.getViewport().getAlignment().getDataset(),
 +                      af.getViewport().getAlignment().getDataset());
              }
            }
            entryCount++;
        ex.printStackTrace(System.err);
        if (attemptversion1parse)
        {
 -        // Is Version 1 Jar file?
 -        try
 -        {
 -          af = new Jalview2XML_V1(raiseGUI).LoadJalviewAlign(jprovider);
 -        } catch (Exception ex2)
 -        {
 -          System.err.println("Exception whilst loading as jalviewXMLV1:");
 -          ex2.printStackTrace();
 -          af = null;
 -        }
 +        // used to attempt to parse as V1 castor-generated xml
        }
        if (Desktop.instance != null)
        {
            addedToSplitFrames.add(af);
            dnaFrame.setMenusForViewport();
            af.setMenusForViewport();
 -          if (af.viewport.isGatherViewsHere())
 +          if (af.getViewport().isGatherViewsHere())
            {
              gatherTo.add(sf);
            }
        if (!addedToSplitFrames.contains(af))
        {
          Viewport view = candidate.getKey();
 -        Desktop.addInternalFrame(af, view.getTitle(), view.getWidth(),
 -                view.getHeight());
 +        Desktop.addInternalFrame(af, view.getTitle(),
 +                safeInt(view.getWidth()), safeInt(view.getHeight()));
          af.setMenusForViewport();
          System.err.println("Failed to restore view " + view.getTitle()
                  + " to split frame");
       * And compute cDNA consensus (couldn't do earlier with consensus as
       * mappings were not yet present)
       */
 -    proteinFrame.viewport.alignmentChanged(proteinFrame.alignPanel);
 +    proteinFrame.getViewport().alignmentChanged(proteinFrame.alignPanel);
  
      return splitFrame;
    }
    /**
     * Load alignment frame from jalview XML DOM object
     * 
 -   * @param object
 +   * @param jalviewModel
     *          DOM
     * @param file
     *          filename source string
     *          data source provider
     * @return alignment frame created from view stored in DOM
     */
 -  AlignFrame loadFromObject(JalviewModel object, String file,
 +  AlignFrame loadFromObject(JalviewModel jalviewModel, String file,
            boolean loadTreesAndStructures, jarInputStreamProvider jprovider)
    {
 -    SequenceSet vamsasSet = object.getVamsasModel().getSequenceSet(0);
 -    Sequence[] vamsasSeq = vamsasSet.getSequence();
 +    SequenceSet vamsasSet = jalviewModel.getVamsasModel().getSequenceSet().get(0);
 +    List<Sequence> vamsasSeqs = vamsasSet.getSequence();
  
 -    JalviewModelSequence jms = object.getJalviewModelSequence();
 +    // JalviewModelSequence jms = object.getJalviewModelSequence();
  
 -    Viewport view = (jms.getViewportCount() > 0) ? jms.getViewport(0)
 +    // Viewport view = (jms.getViewportCount() > 0) ? jms.getViewport(0)
 +    // : null;
 +    Viewport view = (jalviewModel.getViewport().size() > 0)
 +            ? jalviewModel.getViewport().get(0)
              : null;
  
      // ////////////////////////////////
 +    // INITIALISE ALIGNMENT SEQUENCESETID AND VIEWID
 +    //
 +    //
 +    // If we just load in the same jar file again, the sequenceSetId
 +    // will be the same, and we end up with multiple references
 +    // to the same sequenceSet. We must modify this id on load
 +    // so that each load of the file gives a unique id
 +
 +    /**
 +     * used to resolve correct alignment dataset for alignments with multiple
 +     * views
 +     */
 +    String uniqueSeqSetId = null;
 +    String viewId = null;
 +    if (view != null)
 +    {
 +      uniqueSeqSetId = view.getSequenceSetId() + uniqueSetSuffix;
 +      viewId = (view.getId() == null ? null
 +              : view.getId() + uniqueSetSuffix);
 +    }
 +
 +    // ////////////////////////////////
      // LOAD SEQUENCES
  
      List<SequenceI> hiddenSeqs = null;
  
      boolean multipleView = false;
      SequenceI referenceseqForView = null;
 -    JSeq[] jseqs = object.getJalviewModelSequence().getJSeq();
 +    // JSeq[] jseqs = object.getJalviewModelSequence().getJSeq();
 +    List<JSeq> jseqs = jalviewModel.getJSeq();
      int vi = 0; // counter in vamsasSeq array
 -    for (int i = 0; i < jseqs.length; i++)
 +    for (int i = 0; i < jseqs.size(); i++)
      {
 -      String seqId = jseqs[i].getId();
 +      JSeq jseq = jseqs.get(i);
 +      String seqId = jseq.getId();
  
        SequenceI tmpSeq = seqRefIds.get(seqId);
        if (tmpSeq != null)
          if (!incompleteSeqs.containsKey(seqId))
          {
            // may not need this check, but keep it for at least 2.9,1 release
 -          if (tmpSeq.getStart() != jseqs[i].getStart()
 -                  || tmpSeq.getEnd() != jseqs[i].getEnd())
 +          if (tmpSeq.getStart() != jseq.getStart()
 +                  || tmpSeq.getEnd() != jseq.getEnd())
            {
              System.err.println(
                      "Warning JAL-2154 regression: updating start/end for sequence "
 -                            + tmpSeq.toString() + " to " + jseqs[i]);
 +                            + tmpSeq.toString() + " to " + jseq);
            }
          }
          else
          {
            incompleteSeqs.remove(seqId);
          }
 -        if (vamsasSeq.length > vi && vamsasSeq[vi].getId().equals(seqId))
 +        if (vamsasSeqs.size() > vi
 +                && vamsasSeqs.get(vi).getId().equals(seqId))
          {
            // most likely we are reading a dataset XML document so
            // update from vamsasSeq section of XML for this sequence
 -          tmpSeq.setName(vamsasSeq[vi].getName());
 -          tmpSeq.setDescription(vamsasSeq[vi].getDescription());
 -          tmpSeq.setSequence(vamsasSeq[vi].getSequence());
 +          tmpSeq.setName(vamsasSeqs.get(vi).getName());
 +          tmpSeq.setDescription(vamsasSeqs.get(vi).getDescription());
 +          tmpSeq.setSequence(vamsasSeqs.get(vi).getSequence());
            vi++;
          }
          else
            // reading multiple views, so vamsasSeq set is a subset of JSeq
            multipleView = true;
          }
 -        tmpSeq.setStart(jseqs[i].getStart());
 -        tmpSeq.setEnd(jseqs[i].getEnd());
 +        tmpSeq.setStart(jseq.getStart());
 +        tmpSeq.setEnd(jseq.getEnd());
          tmpseqs.add(tmpSeq);
        }
        else
        {
 -        tmpSeq = new jalview.datamodel.Sequence(vamsasSeq[vi].getName(),
 -                vamsasSeq[vi].getSequence());
 -        tmpSeq.setDescription(vamsasSeq[vi].getDescription());
 -        tmpSeq.setStart(jseqs[i].getStart());
 -        tmpSeq.setEnd(jseqs[i].getEnd());
 +        Sequence vamsasSeq = vamsasSeqs.get(vi);
 +        tmpSeq = new jalview.datamodel.Sequence(vamsasSeq.getName(),
 +                vamsasSeq.getSequence());
 +        tmpSeq.setDescription(vamsasSeq.getDescription());
 +        tmpSeq.setStart(jseq.getStart());
 +        tmpSeq.setEnd(jseq.getEnd());
          tmpSeq.setVamsasId(uniqueSetSuffix + seqId);
 -        seqRefIds.put(vamsasSeq[vi].getId(), tmpSeq);
 +        seqRefIds.put(vamsasSeq.getId(), tmpSeq);
          tmpseqs.add(tmpSeq);
          vi++;
        }
  
 -      if (jseqs[i].hasViewreference() && jseqs[i].getViewreference())
 +      if (safeBoolean(jseq.isViewreference()))
        {
          referenceseqForView = tmpseqs.get(tmpseqs.size() - 1);
        }
  
 -      if (jseqs[i].getHidden())
 +      if (jseq.isHidden() != null && jseq.isHidden().booleanValue())
        {
          if (hiddenSeqs == null)
          {
      }
      else
      {
 -      boolean isdsal = object.getJalviewModelSequence()
 -              .getViewportCount() == 0;
 +      boolean isdsal = jalviewModel.getViewport().isEmpty();
        if (isdsal)
        {
          // we are importing a dataset record, so
  
        // finally, verify all data in vamsasSet is actually present in al
        // passing on flag indicating if it is actually a stored dataset
 -      recoverDatasetFor(vamsasSet, al, isdsal);
 +      recoverDatasetFor(vamsasSet, al, isdsal, uniqueSeqSetId);
      }
  
      if (referenceseqForView != null)
        al.setSeqrep(referenceseqForView);
      }
      // / Add the alignment properties
 -    for (int i = 0; i < vamsasSet.getSequenceSetPropertiesCount(); i++)
 +    for (int i = 0; i < vamsasSet.getSequenceSetProperties().size(); i++)
      {
 -      SequenceSetProperties ssp = vamsasSet.getSequenceSetProperties(i);
 +      SequenceSetProperties ssp = vamsasSet.getSequenceSetProperties()
 +              .get(i);
        al.setProperty(ssp.getKey(), ssp.getValue());
      }
  
        // now, for 2.10 projects, this is also done if the xml doc includes
        // dataset sequences not actually present in any particular view.
        //
 -      for (int i = 0; i < vamsasSeq.length; i++)
 +      for (int i = 0; i < vamsasSeqs.size(); i++)
        {
 -        if (jseqs[i].getFeaturesCount() > 0)
 +        JSeq jseq = jseqs.get(i);
 +        if (jseq.getFeatures().size() > 0)
          {
 -          Features[] features = jseqs[i].getFeatures();
 -          for (int f = 0; f < features.length; f++)
 +          List<Feature> features = jseq.getFeatures();
 +          for (int f = 0; f < features.size(); f++)
            {
 -            SequenceFeature sf = new SequenceFeature(features[f].getType(),
 -                    features[f].getDescription(), features[f].getBegin(),
 -                    features[f].getEnd(), features[f].getScore(),
 -                    features[f].getFeatureGroup());
 -            sf.setStatus(features[f].getStatus());
 +            Feature feat = features.get(f);
 +            SequenceFeature sf = new SequenceFeature(feat.getType(),
 +                    feat.getDescription(), feat.getBegin(), feat.getEnd(),
 +                    safeFloat(feat.getScore()), feat.getFeatureGroup());
 +            sf.setStatus(feat.getStatus());
  
              /*
               * load any feature attributes - include map-valued attributes
               */
              Map<String, Map<String, String>> mapAttributes = new HashMap<>();
 -            for (int od = 0; od < features[f].getOtherDataCount(); od++)
 +            for (int od = 0; od < feat.getOtherData().size(); od++)
              {
 -              OtherData keyValue = features[f].getOtherData(od);
 +              OtherData keyValue = feat.getOtherData().get(od);
                String attributeName = keyValue.getKey();
                String attributeValue = keyValue.getValue();
                if (attributeName.startsWith("LINK"))
              al.getSequenceAt(i).addSequenceFeature(sf);
            }
          }
 -        if (vamsasSeq[i].getDBRefCount() > 0)
 +        if (vamsasSeqs.get(i).getDBRef().size() > 0)
          {
            // adds dbrefs to datasequence's set (since Jalview 2.10)
            addDBRefs(
                    al.getSequenceAt(i).getDatasetSequence() == null
                            ? al.getSequenceAt(i)
                            : al.getSequenceAt(i).getDatasetSequence(),
 -                  vamsasSeq[i]);
 +                  vamsasSeqs.get(i));
          }
 -        if (jseqs[i].getPdbidsCount() > 0)
 +        if (jseq.getPdbids().size() > 0)
          {
 -          Pdbids[] ids = jseqs[i].getPdbids();
 -          for (int p = 0; p < ids.length; p++)
 +          List<Pdbids> ids = jseq.getPdbids();
 +          for (int p = 0; p < ids.size(); p++)
            {
 +            Pdbids pdbid = ids.get(p);
              jalview.datamodel.PDBEntry entry = new jalview.datamodel.PDBEntry();
 -            entry.setId(ids[p].getId());
 -            if (ids[p].getType() != null)
 +            entry.setId(pdbid.getId());
 +            if (pdbid.getType() != null)
              {
 -              if (PDBEntry.Type.getType(ids[p].getType()) != null)
 +              if (PDBEntry.Type.getType(pdbid.getType()) != null)
                {
 -                entry.setType(PDBEntry.Type.getType(ids[p].getType()));
 +                entry.setType(PDBEntry.Type.getType(pdbid.getType()));
                }
                else
                {
                }
              }
              // jprovider is null when executing 'New View'
 -            if (ids[p].getFile() != null && jprovider != null)
 +            if (pdbid.getFile() != null && jprovider != null)
              {
 -              if (!pdbloaded.containsKey(ids[p].getFile()))
 +              if (!pdbloaded.containsKey(pdbid.getFile()))
                {
 -                entry.setFile(loadPDBFile(jprovider, ids[p].getId(),
 -                        ids[p].getFile()));
 +                entry.setFile(loadPDBFile(jprovider, pdbid.getId(),
 +                        pdbid.getFile()));
                }
                else
                {
 -                entry.setFile(pdbloaded.get(ids[p].getId()).toString());
 +                entry.setFile(pdbloaded.get(pdbid.getId()).toString());
                }
              }
 -            if (ids[p].getPdbentryItem() != null)
 +            /*
 +            if (pdbid.getPdbentryItem() != null)
              {
 -              for (PdbentryItem item : ids[p].getPdbentryItem())
 +              for (PdbentryItem item : pdbid.getPdbentryItem())
                {
                  for (Property pr : item.getProperty())
                  {
                  }
                }
              }
 +            */
 +            for (Property prop : pdbid.getProperty())
 +            {
 +              entry.setProperty(prop.getName(), prop.getValue());
 +            }
              StructureSelectionManager
                      .getStructureSelectionManager(Desktop.instance)
                      .registerPDBEntry(entry);
      // ///////////////////////////////
      // LOAD SEQUENCE MAPPINGS
  
 -    if (vamsasSet.getAlcodonFrameCount() > 0)
 +    if (vamsasSet.getAlcodonFrame().size() > 0)
      {
        // TODO Potentially this should only be done once for all views of an
        // alignment
 -      AlcodonFrame[] alc = vamsasSet.getAlcodonFrame();
 -      for (int i = 0; i < alc.length; i++)
 +      List<AlcodonFrame> alc = vamsasSet.getAlcodonFrame();
 +      for (int i = 0; i < alc.size(); i++)
        {
          AlignedCodonFrame cf = new AlignedCodonFrame();
 -        if (alc[i].getAlcodMapCount() > 0)
 +        if (alc.get(i).getAlcodMap().size() > 0)
          {
 -          AlcodMap[] maps = alc[i].getAlcodMap();
 -          for (int m = 0; m < maps.length; m++)
 +          List<AlcodMap> maps = alc.get(i).getAlcodMap();
 +          for (int m = 0; m < maps.size(); m++)
            {
 -            SequenceI dnaseq = seqRefIds.get(maps[m].getDnasq());
 +            AlcodMap map = maps.get(m);
 +            SequenceI dnaseq = seqRefIds.get(map.getDnasq());
              // Load Mapping
              jalview.datamodel.Mapping mapping = null;
              // attach to dna sequence reference.
 -            if (maps[m].getMapping() != null)
 +            if (map.getMapping() != null)
              {
 -              mapping = addMapping(maps[m].getMapping());
 +              mapping = addMapping(map.getMapping());
                if (dnaseq != null && mapping.getTo() != null)
                {
                  cf.addMap(dnaseq, mapping.getTo(), mapping.getMap());
                {
                  // defer to later
                  frefedSequence.add(
 -                        newAlcodMapRef(maps[m].getDnasq(), cf, mapping));
 +                        newAlcodMapRef(map.getDnasq(), cf, mapping));
                }
              }
            }
       */
      Map<String, List<AlignmentAnnotation>> groupAnnotRefs = new Hashtable<>();
  
 -    if (vamsasSet.getAnnotationCount() > 0)
 +    if (vamsasSet.getAnnotation().size()/*Count()*/ > 0)
      {
 -      Annotation[] an = vamsasSet.getAnnotation();
 +      List<Annotation> an = vamsasSet.getAnnotation();
  
 -      for (int i = 0; i < an.length; i++)
 +      for (int i = 0; i < an.size(); i++)
        {
 -        Annotation annotation = an[i];
 +        Annotation annotation = an.get(i);
  
          /**
           * test if annotation is automatically calculated for this view only
          {
            // Kludge for pre 2.5 projects which lacked the autocalculated flag
            autoForView = true;
 -          if (!annotation.hasAutoCalculated())
 -          {
 -            annotation.setAutoCalculated(true);
 -          }
 +          // JAXB has no has() test; schema defaults value to false
 +          // if (!annotation.hasAutoCalculated())
 +          // {
 +          // annotation.setAutoCalculated(true);
 +          // }
          }
 -        if (autoForView || (annotation.hasAutoCalculated()
 -                && annotation.isAutoCalculated()))
 +        if (autoForView || annotation.isAutoCalculated())
          {
            // remove ID - we don't recover annotation from other views for
            // view-specific annotation
            annotation.setId(null);
          }
  
 -        // set visiblity for other annotation in this view
 +        // set visibility for other annotation in this view
          String annotationId = annotation.getId();
          if (annotationId != null && annotationIds.containsKey(annotationId))
          {
            AlignmentAnnotation jda = annotationIds.get(annotationId);
            // in principle Visible should always be true for annotation displayed
            // in multiple views
 -          if (annotation.hasVisible())
 +          if (annotation.isVisible() != null)
            {
 -            jda.visible = annotation.getVisible();
 +            jda.visible = annotation.isVisible();
            }
  
            al.addAnnotation(jda);
            continue;
          }
          // Construct new annotation from model.
 -        AnnotationElement[] ae = annotation.getAnnotationElement();
 +        List<AnnotationElement> ae = annotation.getAnnotationElement();
          jalview.datamodel.Annotation[] anot = null;
          java.awt.Color firstColour = null;
          int anpos;
 -        if (!annotation.getScoreOnly())
 +        if (!annotation.isScoreOnly())
          {
            anot = new jalview.datamodel.Annotation[al.getWidth()];
 -          for (int aa = 0; aa < ae.length && aa < anot.length; aa++)
 +          for (int aa = 0; aa < ae.size() && aa < anot.length; aa++)
            {
 -            anpos = ae[aa].getPosition();
 +            AnnotationElement annElement = ae.get(aa);
 +            anpos = annElement.getPosition();
  
              if (anpos >= anot.length)
              {
                continue;
              }
  
 +            float value = safeFloat(annElement.getValue());
              anot[anpos] = new jalview.datamodel.Annotation(
 -
 -                    ae[aa].getDisplayCharacter(), ae[aa].getDescription(),
 -                    (ae[aa].getSecondaryStructure() == null
 -                            || ae[aa].getSecondaryStructure().length() == 0)
 -                                    ? ' '
 -                                    : ae[aa].getSecondaryStructure()
 -                                            .charAt(0),
 -                    ae[aa].getValue()
 -
 -            );
 -            // JBPNote: Consider verifying dataflow for IO of secondary
 -            // structure annotation read from Stockholm files
 -            // this was added to try to ensure that
 -            // if (anot[ae[aa].getPosition()].secondaryStructure>' ')
 -            // {
 -            // anot[ae[aa].getPosition()].displayCharacter = "";
 -            // }
 -            anot[anpos].colour = new java.awt.Color(ae[aa].getColour());
 +                    annElement.getDisplayCharacter(),
 +                    annElement.getDescription(),
 +                    (annElement.getSecondaryStructure() == null
 +                            || annElement.getSecondaryStructure()
 +                                    .length() == 0)
 +                                            ? ' '
 +                                            : annElement
 +                                                    .getSecondaryStructure()
 +                                                    .charAt(0),
 +                    value);
 +            anot[anpos].colour = new Color(safeInt(annElement.getColour()));
              if (firstColour == null)
              {
                firstColour = anot[anpos].colour;
          }
          jalview.datamodel.AlignmentAnnotation jaa = null;
  
 -        if (annotation.getGraph())
 +        if (annotation.isGraph())
          {
            float llim = 0, hlim = 0;
            // if (autoForView || an[i].isAutoCalculated()) {
            // }
            jaa = new jalview.datamodel.AlignmentAnnotation(
                    annotation.getLabel(), annotation.getDescription(), anot,
 -                  llim, hlim, annotation.getGraphType());
 +                  llim, hlim, safeInt(annotation.getGraphType()));
  
 -          jaa.graphGroup = annotation.getGraphGroup();
 +          jaa.graphGroup = safeInt(annotation.getGraphGroup());
            jaa._linecolour = firstColour;
            if (annotation.getThresholdLine() != null)
            {
              jaa.setThreshold(new jalview.datamodel.GraphLine(
 -                    annotation.getThresholdLine().getValue(),
 +                    safeFloat(annotation.getThresholdLine().getValue()),
                      annotation.getThresholdLine().getLabel(),
 -                    new java.awt.Color(
 -                            annotation.getThresholdLine().getColour())));
 -
 +                    new java.awt.Color(safeInt(
 +                            annotation.getThresholdLine().getColour()))));
            }
            if (autoForView || annotation.isAutoCalculated())
            {
          }
          else
          {
 -          jaa = new jalview.datamodel.AlignmentAnnotation(an[i].getLabel(),
 -                  an[i].getDescription(), anot);
 +          jaa = new jalview.datamodel.AlignmentAnnotation(
 +                  annotation.getLabel(), annotation.getDescription(), anot);
            jaa._linecolour = firstColour;
          }
          // register new annotation
 -        if (an[i].getId() != null)
 +        if (annotation.getId() != null)
          {
 -          annotationIds.put(an[i].getId(), jaa);
 -          jaa.annotationId = an[i].getId();
 +          annotationIds.put(annotation.getId(), jaa);
 +          jaa.annotationId = annotation.getId();
          }
          // recover sequence association
 -        String sequenceRef = an[i].getSequenceRef();
 +        String sequenceRef = annotation.getSequenceRef();
          if (sequenceRef != null)
          {
            // from 2.9 sequenceRef is to sequence id (JAL-1781)
            }
          }
          // and make a note of any group association
 -        if (an[i].getGroupRef() != null && an[i].getGroupRef().length() > 0)
 +        if (annotation.getGroupRef() != null
 +                && annotation.getGroupRef().length() > 0)
          {
            List<jalview.datamodel.AlignmentAnnotation> aal = groupAnnotRefs
 -                  .get(an[i].getGroupRef());
 +                  .get(annotation.getGroupRef());
            if (aal == null)
            {
              aal = new ArrayList<>();
 -            groupAnnotRefs.put(an[i].getGroupRef(), aal);
 +            groupAnnotRefs.put(annotation.getGroupRef(), aal);
            }
            aal.add(jaa);
          }
  
 -        if (an[i].hasScore())
 +        if (annotation.getScore() != null)
          {
 -          jaa.setScore(an[i].getScore());
 +          jaa.setScore(annotation.getScore().doubleValue());
          }
 -        if (an[i].hasVisible())
 +        if (annotation.isVisible() != null)
          {
 -          jaa.visible = an[i].getVisible();
 +          jaa.visible = annotation.isVisible().booleanValue();
          }
  
 -        if (an[i].hasCentreColLabels())
 +        if (annotation.isCentreColLabels() != null)
          {
 -          jaa.centreColLabels = an[i].getCentreColLabels();
 +          jaa.centreColLabels = annotation.isCentreColLabels()
 +                  .booleanValue();
          }
  
 -        if (an[i].hasScaleColLabels())
 +        if (annotation.isScaleColLabels() != null)
          {
 -          jaa.scaleColLabel = an[i].getScaleColLabels();
 +          jaa.scaleColLabel = annotation.isScaleColLabels().booleanValue();
          }
 -        if (an[i].hasAutoCalculated() && an[i].isAutoCalculated())
 +        if (annotation.isAutoCalculated())
          {
            // newer files have an 'autoCalculated' flag and store calculation
            // state in viewport properties
            jaa.autoCalculated = true; // means annotation will be marked for
            // update at end of load.
          }
 -        if (an[i].hasGraphHeight())
 -        {
 -          jaa.graphHeight = an[i].getGraphHeight();
 -        }
 -        if (an[i].hasBelowAlignment())
 +        if (annotation.getGraphHeight() != null)
          {
 -          jaa.belowAlignment = an[i].isBelowAlignment();
 +          jaa.graphHeight = annotation.getGraphHeight().intValue();
          }
 -        jaa.setCalcId(an[i].getCalcId());
 -        if (an[i].getPropertyCount() > 0)
 +        jaa.belowAlignment = annotation.isBelowAlignment();
 +        jaa.setCalcId(annotation.getCalcId());
 +        if (annotation.getProperty().size() > 0)
          {
 -          for (jalview.schemabinding.version2.Property prop : an[i]
 +          for (Annotation.Property prop : annotation
                    .getProperty())
            {
              jaa.setProperty(prop.getName(), prop.getValue());
      // ///////////////////////
      // LOAD GROUPS
      // Create alignment markup and styles for this view
 -    if (jms.getJGroupCount() > 0)
 +    if (jalviewModel.getJGroup().size() > 0)
      {
 -      JGroup[] groups = jms.getJGroup();
 +      List<JGroup> groups = jalviewModel.getJGroup();
        boolean addAnnotSchemeGroup = false;
 -      for (int i = 0; i < groups.length; i++)
 +      for (int i = 0; i < groups.size(); i++)
        {
 -        JGroup jGroup = groups[i];
 +        JGroup jGroup = groups.get(i);
          ColourSchemeI cs = null;
          if (jGroup.getColour() != null)
          {
            if (jGroup.getColour().startsWith("ucs"))
            {
 -            cs = getUserColourScheme(jms, jGroup.getColour());
 +            cs = getUserColourScheme(jalviewModel, jGroup.getColour());
            }
            else if (jGroup.getColour().equals("AnnotationColourGradient")
                    && jGroup.getAnnotationColours() != null)
            }
            else
            {
-             cs = ColourSchemeProperty.getColourScheme(al,
 -            // TODO: notify of view reference when available
+             cs = ColourSchemeProperty.getColourScheme(null, al,
                      jGroup.getColour());
            }
          }
 -        int pidThreshold = jGroup.getPidThreshold();
 +        int pidThreshold = safeInt(jGroup.getPidThreshold());
  
          Vector<SequenceI> seqs = new Vector<>();
  
 -        for (int s = 0; s < jGroup.getSeqCount(); s++)
 +        for (int s = 0; s < jGroup.getSeq().size(); s++)
          {
 -          String seqId = jGroup.getSeq(s) + "";
 +          String seqId = jGroup.getSeq().get(s);
            SequenceI ts = seqRefIds.get(seqId);
  
            if (ts != null)
          }
  
          SequenceGroup sg = new SequenceGroup(seqs, jGroup.getName(), cs,
 -                jGroup.getDisplayBoxes(), jGroup.getDisplayText(),
 -                jGroup.getColourText(), jGroup.getStart(), jGroup.getEnd());
 +                safeBoolean(jGroup.isDisplayBoxes()),
 +                safeBoolean(jGroup.isDisplayText()),
 +                safeBoolean(jGroup.isColourText()),
 +                safeInt(jGroup.getStart()), safeInt(jGroup.getEnd()));
          sg.getGroupColourScheme().setThreshold(pidThreshold, true);
          sg.getGroupColourScheme()
 -                .setConservationInc(jGroup.getConsThreshold());
 -        sg.setOutlineColour(new java.awt.Color(jGroup.getOutlineColour()));
 -
 -        sg.textColour = new java.awt.Color(jGroup.getTextCol1());
 -        sg.textColour2 = new java.awt.Color(jGroup.getTextCol2());
 -        sg.setShowNonconserved(
 -                jGroup.hasShowUnconserved() ? jGroup.isShowUnconserved()
 -                        : false);
 -        sg.thresholdTextColour = jGroup.getTextColThreshold();
 -        if (jGroup.hasShowConsensusHistogram())
 -        {
 +                .setConservationInc(safeInt(jGroup.getConsThreshold()));
 +        sg.setOutlineColour(new Color(safeInt(jGroup.getOutlineColour())));
 +
 +        sg.textColour = new Color(safeInt(jGroup.getTextCol1()));
 +        sg.textColour2 = new Color(safeInt(jGroup.getTextCol2()));
 +        sg.setShowNonconserved(safeBoolean(jGroup.isShowUnconserved()));
 +        sg.thresholdTextColour = safeInt(jGroup.getTextColThreshold());
 +        // attributes with a default in the schema are never null
            sg.setShowConsensusHistogram(jGroup.isShowConsensusHistogram());
 -        }
 -        ;
 -        if (jGroup.hasShowSequenceLogo())
 -        {
            sg.setshowSequenceLogo(jGroup.isShowSequenceLogo());
 -        }
 -        if (jGroup.hasNormaliseSequenceLogo())
 -        {
            sg.setNormaliseSequenceLogo(jGroup.isNormaliseSequenceLogo());
 -        }
 -        if (jGroup.hasIgnoreGapsinConsensus())
 -        {
 -          sg.setIgnoreGapsConsensus(jGroup.getIgnoreGapsinConsensus());
 -        }
 -        if (jGroup.getConsThreshold() != 0)
 +        sg.setIgnoreGapsConsensus(jGroup.isIgnoreGapsinConsensus());
 +        if (jGroup.getConsThreshold() != null
 +                && jGroup.getConsThreshold().intValue() != 0)
          {
            Conservation c = new Conservation("All", sg.getSequences(null), 0,
                    sg.getWidth() - 1);
          {
            // reconstruct the annotation colourscheme
            sg.setColourScheme(constructAnnotationColour(
 -                  jGroup.getAnnotationColours(), null, al, jms, false));
 +                  jGroup.getAnnotationColours(), null, al, jalviewModel, false));
          }
        }
      }
      // ///////////////////////////////
      // LOAD VIEWPORT
  
 -    // If we just load in the same jar file again, the sequenceSetId
 -    // will be the same, and we end up with multiple references
 -    // to the same sequenceSet. We must modify this id on load
 -    // so that each load of the file gives a unique id
 -    String uniqueSeqSetId = view.getSequenceSetId() + uniqueSetSuffix;
 -    String viewId = (view.getId() == null ? null
 -            : view.getId() + uniqueSetSuffix);
      AlignFrame af = null;
      AlignViewport av = null;
      // now check to see if we really need to create a new viewport.
       * Jalview 2.8.1 behaviour)
       */
      boolean doGroupAnnColour = Jalview2XML.isVersionStringLaterThan("2.8.1",
 -            object.getVersion());
 +            jalviewModel.getVersion());
  
      AlignmentPanel ap = null;
      boolean isnewview = true;
  
      if (isnewview)
      {
 -      af = loadViewport(file, jseqs, hiddenSeqs, al, jms, view,
 +      af = loadViewport(file, jseqs, hiddenSeqs, al, jalviewModel, view,
                uniqueSeqSetId, viewId, autoAlan);
 -      av = af.viewport;
 +      av = af.getViewport();
        ap = af.alignPanel;
      }
  
       */
      if (loadTreesAndStructures)
      {
 -      loadTrees(jms, view, af, av, ap);
 +      loadTrees(jalviewModel, view, af, av, ap);
 +      loadPCAViewers(jalviewModel, ap);
        loadPDBStructures(jprovider, jseqs, af, ap);
        loadRnaViewers(jprovider, jseqs, ap);
      }
     * @param ap
     */
    private void loadRnaViewers(jarInputStreamProvider jprovider,
 -          JSeq[] jseqs, AlignmentPanel ap)
 +          List<JSeq> jseqs, AlignmentPanel ap)
    {
      /*
       * scan the sequences for references to viewers; create each one the first
       */
      for (JSeq jseq : jseqs)
      {
 -      for (int i = 0; i < jseq.getRnaViewerCount(); i++)
 +      for (int i = 0; i < jseq.getRnaViewer().size(); i++)
        {
 -        RnaViewer viewer = jseq.getRnaViewer(i);
 +        RnaViewer viewer = jseq.getRnaViewer().get(i);
          AppVarna appVarna = findOrCreateVarnaViewer(viewer, uniqueSetSuffix,
                  ap);
  
 -        for (int j = 0; j < viewer.getSecondaryStructureCount(); j++)
 +        for (int j = 0; j < viewer.getSecondaryStructure().size(); j++)
          {
 -          SecondaryStructure ss = viewer.getSecondaryStructure(j);
 +          SecondaryStructure ss = viewer.getSecondaryStructure().get(j);
            SequenceI seq = seqRefIds.get(jseq.getId());
            AlignmentAnnotation ann = this.annotationIds
                    .get(ss.getAnnotationId());
             * add the structure to the Varna display (with session state copied
             * from the jar to a temporary file)
             */
 -          boolean gapped = ss.isGapped();
 +          boolean gapped = safeBoolean(ss.isGapped());
            String rnaTitle = ss.getTitle();
            String sessionState = ss.getViewerState();
            String tempStateFile = copyJarEntry(jprovider, sessionState,
            RnaModel rna = new RnaModel(rnaTitle, ann, seq, null, gapped);
            appVarna.addModelSession(rna, rnaTitle, tempStateFile);
          }
 -        appVarna.setInitialSelection(viewer.getSelectedRna());
 +        appVarna.setInitialSelection(safeInt(viewer.getSelectedRna()));
        }
      }
    }
       * viewer not found - make it
       */
      RnaViewerModel model = new RnaViewerModel(postLoadId, viewer.getTitle(),
 -            viewer.getXpos(), viewer.getYpos(), viewer.getWidth(),
 -            viewer.getHeight(), viewer.getDividerLocation());
 +            safeInt(viewer.getXpos()), safeInt(viewer.getYpos()),
 +            safeInt(viewer.getWidth()), safeInt(viewer.getHeight()),
 +            safeInt(viewer.getDividerLocation()));
      AppVarna varna = new AppVarna(model, ap);
  
      return varna;
    /**
     * Load any saved trees
     * 
 -   * @param jms
 +   * @param jm
     * @param view
     * @param af
     * @param av
     * @param ap
     */
 -  protected void loadTrees(JalviewModelSequence jms, Viewport view,
 +  protected void loadTrees(JalviewModel jm, Viewport view,
            AlignFrame af, AlignViewport av, AlignmentPanel ap)
    {
      // TODO result of automated refactoring - are all these parameters needed?
      try
      {
 -      for (int t = 0; t < jms.getTreeCount(); t++)
 +      for (int t = 0; t < jm.getTree().size(); t++)
        {
  
 -        Tree tree = jms.getTree(t);
 +        Tree tree = jm.getTree().get(t);
  
          TreePanel tp = (TreePanel) retrieveExistingObj(tree.getId());
          if (tp == null)
          {
 -          tp = af.showNewickTree(
 -                  new jalview.io.NewickFile(tree.getNewick()),
 -                  tree.getTitle(), tree.getWidth(), tree.getHeight(),
 -                  tree.getXpos(), tree.getYpos());
 +          tp = af.showNewickTree(new NewickFile(tree.getNewick()),
 +                  tree.getTitle(), safeInt(tree.getWidth()),
 +                  safeInt(tree.getHeight()), safeInt(tree.getXpos()),
 +                  safeInt(tree.getYpos()));
            if (tree.getId() != null)
            {
              // perhaps bind the tree id to something ?
            // TODO: should check if tp has been manipulated by user - if so its
            // settings shouldn't be modified
            tp.setTitle(tree.getTitle());
 -          tp.setBounds(new Rectangle(tree.getXpos(), tree.getYpos(),
 -                  tree.getWidth(), tree.getHeight()));
 -          tp.av = av; // af.viewport; // TODO: verify 'associate with all
 -          // views'
 -          // works still
 -          tp.treeCanvas.av = av; // af.viewport;
 -          tp.treeCanvas.ap = ap; // af.alignPanel;
 +          tp.setBounds(new Rectangle(safeInt(tree.getXpos()),
 +                  safeInt(tree.getYpos()), safeInt(tree.getWidth()),
 +                  safeInt(tree.getHeight())));
 +          tp.setViewport(av); // af.viewport;
 +          // TODO: verify 'associate with all views' works still
 +          tp.getTreeCanvas().setViewport(av); // af.viewport;
 +          tp.getTreeCanvas().setAssociatedPanel(ap); // af.alignPanel;
 +          // FIXME: should we use safeBoolean here ?
 +          tp.getTreeCanvas().setApplyToAllViews(tree.isLinkToAllViews());
  
          }
          if (tp == null)
            continue;
          }
  
 -        tp.fitToWindow.setState(tree.getFitToWindow());
 +        tp.fitToWindow.setState(safeBoolean(tree.isFitToWindow()));
          tp.fitToWindow_actionPerformed(null);
  
          if (tree.getFontName() != null)
          {
 -          tp.setTreeFont(new java.awt.Font(tree.getFontName(),
 -                  tree.getFontStyle(), tree.getFontSize()));
 +          tp.setTreeFont(
 +                  new Font(tree.getFontName(), safeInt(tree.getFontStyle()),
 +                          safeInt(tree.getFontSize())));
          }
          else
          {
 -          tp.setTreeFont(new java.awt.Font(view.getFontName(),
 -                  view.getFontStyle(), tree.getFontSize()));
 +          tp.setTreeFont(
 +                  new Font(view.getFontName(), safeInt(view.getFontStyle()),
 +                          safeInt(view.getFontSize())));
          }
  
 -        tp.showPlaceholders(tree.getMarkUnlinked());
 -        tp.showBootstrap(tree.getShowBootstrap());
 -        tp.showDistances(tree.getShowDistances());
 +        tp.showPlaceholders(safeBoolean(tree.isMarkUnlinked()));
 +        tp.showBootstrap(safeBoolean(tree.isShowBootstrap()));
 +        tp.showDistances(safeBoolean(tree.isShowDistances()));
  
 -        tp.treeCanvas.threshold = tree.getThreshold();
 +        tp.getTreeCanvas().setThreshold(safeFloat(tree.getThreshold()));
  
 -        if (tree.getCurrentTree())
 +        if (safeBoolean(tree.isCurrentTree()))
          {
 -          af.viewport.setCurrentTree(tp.getTree());
 +          af.getViewport().setCurrentTree(tp.getTree());
          }
        }
  
     * @param ap
     */
    protected void loadPDBStructures(jarInputStreamProvider jprovider,
 -          JSeq[] jseqs, AlignFrame af, AlignmentPanel ap)
 +          List<JSeq> jseqs, AlignFrame af, AlignmentPanel ap)
    {
      /*
       * Run through all PDB ids on the alignment, and collect mappings between
       */
      Map<String, StructureViewerModel> structureViewers = new LinkedHashMap<>();
  
 -    for (int i = 0; i < jseqs.length; i++)
 +    for (int i = 0; i < jseqs.size(); i++)
      {
 -      if (jseqs[i].getPdbidsCount() > 0)
 +      JSeq jseq = jseqs.get(i);
 +      if (jseq.getPdbids().size() > 0)
        {
 -        Pdbids[] ids = jseqs[i].getPdbids();
 -        for (int p = 0; p < ids.length; p++)
 +        List<Pdbids> ids = jseq.getPdbids();
 +        for (int p = 0; p < ids.size(); p++)
          {
 -          final int structureStateCount = ids[p].getStructureStateCount();
 +          Pdbids pdbid = ids.get(p);
 +          final int structureStateCount = pdbid.getStructureState().size();
            for (int s = 0; s < structureStateCount; s++)
            {
              // check to see if we haven't already created this structure view
 -            final StructureState structureState = ids[p]
 -                    .getStructureState(s);
 +            final StructureState structureState = pdbid
 +                    .getStructureState().get(s);
              String sviewid = (structureState.getViewId() == null) ? null
                      : structureState.getViewId() + uniqueSetSuffix;
              jalview.datamodel.PDBEntry jpdb = new jalview.datamodel.PDBEntry();
 -            // Originally : ids[p].getFile()
 +            // Originally : pdbid.getFile()
              // : TODO: verify external PDB file recovery still works in normal
              // jalview project load
 -            jpdb.setFile(loadPDBFile(jprovider, ids[p].getId(),
 -                    ids[p].getFile()));
 -            jpdb.setId(ids[p].getId());
 +            jpdb.setFile(
 +                    loadPDBFile(jprovider, pdbid.getId(), pdbid.getFile()));
 +            jpdb.setId(pdbid.getId());
  
 -            int x = structureState.getXpos();
 -            int y = structureState.getYpos();
 -            int width = structureState.getWidth();
 -            int height = structureState.getHeight();
 +            int x = safeInt(structureState.getXpos());
 +            int y = safeInt(structureState.getYpos());
 +            int width = safeInt(structureState.getWidth());
 +            int height = safeInt(structureState.getHeight());
  
              // Probably don't need to do this anymore...
              // Desktop.desktop.getComponentAt(x, y);
              // TODO: NOW: check that this recovers the PDB file correctly.
 -            String pdbFile = loadPDBFile(jprovider, ids[p].getId(),
 -                    ids[p].getFile());
 +            String pdbFile = loadPDBFile(jprovider, pdbid.getId(),
 +                    pdbid.getFile());
              jalview.datamodel.SequenceI seq = seqRefIds
 -                    .get(jseqs[i].getId() + "");
 +                    .get(jseq.getId() + "");
              if (sviewid == null)
              {
                sviewid = "_jalview_pre2_4_" + x + "," + y + "," + width + ","
              // linkAlignPanel,superposeWithAlignpanel}} from hash
              StructureViewerModel jmoldat = structureViewers.get(sviewid);
              jmoldat.setAlignWithPanel(jmoldat.isAlignWithPanel()
 -                    | (structureState.hasAlignwithAlignPanel()
 -                            ? structureState.getAlignwithAlignPanel()
 -                            : false));
 +                    || structureState.isAlignwithAlignPanel());
  
              /*
               * Default colour by linked panel to false if not specified (e.g.
               * for pre-2.7 projects)
               */
              boolean colourWithAlignPanel = jmoldat.isColourWithAlignPanel();
 -            colourWithAlignPanel |= (structureState
 -                    .hasColourwithAlignPanel()
 -                            ? structureState.getColourwithAlignPanel()
 -                            : false);
 +            colourWithAlignPanel |= structureState.isColourwithAlignPanel();
              jmoldat.setColourWithAlignPanel(colourWithAlignPanel);
  
              /*
               * pre-2.7 projects)
               */
              boolean colourByViewer = jmoldat.isColourByViewer();
 -            colourByViewer &= structureState.hasColourByJmol()
 -                    ? structureState.getColourByJmol()
 -                    : true;
 +            colourByViewer &= structureState.isColourByJmol();
              jmoldat.setColourByViewer(colourByViewer);
  
              if (jmoldat.getStateData().length() < structureState
 -                    .getContent().length())
 +                    .getValue()/*Content()*/.length())
              {
 -              {
 -                jmoldat.setStateData(structureState.getContent());
 -              }
 +              jmoldat.setStateData(structureState.getValue());// Content());
              }
 -            if (ids[p].getFile() != null)
 +            if (pdbid.getFile() != null)
              {
 -              File mapkey = new File(ids[p].getFile());
 +              File mapkey = new File(pdbid.getFile());
                StructureData seqstrmaps = jmoldat.getFileData().get(mapkey);
                if (seqstrmaps == null)
                {
                  jmoldat.getFileData().put(mapkey,
                          seqstrmaps = jmoldat.new StructureData(pdbFile,
 -                                ids[p].getId()));
 +                                pdbid.getId()));
                }
                if (!seqstrmaps.getSeqList().contains(seq))
                {
      }
    }
  
 -  AlignFrame loadViewport(String file, JSeq[] JSEQ,
 +  AlignFrame loadViewport(String file, List<JSeq> JSEQ,
            List<SequenceI> hiddenSeqs, AlignmentI al,
 -          JalviewModelSequence jms, Viewport view, String uniqueSeqSetId,
 +          JalviewModel jm, Viewport view, String uniqueSeqSetId,
            String viewId, List<JvAnnotRow> autoAlan)
    {
      AlignFrame af = null;
 -    af = new AlignFrame(al, view.getWidth(), view.getHeight(),
 -            uniqueSeqSetId, viewId);
 +    af = new AlignFrame(al, safeInt(view.getWidth()),
 +            safeInt(view.getHeight()), uniqueSeqSetId, viewId);
  
      af.setFileName(file, FileFormat.Jalview);
  
 -    for (int i = 0; i < JSEQ.length; i++)
 +    final AlignViewport viewport = af.getViewport();
 +    for (int i = 0; i < JSEQ.size(); i++)
      {
 -      af.viewport.setSequenceColour(
 -              af.viewport.getAlignment().getSequenceAt(i),
 -              new java.awt.Color(JSEQ[i].getColour()));
 +      int colour = safeInt(JSEQ.get(i).getColour());
 +      viewport.setSequenceColour(viewport.getAlignment().getSequenceAt(i),
 +              new Color(colour));
      }
  
      if (al.hasSeqrep())
      {
 -      af.getViewport().setColourByReferenceSeq(true);
 -      af.getViewport().setDisplayReferenceSeq(true);
 +      viewport.setColourByReferenceSeq(true);
 +      viewport.setDisplayReferenceSeq(true);
      }
  
 -    af.viewport.setGatherViewsHere(view.getGatheredViews());
 +    viewport.setGatherViewsHere(safeBoolean(view.isGatheredViews()));
  
      if (view.getSequenceSetId() != null)
      {
        AlignmentViewport av = viewportsAdded.get(uniqueSeqSetId);
  
 -      af.viewport.setSequenceSetId(uniqueSeqSetId);
 +      viewport.setSequenceSetId(uniqueSeqSetId);
        if (av != null)
        {
          // propagate shared settings to this new view
 -        af.viewport.setHistoryList(av.getHistoryList());
 -        af.viewport.setRedoList(av.getRedoList());
 +        viewport.setHistoryList(av.getHistoryList());
 +        viewport.setRedoList(av.getRedoList());
        }
        else
        {
 -        viewportsAdded.put(uniqueSeqSetId, af.viewport);
 +        viewportsAdded.put(uniqueSeqSetId, viewport);
        }
        // TODO: check if this method can be called repeatedly without
        // side-effects if alignpanel already registered.
      // apply Hidden regions to view.
      if (hiddenSeqs != null)
      {
 -      for (int s = 0; s < JSEQ.length; s++)
 +      for (int s = 0; s < JSEQ.size(); s++)
        {
          SequenceGroup hidden = new SequenceGroup();
          boolean isRepresentative = false;
 -        for (int r = 0; r < JSEQ[s].getHiddenSequencesCount(); r++)
 +        for (int r = 0; r < JSEQ.get(s).getHiddenSequences().size(); r++)
          {
            isRepresentative = true;
            SequenceI sequenceToHide = al
 -                  .getSequenceAt(JSEQ[s].getHiddenSequences(r));
 +                  .getSequenceAt(JSEQ.get(s).getHiddenSequences().get(r));
            hidden.addSequence(sequenceToHide, false);
            // remove from hiddenSeqs list so we don't try to hide it twice
            hiddenSeqs.remove(sequenceToHide);
          {
            SequenceI representativeSequence = al.getSequenceAt(s);
            hidden.addSequence(representativeSequence, false);
 -          af.viewport.hideRepSequences(representativeSequence, hidden);
 +          viewport.hideRepSequences(representativeSequence, hidden);
          }
        }
  
        SequenceI[] hseqs = hiddenSeqs
                .toArray(new SequenceI[hiddenSeqs.size()]);
 -      af.viewport.hideSequence(hseqs);
 +      viewport.hideSequence(hseqs);
  
      }
      // recover view properties and display parameters
  
 -    af.viewport.setShowAnnotation(view.getShowAnnotation());
 -    af.viewport.setAbovePIDThreshold(view.getPidSelected());
 -    af.viewport.setThreshold(view.getPidThreshold());
 -
 -    af.viewport.setColourText(view.getShowColourText());
 -
 -    af.viewport.setConservationSelected(view.getConservationSelected());
 -    af.viewport.setIncrement(view.getConsThreshold());
 -    af.viewport.setShowJVSuffix(view.getShowFullId());
 -    af.viewport.setRightAlignIds(view.getRightAlignIds());
 -    af.viewport.setFont(new java.awt.Font(view.getFontName(),
 -            view.getFontStyle(), view.getFontSize()), true);
 -    ViewStyleI vs = af.viewport.getViewStyle();
 +    viewport.setShowAnnotation(safeBoolean(view.isShowAnnotation()));
 +    viewport.setAbovePIDThreshold(safeBoolean(view.isPidSelected()));
 +    final int pidThreshold = safeInt(view.getPidThreshold());
 +    viewport.setThreshold(pidThreshold);
 +
 +    viewport.setColourText(safeBoolean(view.isShowColourText()));
 +
 +    viewport
 +            .setConservationSelected(
 +                    safeBoolean(view.isConservationSelected()));
 +    viewport.setIncrement(safeInt(view.getConsThreshold()));
 +    viewport.setShowJVSuffix(safeBoolean(view.isShowFullId()));
 +    viewport.setRightAlignIds(safeBoolean(view.isRightAlignIds()));
 +    viewport.setFont(new Font(view.getFontName(),
 +            safeInt(view.getFontStyle()), safeInt(view.getFontSize())),
 +            true);
 +    ViewStyleI vs = viewport.getViewStyle();
      vs.setScaleProteinAsCdna(view.isScaleProteinAsCdna());
 -    af.viewport.setViewStyle(vs);
 +    viewport.setViewStyle(vs);
      // TODO: allow custom charWidth/Heights to be restored by updating them
      // after setting font - which means set above to false
 -    af.viewport.setRenderGaps(view.getRenderGaps());
 -    af.viewport.setWrapAlignment(view.getWrapAlignment());
 -    af.viewport.setShowAnnotation(view.getShowAnnotation());
 +    viewport.setRenderGaps(safeBoolean(view.isRenderGaps()));
 +    viewport.setWrapAlignment(safeBoolean(view.isWrapAlignment()));
 +    viewport.setShowAnnotation(safeBoolean(view.isShowAnnotation()));
  
 -    af.viewport.setShowBoxes(view.getShowBoxes());
 +    viewport.setShowBoxes(safeBoolean(view.isShowBoxes()));
  
 -    af.viewport.setShowText(view.getShowText());
 +    viewport.setShowText(safeBoolean(view.isShowText()));
  
 -    af.viewport.setTextColour(new java.awt.Color(view.getTextCol1()));
 -    af.viewport.setTextColour2(new java.awt.Color(view.getTextCol2()));
 -    af.viewport.setThresholdTextColour(view.getTextColThreshold());
 -    af.viewport.setShowUnconserved(
 -            view.hasShowUnconserved() ? view.isShowUnconserved() : false);
 -    af.viewport.getRanges().setStartRes(view.getStartRes());
 +    viewport.setTextColour(new Color(safeInt(view.getTextCol1())));
 +    viewport.setTextColour2(new Color(safeInt(view.getTextCol2())));
 +    viewport.setThresholdTextColour(safeInt(view.getTextColThreshold()));
 +    viewport.setShowUnconserved(view.isShowUnconserved());
 +    viewport.getRanges().setStartRes(safeInt(view.getStartRes()));
  
      if (view.getViewName() != null)
      {
 -      af.viewport.viewName = view.getViewName();
 +      viewport.setViewName(view.getViewName());
        af.setInitialTabVisible();
      }
 -    af.setBounds(view.getXpos(), view.getYpos(), view.getWidth(),
 -            view.getHeight());
 +    af.setBounds(safeInt(view.getXpos()), safeInt(view.getYpos()),
 +            safeInt(view.getWidth()), safeInt(view.getHeight()));
      // startSeq set in af.alignPanel.updateLayout below
      af.alignPanel.updateLayout();
      ColourSchemeI cs = null;
      {
        if (view.getBgColour().startsWith("ucs"))
        {
 -        cs = getUserColourScheme(jms, view.getBgColour());
 +        cs = getUserColourScheme(jm, view.getBgColour());
        }
        else if (view.getBgColour().startsWith("Annotation"))
        {
 -        AnnotationColours viewAnnColour = view.getAnnotationColours();
 -        cs = constructAnnotationColour(viewAnnColour, af, al, jms, true);
 +        AnnotationColourScheme viewAnnColour = view.getAnnotationColours();
 +        cs = constructAnnotationColour(viewAnnColour, af, al, jm, true);
  
          // annpos
  
        }
        else
        {
-         cs = ColourSchemeProperty.getColourScheme(al, view.getBgColour());
 -        cs = ColourSchemeProperty.getColourScheme(af.viewport, al,
++        cs = ColourSchemeProperty.getColourScheme(af.getViewport(), al,
+                 view.getBgColour());
        }
      }
  
 -    af.viewport.setGlobalColourScheme(cs);
 -    af.viewport.getResidueShading().setThreshold(view.getPidThreshold(),
 -            view.getIgnoreGapsinConsensus());
 -    af.viewport.getResidueShading()
 -            .setConsensus(af.viewport.getSequenceConsensusHash());
 -    af.viewport.setColourAppliesToAllGroups(false);
 +    viewport.setGlobalColourScheme(cs);
 +    viewport.getResidueShading().setThreshold(pidThreshold,
 +            view.isIgnoreGapsinConsensus());
 +    viewport.getResidueShading()
 +            .setConsensus(viewport.getSequenceConsensusHash());
 +    viewport.setColourAppliesToAllGroups(false);
  
 -    if (view.getConservationSelected() && cs != null)
 +    if (safeBoolean(view.isConservationSelected()) && cs != null)
      {
 -      af.viewport.getResidueShading()
 -              .setConservationInc(view.getConsThreshold());
 +      viewport.getResidueShading()
 +              .setConservationInc(safeInt(view.getConsThreshold()));
      }
  
      af.changeColour(cs);
  
 -    af.viewport.setColourAppliesToAllGroups(true);
 +    viewport.setColourAppliesToAllGroups(true);
  
 -    af.viewport.setShowSequenceFeatures(view.getShowSequenceFeatures());
 +    viewport
 +            .setShowSequenceFeatures(
 +                    safeBoolean(view.isShowSequenceFeatures()));
  
 -    if (view.hasCentreColumnLabels())
 -    {
 -      af.viewport.setCentreColumnLabels(view.getCentreColumnLabels());
 -    }
 -    if (view.hasIgnoreGapsinConsensus())
 -    {
 -      af.viewport.setIgnoreGapsConsensus(view.getIgnoreGapsinConsensus(),
 -              null);
 -    }
 -    if (view.hasFollowHighlight())
 -    {
 -      af.viewport.setFollowHighlight(view.getFollowHighlight());
 -    }
 -    if (view.hasFollowSelection())
 -    {
 -      af.viewport.followSelection = view.getFollowSelection();
 -    }
 -    if (view.hasShowConsensusHistogram())
 -    {
 -      af.viewport
 -              .setShowConsensusHistogram(view.getShowConsensusHistogram());
 -    }
 -    else
 -    {
 -      af.viewport.setShowConsensusHistogram(true);
 -    }
 -    if (view.hasShowSequenceLogo())
 -    {
 -      af.viewport.setShowSequenceLogo(view.getShowSequenceLogo());
 -    }
 -    else
 -    {
 -      af.viewport.setShowSequenceLogo(false);
 -    }
 -    if (view.hasNormaliseSequenceLogo())
 -    {
 -      af.viewport.setNormaliseSequenceLogo(view.getNormaliseSequenceLogo());
 -    }
 -    if (view.hasShowDbRefTooltip())
 -    {
 -      af.viewport.setShowDBRefs(view.getShowDbRefTooltip());
 -    }
 -    if (view.hasShowNPfeatureTooltip())
 -    {
 -      af.viewport.setShowNPFeats(view.hasShowNPfeatureTooltip());
 -    }
 -    if (view.hasShowGroupConsensus())
 -    {
 -      af.viewport.setShowGroupConsensus(view.getShowGroupConsensus());
 -    }
 -    else
 -    {
 -      af.viewport.setShowGroupConsensus(false);
 -    }
 -    if (view.hasShowGroupConservation())
 -    {
 -      af.viewport.setShowGroupConservation(view.getShowGroupConservation());
 -    }
 -    else
 -    {
 -      af.viewport.setShowGroupConservation(false);
 -    }
 +    viewport.setCentreColumnLabels(view.isCentreColumnLabels());
 +    viewport.setIgnoreGapsConsensus(view.isIgnoreGapsinConsensus(), null);
 +    viewport.setFollowHighlight(view.isFollowHighlight());
 +    viewport.followSelection = view.isFollowSelection();
 +    viewport.setShowConsensusHistogram(view.isShowConsensusHistogram());
 +    viewport.setShowSequenceLogo(view.isShowSequenceLogo());
 +    viewport.setNormaliseSequenceLogo(view.isNormaliseSequenceLogo());
 +    viewport.setShowDBRefs(safeBoolean(view.isShowDbRefTooltip()));
 +    viewport.setShowNPFeats(safeBoolean(view.isShowNPfeatureTooltip()));
 +    viewport.setShowGroupConsensus(view.isShowGroupConsensus());
 +    viewport.setShowGroupConservation(view.isShowGroupConservation());
  
      // recover feature settings
 -    if (jms.getFeatureSettings() != null)
 +    if (jm.getFeatureSettings() != null)
      {
        FeatureRenderer fr = af.alignPanel.getSeqPanel().seqCanvas
                .getFeatureRenderer();
        FeaturesDisplayed fdi;
 -      af.viewport.setFeaturesDisplayed(fdi = new FeaturesDisplayed());
 -      String[] renderOrder = new String[jms.getFeatureSettings()
 -              .getSettingCount()];
 +      viewport.setFeaturesDisplayed(fdi = new FeaturesDisplayed());
 +      String[] renderOrder = new String[jm.getFeatureSettings()
 +              .getSetting().size()];
        Map<String, FeatureColourI> featureColours = new Hashtable<>();
        Map<String, Float> featureOrder = new Hashtable<>();
  
 -      for (int fs = 0; fs < jms.getFeatureSettings()
 -              .getSettingCount(); fs++)
 +      for (int fs = 0; fs < jm.getFeatureSettings()
 +              .getSetting().size(); fs++)
        {
 -        Setting setting = jms.getFeatureSettings().getSetting(fs);
 +        Setting setting = jm.getFeatureSettings().getSetting().get(fs);
          String featureType = setting.getType();
  
          /*
           * restore feature filters (if any)
           */
 -        MatcherSet filters = setting.getMatcherSet();
 +        jalview.xml.binding.jalview.FeatureMatcherSet filters = setting
 +                .getMatcherSet();
          if (filters != null)
          {
            FeatureMatcherSetI filter = Jalview2XML
 -                  .unmarshalFilter(featureType, filters);
 +                  .parseFilter(featureType, filters);
            if (!filter.isEmpty())
            {
              fr.setFeatureFilter(featureType, filter);
           * restore feature colour scheme
           */
          Color maxColour = new Color(setting.getColour());
 -        if (setting.hasMincolour())
 +        if (setting.getMincolour() != null)
          {
            /*
             * minColour is always set unless a simple colour
             * (including for colour by label though it doesn't use it)
             */
 -          Color minColour = new Color(setting.getMincolour());
 +          Color minColour = new Color(setting.getMincolour().intValue());
            Color noValueColour = minColour;
            NoValueColour noColour = setting.getNoValueColour();
            if (noColour == NoValueColour.NONE)
            {
              noValueColour = maxColour;
            }
 -          float min = setting.hasMin() ? setting.getMin() : 0f;
 -          float max = setting.hasMin() ? setting.getMax() : 1f;
 -          FeatureColourI gc = new FeatureColour(minColour, maxColour,
 +          float min = safeFloat(safeFloat(setting.getMin()));
 +          float max = setting.getMax() == null ? 1f
 +                  : setting.getMax().floatValue();
 +          FeatureColourI gc = new FeatureColour(maxColour, minColour,
 +                  maxColour,
                    noValueColour, min, max);
 -          if (setting.getAttributeNameCount() > 0)
 +          if (setting.getAttributeName().size() > 0)
            {
 -            gc.setAttributeName(setting.getAttributeName());
 +            gc.setAttributeName(setting.getAttributeName().toArray(
 +                    new String[setting.getAttributeName().size()]));
            }
 -          if (setting.hasThreshold())
 +          if (setting.getThreshold() != null)
            {
 -            gc.setThreshold(setting.getThreshold());
 -            int threshstate = setting.getThreshstate();
 +            gc.setThreshold(setting.getThreshold().floatValue());
 +            int threshstate = safeInt(setting.getThreshstate());
              // -1 = None, 0 = Below, 1 = Above threshold
              if (threshstate == 0)
              {
              }
            }
            gc.setAutoScaled(true); // default
 -          if (setting.hasAutoScale())
 +          if (setting.isAutoScale() != null)
            {
 -            gc.setAutoScaled(setting.getAutoScale());
 +            gc.setAutoScaled(setting.isAutoScale());
            }
 -          if (setting.hasColourByLabel())
 +          if (setting.isColourByLabel() != null)
            {
 -            gc.setColourByLabel(setting.getColourByLabel());
 +            gc.setColourByLabel(setting.isColourByLabel());
            }
            // and put in the feature colour table.
            featureColours.put(featureType, gc);
                    new FeatureColour(maxColour));
          }
          renderOrder[fs] = featureType;
 -        if (setting.hasOrder())
 +        if (setting.getOrder() != null)
          {
 -          featureOrder.put(featureType, setting.getOrder());
 +          featureOrder.put(featureType, setting.getOrder().floatValue());
          }
          else
          {
            featureOrder.put(featureType, new Float(
 -                  fs / jms.getFeatureSettings().getSettingCount()));
 +                  fs / jm.getFeatureSettings().getSetting().size()));
          }
 -        if (setting.getDisplay())
 +        if (safeBoolean(setting.isDisplay()))
          {
            fdi.setVisible(featureType);
          }
        }
        Map<String, Boolean> fgtable = new Hashtable<>();
 -      for (int gs = 0; gs < jms.getFeatureSettings().getGroupCount(); gs++)
 +      for (int gs = 0; gs < jm.getFeatureSettings().getGroup().size(); gs++)
        {
 -        Group grp = jms.getFeatureSettings().getGroup(gs);
 -        fgtable.put(grp.getName(), new Boolean(grp.getDisplay()));
 +        Group grp = jm.getFeatureSettings().getGroup().get(gs);
 +        fgtable.put(grp.getName(), new Boolean(grp.isDisplay()));
        }
        // FeatureRendererSettings frs = new FeatureRendererSettings(renderOrder,
        // fgtable, featureColours, jms.getFeatureSettings().hasTransparency() ?
        fr.transferSettings(frs);
      }
  
 -    if (view.getHiddenColumnsCount() > 0)
 +    if (view.getHiddenColumns().size() > 0)
      {
 -      for (int c = 0; c < view.getHiddenColumnsCount(); c++)
 +      for (int c = 0; c < view.getHiddenColumns().size(); c++)
        {
 -        af.viewport.hideColumns(view.getHiddenColumns(c).getStart(),
 -                view.getHiddenColumns(c).getEnd() // +1
 -        );
 +        final HiddenColumns hc = view.getHiddenColumns().get(c);
 +        viewport.hideColumns(safeInt(hc.getStart()),
 +                safeInt(hc.getEnd()) /* +1 */);
        }
      }
      if (view.getCalcIdParam() != null)
        {
          if (calcIdParam != null)
          {
 -          if (recoverCalcIdParam(calcIdParam, af.viewport))
 +          if (recoverCalcIdParam(calcIdParam, viewport))
            {
            }
            else
          }
        }
      }
 -    af.setMenusFromViewport(af.viewport);
 +    af.setMenusFromViewport(viewport);
      af.setTitle(view.getTitle());
      // TODO: we don't need to do this if the viewport is aready visible.
      /*
      String complementaryViewId = view.getComplementId();
      if (complementaryViewId == null)
      {
 -      Desktop.addInternalFrame(af, view.getTitle(), view.getWidth(),
 -              view.getHeight());
 +      Desktop.addInternalFrame(af, view.getTitle(),
 +              safeInt(view.getWidth()), safeInt(view.getHeight()));
        // recompute any autoannotation
        af.alignPanel.updateAnnotation(false, true);
        reorderAutoannotation(af, al, autoAlan);
     * @param viewAnnColour
     * @param af
     * @param al
 -   * @param jms
 +   * @param model
     * @param checkGroupAnnColour
     * @return
     */
    private ColourSchemeI constructAnnotationColour(
 -          AnnotationColours viewAnnColour, AlignFrame af, AlignmentI al,
 -          JalviewModelSequence jms, boolean checkGroupAnnColour)
 +          AnnotationColourScheme viewAnnColour, AlignFrame af,
 +          AlignmentI al, JalviewModel model, boolean checkGroupAnnColour)
    {
      boolean propagateAnnColour = false;
 -    AlignmentI annAlignment = af != null ? af.viewport.getAlignment() : al;
 +    AlignmentI annAlignment = af != null ? af.getViewport().getAlignment()
 +            : al;
      if (checkGroupAnnColour && al.getGroups() != null
              && al.getGroups().size() > 0)
      {
      }
      if (matchedAnnotation.getThreshold() == null)
      {
 -      matchedAnnotation.setThreshold(new GraphLine(
 -              viewAnnColour.getThreshold(), "Threshold", Color.black));
 +      matchedAnnotation.setThreshold(
 +              new GraphLine(safeFloat(viewAnnColour.getThreshold()),
 +                      "Threshold", Color.black));
      }
  
      AnnotationColourGradient cs = null;
      if (viewAnnColour.getColourScheme().equals("None"))
      {
        cs = new AnnotationColourGradient(matchedAnnotation,
 -              new Color(viewAnnColour.getMinColour()),
 -              new Color(viewAnnColour.getMaxColour()),
 -              viewAnnColour.getAboveThreshold());
 +              new Color(safeInt(viewAnnColour.getMinColour())),
 +              new Color(safeInt(viewAnnColour.getMaxColour())),
 +              safeInt(viewAnnColour.getAboveThreshold()));
      }
      else if (viewAnnColour.getColourScheme().startsWith("ucs"))
      {
        cs = new AnnotationColourGradient(matchedAnnotation,
 -              getUserColourScheme(jms, viewAnnColour.getColourScheme()),
 -              viewAnnColour.getAboveThreshold());
 +              getUserColourScheme(model, viewAnnColour.getColourScheme()),
 +              safeInt(viewAnnColour.getAboveThreshold()));
      }
      else
      {
        cs = new AnnotationColourGradient(matchedAnnotation,
-               ColourSchemeProperty.getColourScheme(al,
 -              ColourSchemeProperty.getColourScheme(af.viewport, al,
++              ColourSchemeProperty.getColourScheme(af.getViewport(), al,
                        viewAnnColour.getColourScheme()),
 -              viewAnnColour.getAboveThreshold());
 +              safeInt(viewAnnColour.getAboveThreshold()));
      }
  
 -    boolean perSequenceOnly = viewAnnColour.isPerSequence();
 -    boolean useOriginalColours = viewAnnColour.isPredefinedColours();
 +    boolean perSequenceOnly = safeBoolean(viewAnnColour.isPerSequence());
 +    boolean useOriginalColours = safeBoolean(
 +            viewAnnColour.isPredefinedColours());
      cs.setSeqAssociated(perSequenceOnly);
      cs.setPredefinedColours(useOriginalColours);
  
  
          AnnotationColourGradient groupScheme = new AnnotationColourGradient(
                  matchedAnnotation, sg.getColourScheme(),
 -                viewAnnColour.getAboveThreshold());
 +                safeInt(viewAnnColour.getAboveThreshold()));
          sg.setColourScheme(groupScheme);
          groupScheme.setSeqAssociated(perSequenceOnly);
          groupScheme.setPredefinedColours(useOriginalColours);
      {
        return false;
      }
 -    String id;
 -    if (skipList.containsKey(
 -            id = object.getJalviewModelSequence().getViewport()[0]
 -                    .getSequenceSetId()))
 +    String id = object.getViewport().get(0).getSequenceSetId();
 +    if (skipList.containsKey(id))
      {
        if (Cache.log != null && Cache.log.isDebugEnabled())
        {
    }
  
    private void recoverDatasetFor(SequenceSet vamsasSet, AlignmentI al,
 -          boolean ignoreUnrefed)
 +          boolean ignoreUnrefed, String uniqueSeqSetId)
    {
      jalview.datamodel.AlignmentI ds = getDatasetFor(
              vamsasSet.getDatasetId());
 +    AlignmentI xtant_ds = ds;
 +    if (xtant_ds == null)
 +    {
 +      // good chance we are about to create a new dataset, but check if we've
 +      // seen some of the dataset sequence IDs before.
 +      // TODO: skip this check if we are working with project generated by
 +      // version 2.11 or later
 +      xtant_ds = checkIfHasDataset(vamsasSet.getSequence());
 +      if (xtant_ds != null)
 +      {
 +        ds = xtant_ds;
 +        addDatasetRef(vamsasSet.getDatasetId(), ds);
 +      }
 +    }
      Vector dseqs = null;
 +    if (!ignoreUnrefed)
 +    {
 +      // recovering an alignment View
 +      AlignmentI seqSetDS = getDatasetFor(UNIQSEQSETID + uniqueSeqSetId);
 +      if (seqSetDS != null)
 +      {
 +        if (ds != null && ds != seqSetDS)
 +        {
 +          warn("JAL-3171 regression: Overwriting a dataset reference for an alignment"
 +                  + " - CDS/Protein crossreference data may be lost");
 +          if (xtant_ds != null)
 +          {
 +            // This can only happen if the unique sequence set ID was bound to a
 +            // dataset that did not contain any of the sequences in the view
 +            // currently being restored.
 +            warn("JAL-3171 SERIOUS!  TOTAL CONFUSION - please consider contacting the Jalview Development team so they can investigate why your project caused this message to be displayed.");
 +          }
 +        }
 +        ds = seqSetDS;
 +        addDatasetRef(vamsasSet.getDatasetId(), ds);
 +      }
 +    }
      if (ds == null)
      {
 +      // try even harder to restore dataset
 +      AlignmentI xtantDS = checkIfHasDataset(vamsasSet.getSequence());
        // create a list of new dataset sequences
        dseqs = new Vector();
      }
 -    for (int i = 0, iSize = vamsasSet.getSequenceCount(); i < iSize; i++)
 +    for (int i = 0, iSize = vamsasSet.getSequence().size(); i < iSize; i++)
      {
 -      Sequence vamsasSeq = vamsasSet.getSequence(i);
 +      Sequence vamsasSeq = vamsasSet.getSequence().get(i);
        ensureJalviewDatasetSequence(vamsasSeq, ds, dseqs, ignoreUnrefed, i);
      }
      // create a new dataset
      if (al.getDataset() == null && !ignoreUnrefed)
      {
        al.setDataset(ds);
 +      // register dataset for the alignment's uniqueSeqSetId for legacy projects
 +      addDatasetRef(UNIQSEQSETID + uniqueSeqSetId, ds);
 +    }
 +    updateSeqDatasetBinding(vamsasSet.getSequence(), ds);
 +  }
 +
 +  /**
 +   * XML dataset sequence ID to materialised dataset reference
 +   */
 +  HashMap<String, AlignmentI> seqToDataset = new HashMap<>();
 +
 +  /**
 +   * @return the first materialised dataset reference containing a dataset
 +   *         sequence referenced in the given view
 +   * @param list
 +   *          - sequences from the view
 +   */
 +  AlignmentI checkIfHasDataset(List<Sequence> list)
 +  {
 +    for (Sequence restoredSeq : list)
 +    {
 +      AlignmentI datasetFor = seqToDataset.get(restoredSeq.getDsseqid());
 +      if (datasetFor != null)
 +      {
 +        return datasetFor;
 +      }
      }
 +    return null;
    }
  
    /**
 +   * Register ds as the containing dataset for the dataset sequences referenced
 +   * by sequences in list
 +   * 
 +   * @param list
 +   *          - sequences in a view
 +   * @param ds
 +   */
 +  void updateSeqDatasetBinding(List<Sequence> list, AlignmentI ds)
 +  {
 +    for (Sequence restoredSeq : list)
 +    {
 +      AlignmentI prevDS = seqToDataset.put(restoredSeq.getDsseqid(), ds);
 +      if (prevDS != null && prevDS != ds)
 +      {
 +        warn("Dataset sequence appears in many datasets: "
 +                + restoredSeq.getDsseqid());
 +        // TODO: try to merge!
 +      }
 +    }
 +  }
 +  /**
     * 
     * @param vamsasSeq
     *          sequence definition to create/merge dataset sequence for
  
    private void addDBRefs(SequenceI datasetSequence, Sequence sequence)
    {
 -    for (int d = 0; d < sequence.getDBRefCount(); d++)
 +    for (int d = 0; d < sequence.getDBRef().size(); d++)
      {
 -      DBRef dr = sequence.getDBRef(d);
 +      DBRef dr = sequence.getDBRef().get(d);
        jalview.datamodel.DBRefEntry entry = new jalview.datamodel.DBRefEntry(
 -              sequence.getDBRef(d).getSource(),
 -              sequence.getDBRef(d).getVersion(),
 -              sequence.getDBRef(d).getAccessionId());
 +              dr.getSource(), dr.getVersion(), dr.getAccessionId());
        if (dr.getMapping() != null)
        {
          entry.setMap(addMapping(dr.getMapping()));
    {
      SequenceI dsto = null;
      // Mapping m = dr.getMapping();
 -    int fr[] = new int[m.getMapListFromCount() * 2];
 -    Enumeration f = m.enumerateMapListFrom();
 -    for (int _i = 0; f.hasMoreElements(); _i += 2)
 +    int fr[] = new int[m.getMapListFrom().size() * 2];
 +    Iterator<MapListFrom> from = m.getMapListFrom().iterator();// enumerateMapListFrom();
 +    for (int _i = 0; from.hasNext(); _i += 2)
      {
 -      MapListFrom mf = (MapListFrom) f.nextElement();
 +      MapListFrom mf = from.next();
        fr[_i] = mf.getStart();
        fr[_i + 1] = mf.getEnd();
      }
 -    int fto[] = new int[m.getMapListToCount() * 2];
 -    f = m.enumerateMapListTo();
 -    for (int _i = 0; f.hasMoreElements(); _i += 2)
 +    int fto[] = new int[m.getMapListTo().size() * 2];
 +    Iterator<MapListTo> to = m.getMapListTo().iterator();// enumerateMapListTo();
 +    for (int _i = 0; to.hasNext(); _i += 2)
      {
 -      MapListTo mf = (MapListTo) f.nextElement();
 +      MapListTo mf = to.next();
        fto[_i] = mf.getStart();
        fto[_i + 1] = mf.getEnd();
      }
      jalview.datamodel.Mapping jmap = new jalview.datamodel.Mapping(dsto, fr,
 -            fto, (int) m.getMapFromUnit(), (int) m.getMapToUnit());
 -    if (m.getMappingChoice() != null)
 +            fto, m.getMapFromUnit().intValue(),
 +            m.getMapToUnit().intValue());
 +
 +    /*
 +     * (optional) choice of dseqFor or Sequence
 +     */
 +    if (m.getDseqFor() != null)
      {
 -      MappingChoice mc = m.getMappingChoice();
 -      if (mc.getDseqFor() != null)
 +      String dsfor = m.getDseqFor();
 +      if (seqRefIds.containsKey(dsfor))
        {
 -        String dsfor = "" + mc.getDseqFor();
 -        if (seqRefIds.containsKey(dsfor))
 -        {
 -          /**
 -           * recover from hash
 -           */
 -          jmap.setTo(seqRefIds.get(dsfor));
 -        }
 -        else
 -        {
 -          frefedSequence.add(newMappingRef(dsfor, jmap));
 -        }
 +        /*
 +         * recover from hash
 +         */
 +        jmap.setTo(seqRefIds.get(dsfor));
        }
        else
        {
 -        /**
 -         * local sequence definition
 +        frefedSequence.add(newMappingRef(dsfor, jmap));
 +      }
 +    }
 +    else if (m.getSequence() != null)
 +    {
 +      /*
 +       * local sequence definition
 +       */
 +      Sequence ms = m.getSequence();
 +      SequenceI djs = null;
 +      String sqid = ms.getDsseqid();
 +      if (sqid != null && sqid.length() > 0)
 +      {
 +        /*
 +         * recover dataset sequence
           */
 -        Sequence ms = mc.getSequence();
 -        SequenceI djs = null;
 -        String sqid = ms.getDsseqid();
 -        if (sqid != null && sqid.length() > 0)
 -        {
 -          /*
 -           * recover dataset sequence
 -           */
 -          djs = seqRefIds.get(sqid);
 -        }
 -        else
 -        {
 -          System.err.println(
 -                  "Warning - making up dataset sequence id for DbRef sequence map reference");
 -          sqid = ((Object) ms).toString(); // make up a new hascode for
 -          // undefined dataset sequence hash
 -          // (unlikely to happen)
 -        }
 -
 -        if (djs == null)
 -        {
 -          /**
 -           * make a new dataset sequence and add it to refIds hash
 -           */
 -          djs = new jalview.datamodel.Sequence(ms.getName(),
 -                  ms.getSequence());
 -          djs.setStart(jmap.getMap().getToLowest());
 -          djs.setEnd(jmap.getMap().getToHighest());
 -          djs.setVamsasId(uniqueSetSuffix + sqid);
 -          jmap.setTo(djs);
 -          incompleteSeqs.put(sqid, djs);
 -          seqRefIds.put(sqid, djs);
 +        djs = seqRefIds.get(sqid);
 +      }
 +      else
 +      {
 +        System.err.println(
 +                "Warning - making up dataset sequence id for DbRef sequence map reference");
 +        sqid = ((Object) ms).toString(); // make up a new hascode for
 +        // undefined dataset sequence hash
 +        // (unlikely to happen)
 +      }
  
 -        }
 -        jalview.bin.Cache.log.debug("about to recurse on addDBRefs.");
 -        addDBRefs(djs, ms);
 +      if (djs == null)
 +      {
 +        /**
 +         * make a new dataset sequence and add it to refIds hash
 +         */
 +        djs = new jalview.datamodel.Sequence(ms.getName(),
 +                ms.getSequence());
 +        djs.setStart(jmap.getMap().getToLowest());
 +        djs.setEnd(jmap.getMap().getToHighest());
 +        djs.setVamsasId(uniqueSetSuffix + sqid);
 +        jmap.setTo(djs);
 +        incompleteSeqs.put(sqid, djs);
 +        seqRefIds.put(sqid, djs);
  
        }
 +      jalview.bin.Cache.log.debug("about to recurse on addDBRefs.");
 +      addDBRefs(djs, ms);
 +
      }
 -    return (jmap);
  
 +    return jmap;
    }
  
    /**
      initSeqRefs();
      JalviewModel jm = saveState(ap, null, null, null);
  
 +    addDatasetRef(
 +            jm.getVamsasModel().getSequenceSet().get(0).getDatasetId(),
 +            ap.getAlignment().getDataset());
 +
      uniqueSetSuffix = "";
 -    jm.getJalviewModelSequence().getViewport(0).setId(null);
 +    // jm.getJalviewModelSequence().getViewport(0).setId(null);
 +    jm.getViewport().get(0).setId(null);
      // we don't overwrite the view we just copied
  
      if (this.frefedSequence == null)
      viewportsAdded.clear();
  
      AlignFrame af = loadFromObject(jm, null, false, null);
 -    af.alignPanels.clear();
 +    af.getAlignPanels().clear();
      af.closeMenuItem_actionPerformed(true);
  
      /*
    }
  
    /**
 +   * Loads any saved PCA viewers
 +   * 
 +   * @param jms
 +   * @param ap
 +   */
 +  protected void loadPCAViewers(JalviewModel model, AlignmentPanel ap)
 +  {
 +    try
 +    {
 +      List<PcaViewer> pcaviewers = model.getPcaViewer();
 +      for (PcaViewer viewer : pcaviewers)
 +      {
 +        String modelName = viewer.getScoreModelName();
 +        SimilarityParamsI params = new SimilarityParams(
 +                viewer.isIncludeGappedColumns(), viewer.isMatchGaps(),
 +                viewer.isIncludeGaps(),
 +                viewer.isDenominateByShortestLength());
 +
 +        /*
 +         * create the panel (without computing the PCA)
 +         */
 +        PCAPanel panel = new PCAPanel(ap, modelName, params);
 +
 +        panel.setTitle(viewer.getTitle());
 +        panel.setBounds(new Rectangle(viewer.getXpos(), viewer.getYpos(),
 +                viewer.getWidth(), viewer.getHeight()));
 +
 +        boolean showLabels = viewer.isShowLabels();
 +        panel.setShowLabels(showLabels);
 +        panel.getRotatableCanvas().setShowLabels(showLabels);
 +        panel.getRotatableCanvas()
 +                .setBgColour(new Color(viewer.getBgColour()));
 +        panel.getRotatableCanvas()
 +                .setApplyToAllViews(viewer.isLinkToAllViews());
 +
 +        /*
 +         * load PCA output data
 +         */
 +        ScoreModelI scoreModel = ScoreModels.getInstance()
 +                .getScoreModel(modelName, ap);
 +        PCA pca = new PCA(null, scoreModel, params);
 +        PcaDataType pcaData = viewer.getPcaData();
 +
 +        MatrixI pairwise = loadDoubleMatrix(pcaData.getPairwiseMatrix());
 +        pca.setPairwiseScores(pairwise);
 +
 +        MatrixI triDiag = loadDoubleMatrix(pcaData.getTridiagonalMatrix());
 +        pca.setTridiagonal(triDiag);
 +
 +        MatrixI result = loadDoubleMatrix(pcaData.getEigenMatrix());
 +        pca.setEigenmatrix(result);
 +
 +        panel.getPcaModel().setPCA(pca);
 +
 +        /*
 +         * we haven't saved the input data! (JAL-2647 to do)
 +         */
 +        panel.setInputData(null);
 +
 +        /*
 +         * add the sequence points for the PCA display
 +         */
 +        List<jalview.datamodel.SequencePoint> seqPoints = new ArrayList<>();
 +        for (SequencePoint sp : viewer.getSequencePoint())
 +        {
 +          String seqId = sp.getSequenceRef();
 +          SequenceI seq = seqRefIds.get(seqId);
 +          if (seq == null)
 +          {
 +            throw new IllegalStateException(
 +                    "Unmatched seqref for PCA: " + seqId);
 +          }
 +          Point pt = new Point(sp.getXPos(), sp.getYPos(), sp.getZPos());
 +          jalview.datamodel.SequencePoint seqPoint = new jalview.datamodel.SequencePoint(
 +                  seq, pt);
 +          seqPoints.add(seqPoint);
 +        }
 +        panel.getRotatableCanvas().setPoints(seqPoints, seqPoints.size());
 +
 +        /*
 +         * set min-max ranges and scale after setPoints (which recomputes them)
 +         */
 +        panel.getRotatableCanvas().setScaleFactor(viewer.getScaleFactor());
 +        SeqPointMin spMin = viewer.getSeqPointMin();
 +        float[] min = new float[] { spMin.getXPos(), spMin.getYPos(),
 +            spMin.getZPos() };
 +        SeqPointMax spMax = viewer.getSeqPointMax();
 +        float[] max = new float[] { spMax.getXPos(), spMax.getYPos(),
 +            spMax.getZPos() };
 +        panel.getRotatableCanvas().setSeqMinMax(min, max);
 +
 +        // todo: hold points list in PCAModel only
 +        panel.getPcaModel().setSequencePoints(seqPoints);
 +
 +        panel.setSelectedDimensionIndex(viewer.getXDim(), X);
 +        panel.setSelectedDimensionIndex(viewer.getYDim(), Y);
 +        panel.setSelectedDimensionIndex(viewer.getZDim(), Z);
 +
 +        // is this duplication needed?
 +        panel.setTop(seqPoints.size() - 1);
 +        panel.getPcaModel().setTop(seqPoints.size() - 1);
 +
 +        /*
 +         * add the axes' end points for the display
 +         */
 +        for (int i = 0; i < 3; i++)
 +        {
 +          Axis axis = viewer.getAxis().get(i);
 +          panel.getRotatableCanvas().getAxisEndPoints()[i] = new Point(
 +                  axis.getXPos(), axis.getYPos(), axis.getZPos());
 +        }
 +
 +        Desktop.addInternalFrame(panel, MessageManager.formatMessage(
 +                "label.calc_title", "PCA", modelName), 475, 450);
 +      }
 +    } catch (Exception ex)
 +    {
 +      Cache.log.error("Error loading PCA: " + ex.toString());
 +    }
 +  }
 +
 +  /**
     * Populates an XML model of the feature colour scheme for one feature type
     * 
     * @param featureType
     * @param fcol
     * @return
     */
 -  protected static jalview.schemabinding.version2.Colour marshalColour(
 +  public static Colour marshalColour(
            String featureType, FeatureColourI fcol)
    {
 -    jalview.schemabinding.version2.Colour col = new jalview.schemabinding.version2.Colour();
 +    Colour col = new Colour();
      if (fcol.isSimpleColour())
      {
        col.setRGB(Format.getHexString(fcol.getColour()));
        col.setAutoScale(fcol.isAutoScaled());
        col.setThreshold(fcol.getThreshold());
        col.setColourByLabel(fcol.isColourByLabel());
 -      col.setThreshType(fcol.isAboveThreshold() ? ColourThreshTypeType.ABOVE
 -              : (fcol.isBelowThreshold() ? ColourThreshTypeType.BELOW
 -                      : ColourThreshTypeType.NONE));
 +      col.setThreshType(fcol.isAboveThreshold() ? ThresholdType.ABOVE
 +              : (fcol.isBelowThreshold() ? ThresholdType.BELOW
 +                      : ThresholdType.NONE));
        if (fcol.isColourByAttribute())
        {
 -        col.setAttributeName(fcol.getAttributeName());
 +        final String[] attName = fcol.getAttributeName();
 +        col.getAttributeName().add(attName[0]);
 +        if (attName.length > 1)
 +        {
 +          col.getAttributeName().add(attName[1]);
 +        }
        }
        Color noColour = fcol.getNoColour();
        if (noColour == null)
     * @param and
     *          if true, conditions are and-ed, else or-ed
     */
 -  protected static MatcherSet marshalFilter(FeatureMatcherI firstMatcher,
 -          Iterator<FeatureMatcherI> filters, boolean and)
 +  public static jalview.xml.binding.jalview.FeatureMatcherSet marshalFilter(
 +          FeatureMatcherI firstMatcher, Iterator<FeatureMatcherI> filters,
 +          boolean and)
    {
 -    MatcherSet result = new MatcherSet();
 +    jalview.xml.binding.jalview.FeatureMatcherSet result = new jalview.xml.binding.jalview.FeatureMatcherSet();
    
      if (filters.hasNext())
      {
         */
        CompoundMatcher compound = new CompoundMatcher();
        compound.setAnd(and);
 -      MatcherSet matcher1 = marshalFilter(firstMatcher,
 -              Collections.emptyIterator(), and);
 -      compound.addMatcherSet(matcher1);
 +      jalview.xml.binding.jalview.FeatureMatcherSet matcher1 = marshalFilter(
 +              firstMatcher, Collections.emptyIterator(), and);
 +      // compound.addMatcherSet(matcher1);
 +      compound.getMatcherSet().add(matcher1);
        FeatureMatcherI nextMatcher = filters.next();
 -      MatcherSet matcher2 = marshalFilter(nextMatcher, filters, and);
 -      compound.addMatcherSet(matcher2);
 +      jalview.xml.binding.jalview.FeatureMatcherSet matcher2 = marshalFilter(
 +              nextMatcher, filters, and);
 +      // compound.addMatcherSet(matcher2);
 +      compound.getMatcherSet().add(matcher2);
        result.setCompoundMatcher(compound);
      }
      else
        /*
         * single condition matcher
         */
 -      MatchCondition matcherModel = new MatchCondition();
 +      // MatchCondition matcherModel = new MatchCondition();
 +      jalview.xml.binding.jalview.FeatureMatcher matcherModel = new jalview.xml.binding.jalview.FeatureMatcher();
        matcherModel.setCondition(
                firstMatcher.getMatcher().getCondition().getStableName());
        matcherModel.setValue(firstMatcher.getMatcher().getPattern());
        if (firstMatcher.isByAttribute())
        {
 -        matcherModel.setBy(FeatureMatcherByType.BYATTRIBUTE);
 -        matcherModel.setAttributeName(firstMatcher.getAttribute());
 +        matcherModel.setBy(FilterBy.BY_ATTRIBUTE);
 +        // matcherModel.setAttributeName(firstMatcher.getAttribute());
 +        String[] attName = firstMatcher.getAttribute();
 +        matcherModel.getAttributeName().add(attName[0]); // attribute
 +        if (attName.length > 1)
 +        {
 +          matcherModel.getAttributeName().add(attName[1]); // sub-attribute
 +        }
        }
        else if (firstMatcher.isByLabel())
        {
 -        matcherModel.setBy(FeatureMatcherByType.BYLABEL);
 +        matcherModel.setBy(FilterBy.BY_LABEL);
        }
        else if (firstMatcher.isByScore())
        {
 -        matcherModel.setBy(FeatureMatcherByType.BYSCORE);
 +        matcherModel.setBy(FilterBy.BY_SCORE);
        }
        result.setMatchCondition(matcherModel);
      }
     * @param matcherSetModel
     * @return
     */
 -  protected static FeatureMatcherSetI unmarshalFilter(
 -          String featureType, MatcherSet matcherSetModel)
 +  public static FeatureMatcherSetI parseFilter(
 +          String featureType,
 +          jalview.xml.binding.jalview.FeatureMatcherSet matcherSetModel)
    {
      FeatureMatcherSetI result = new FeatureMatcherSet();
      try
      {
 -      unmarshalFilterConditions(result, matcherSetModel, true);
 +      parseFilterConditions(result, matcherSetModel, true);
      } catch (IllegalStateException e)
      {
        // mixing AND and OR conditions perhaps
     * @throws IllegalStateException
     *           if AND and OR conditions are mixed
     */
 -  protected static void unmarshalFilterConditions(
 -          FeatureMatcherSetI matcherSet, MatcherSet matcherSetModel,
 +  protected static void parseFilterConditions(
 +          FeatureMatcherSetI matcherSet,
 +          jalview.xml.binding.jalview.FeatureMatcherSet matcherSetModel,
            boolean and)
    {
 -    MatchCondition mc = matcherSetModel.getMatchCondition();
 +    jalview.xml.binding.jalview.FeatureMatcher mc = matcherSetModel
 +            .getMatchCondition();
      if (mc != null)
      {
        /*
         * single condition
         */
 -      FeatureMatcherByType filterBy = mc.getBy();
 +      FilterBy filterBy = mc.getBy();
        Condition cond = Condition.fromString(mc.getCondition());
        String pattern = mc.getValue();
        FeatureMatcherI matchCondition = null;
 -      if (filterBy == FeatureMatcherByType.BYLABEL)
 +      if (filterBy == FilterBy.BY_LABEL)
        {
          matchCondition = FeatureMatcher.byLabel(cond, pattern);
        }
 -      else if (filterBy == FeatureMatcherByType.BYSCORE)
 +      else if (filterBy == FilterBy.BY_SCORE)
        {
          matchCondition = FeatureMatcher.byScore(cond, pattern);
    
        }
 -      else if (filterBy == FeatureMatcherByType.BYATTRIBUTE)
 +      else if (filterBy == FilterBy.BY_ATTRIBUTE)
        {
 -        String[] attNames = mc.getAttributeName();
 +        final List<String> attributeName = mc.getAttributeName();
 +        String[] attNames = attributeName
 +                .toArray(new String[attributeName.size()]);
          matchCondition = FeatureMatcher.byAttribute(cond, pattern,
                  attNames);
        }
        /*
         * compound condition
         */
 -      MatcherSet[] matchers = matcherSetModel.getCompoundMatcher()
 -              .getMatcherSet();
 -      boolean anded = matcherSetModel.getCompoundMatcher().getAnd();
 -      if (matchers.length == 2)
 +      List<jalview.xml.binding.jalview.FeatureMatcherSet> matchers = matcherSetModel
 +              .getCompoundMatcher().getMatcherSet();
 +      boolean anded = matcherSetModel.getCompoundMatcher().isAnd();
 +      if (matchers.size() == 2)
        {
 -        unmarshalFilterConditions(matcherSet, matchers[0], anded);
 -        unmarshalFilterConditions(matcherSet, matchers[1], anded);
 +        parseFilterConditions(matcherSet, matchers.get(0), anded);
 +        parseFilterConditions(matcherSet, matchers.get(1), anded);
        }
        else
        {
     * @param colourModel
     * @return
     */
 -  protected static FeatureColourI unmarshalColour(
 -          jalview.schemabinding.version2.Colour colourModel)
 +  public static FeatureColourI parseColour(Colour colourModel)
    {
      FeatureColourI colour = null;
    
 -    if (colourModel.hasMax())
 +    if (colourModel.getMax() != null)
      {
        Color mincol = null;
        Color maxcol = null;
          noValueColour = maxcol;
        }
    
 -      colour = new FeatureColour(mincol, maxcol, noValueColour,
 -              colourModel.getMin(),
 -              colourModel.getMax());
 -      String[] attributes = colourModel.getAttributeName();
 +      colour = new FeatureColour(maxcol, mincol, maxcol, noValueColour,
 +              safeFloat(colourModel.getMin()),
 +              safeFloat(colourModel.getMax()));
 +      final List<String> attributeName = colourModel.getAttributeName();
 +      String[] attributes = attributeName
 +              .toArray(new String[attributeName.size()]);
        if (attributes != null && attributes.length > 0)
        {
          colour.setAttributeName(attributes);
        }
 -      if (colourModel.hasAutoScale())
 +      if (colourModel.isAutoScale() != null)
        {
 -        colour.setAutoScaled(colourModel.getAutoScale());
 +        colour.setAutoScaled(colourModel.isAutoScale().booleanValue());
        }
 -      if (colourModel.hasColourByLabel())
 +      if (colourModel.isColourByLabel() != null)
        {
 -        colour.setColourByLabel(colourModel.getColourByLabel());
 +        colour.setColourByLabel(
 +                colourModel.isColourByLabel().booleanValue());
        }
 -      if (colourModel.hasThreshold())
 +      if (colourModel.getThreshold() != null)
        {
 -        colour.setThreshold(colourModel.getThreshold());
 +        colour.setThreshold(colourModel.getThreshold().floatValue());
        }
 -      ColourThreshTypeType ttyp = colourModel.getThreshType();
 -      if (ttyp != null)
 +      ThresholdType ttyp = colourModel.getThreshType();
 +      if (ttyp == ThresholdType.ABOVE)
        {
 -        if (ttyp == ColourThreshTypeType.ABOVE)
 -        {
 -          colour.setAboveThreshold(true);
 -        }
 -        else if (ttyp == ColourThreshTypeType.BELOW)
 -        {
 -          colour.setBelowThreshold(true);
 -        }
 +        colour.setAboveThreshold(true);
 +      }
 +      else if (ttyp == ThresholdType.BELOW)
 +      {
 +        colour.setBelowThreshold(true);
        }
      }
      else
@@@ -20,6 -20,7 +20,7 @@@
   */
  package jalview.schemes;
  
+ import jalview.api.AlignViewportI;
  import jalview.datamodel.AlignmentAnnotation;
  import jalview.datamodel.AlignmentI;
  import jalview.datamodel.AnnotatedCollectionI;
@@@ -76,8 -77,8 +77,8 @@@ public class AnnotationColourGradient e
    private IdentityHashMap<SequenceI, AlignmentAnnotation> seqannot = null;
  
    @Override
-   public ColourSchemeI getInstance(AnnotatedCollectionI sg,
-           Map<SequenceI, SequenceCollectionI> hiddenRepSequences)
+   public ColourSchemeI getInstance(AlignViewportI view,
+           AnnotatedCollectionI sg)
    {
      AnnotationColourGradient acg = new AnnotationColourGradient(annotation,
              getColourScheme(), aboveAnnotationThreshold);
      if (annotationThreshold != null)
      {
        if ((aboveAnnotationThreshold == ABOVE_THRESHOLD
 -              && aj.value < annotationThreshold.value)
 +              && aj.value <= annotationThreshold.value)
                || (aboveAnnotationThreshold == BELOW_THRESHOLD
 -                      && aj.value > annotationThreshold.value))
 +                      && aj.value >= annotationThreshold.value))
        {
          return Color.white;
        }
              && aboveAnnotationThreshold == ABOVE_THRESHOLD
              && value >= ann.threshold.value)
      {
 -      range = (value - ann.threshold.value)
 +      range = ann.graphMax == ann.threshold.value ? 1f
 +              : (value - ann.threshold.value)
                / (ann.graphMax - ann.threshold.value);
      }
      else if (thresholdIsMinMax && ann.threshold != null
              && aboveAnnotationThreshold == BELOW_THRESHOLD
              && value <= ann.threshold.value)
      {
 -      range = (value - ann.graphMin) / (ann.threshold.value - ann.graphMin);
 +      range = ann.graphMin == ann.threshold.value ? 0f
 +              : (value - ann.graphMin)
 +                      / (ann.threshold.value - ann.graphMin);
      }
      else
      {
    @Override
    public String getSchemeName()
    {
 -    return "Annotation";
 +    return ANNOTATION_COLOUR;
    }
  
    @Override
@@@ -662,7 -662,7 +662,7 @@@ public abstract class AlignmentViewpor
           * retain any colour thresholds per group while
           * changing choice of colour scheme (JAL-2386)
           */
-         sg.setColourScheme(cs.getInstance(sg, hiddenRepSequences));
 -        sg.setColourScheme(cs);
++        sg.setColourScheme(cs.getInstance(this, sg));
          if (cs != null)
          {
            sg.getGroupColourScheme().alignmentChanged(sg,
    public void invertColumnSelection()
    {
      colSel.invertColumnSelection(0, alignment.getWidth(), alignment);
 +    isColSelChanged(true);
    }
  
    @Override
    {
      return currentTree;
    }
+   /**
+    * flag set to indicate if structure views might be out of sync with sequences
+    * in the alignment
+    */
+   private boolean needToUpdateStructureViews = false;
+   @Override
+   public boolean isUpdateStructures()
+   {
+     return needToUpdateStructureViews;
+   }
+   @Override
+   public void setUpdateStructures(boolean update)
+   {
+     needToUpdateStructureViews = update;
+   }
+   @Override
+   public boolean needToUpdateStructureViews()
+   {
+     boolean update = needToUpdateStructureViews;
+     needToUpdateStructureViews = false;
+     return update;
+   }
+   @Override
+   public void addSequenceGroup(SequenceGroup sequenceGroup)
+   {
+     alignment.addGroup(sequenceGroup);
+     Color col = sequenceGroup.idColour;
+     if (col != null)
+     {
+       col = col.brighter();
+       for (SequenceI sq : sequenceGroup.getSequences())
+       {
+         setSequenceColour(sq, col);
+       }
+     }
+     if (codingComplement != null)
+     {
+       SequenceGroup mappedGroup = MappingUtils
+               .mapSequenceGroup(sequenceGroup, this, codingComplement);
+       if (mappedGroup.getSequences().size() > 0)
+       {
+         codingComplement.getAlignment().addGroup(mappedGroup);
+         if (col != null)
+         {
+           for (SequenceI seq : mappedGroup.getSequences())
+           {
+             codingComplement.setSequenceColour(seq, col);
+           }
+         }
+       }
+       // propagate the structure view update flag according to our own setting
+       codingComplement.setUpdateStructures(needToUpdateStructureViews);
+     }
+   }
  }
@@@ -18,7 -18,7 +18,7 @@@
   * along with Jalview.  If not, see <http://www.gnu.org/licenses/>.
   * The Jalview Authors are detailed in the 'AUTHORS' file.
   */
 -package jalview.io;
 +package jalview.project;
  
  import static org.testng.Assert.assertEquals;
  import static org.testng.Assert.assertFalse;
@@@ -27,7 -27,6 +27,7 @@@ import static org.testng.Assert.assertN
  import static org.testng.Assert.assertSame;
  import static org.testng.Assert.assertTrue;
  
 +import jalview.analysis.scoremodels.SimilarityParams;
  import jalview.api.AlignViewportI;
  import jalview.api.AlignmentViewPanel;
  import jalview.api.FeatureColourI;
@@@ -49,14 -48,10 +49,14 @@@ import jalview.gui.AlignViewport
  import jalview.gui.AlignmentPanel;
  import jalview.gui.Desktop;
  import jalview.gui.FeatureRenderer;
 -import jalview.gui.Jalview2XML;
  import jalview.gui.JvOptionPane;
 +import jalview.gui.PCAPanel;
  import jalview.gui.PopupMenu;
  import jalview.gui.SliderPanel;
 +import jalview.io.DataSourceType;
 +import jalview.io.FileFormat;
 +import jalview.io.FileLoader;
 +import jalview.io.Jalview2xmlBase;
  import jalview.renderer.ResidueShaderI;
  import jalview.schemes.AnnotationColourGradient;
  import jalview.schemes.BuriedColourScheme;
@@@ -79,8 -74,6 +79,8 @@@ import java.util.HashMap
  import java.util.List;
  import java.util.Map;
  
 +import javax.swing.JInternalFrame;
 +
  import org.testng.Assert;
  import org.testng.AssertJUnit;
  import org.testng.annotations.BeforeClass;
@@@ -109,72 -102,67 +109,73 @@@ public class Jalview2xmlTests extends J
      assertNotNull(af, "Didn't read input file " + inFile);
      int olddsann = countDsAnn(af.getViewport());
      assertTrue(olddsann > 0, "Didn't find any dataset annotations");
 -    af.changeColour_actionPerformed(JalviewColourScheme.RNAHelices
 -            .toString());
 +    af.changeColour_actionPerformed(
 +            JalviewColourScheme.RNAHelices.toString());
      assertTrue(
 -            af.getViewport().getGlobalColourScheme() instanceof RNAHelicesColour,
 +            af.getViewport()
 +                    .getGlobalColourScheme() instanceof RNAHelicesColour,
              "Couldn't apply RNA helices colourscheme");
      assertTrue(af.saveAlignment(tfile, FileFormat.Jalview),
              "Failed to store as a project.");
      af.closeMenuItem_actionPerformed(true);
      af = null;
 -    af = new FileLoader()
 -            .LoadFileWaitTillLoaded(tfile, DataSourceType.FILE);
 +    af = new FileLoader().LoadFileWaitTillLoaded(tfile,
 +            DataSourceType.FILE);
      assertNotNull(af, "Failed to import new project");
      int newdsann = countDsAnn(af.getViewport());
      assertEquals(olddsann, newdsann,
              "Differing numbers of dataset sequence annotation\nOriginally "
                      + olddsann + " and now " + newdsann);
 -    System.out
 -            .println("Read in same number of annotations as originally present ("
 +    System.out.println(
 +            "Read in same number of annotations as originally present ("
                      + olddsann + ")");
      assertTrue(
  
 -    af.getViewport().getGlobalColourScheme() instanceof RNAHelicesColour,
 +            af.getViewport()
 +                    .getGlobalColourScheme() instanceof RNAHelicesColour,
              "RNA helices colourscheme was not applied on import.");
    }
  
    @Test(groups = { "Functional" })
    public void testTCoffeeScores() throws Exception
    {
 -    String inFile = "examples/uniref50.fa", inAnnot = "examples/uniref50.score_ascii";
 +    String inFile = "examples/uniref50.fa",
 +            inAnnot = "examples/uniref50.score_ascii";
      String tfile = File.createTempFile("JalviewTest", ".jvp")
              .getAbsolutePath();
      AlignFrame af = new FileLoader().LoadFileWaitTillLoaded(inFile,
              DataSourceType.FILE);
      assertNotNull(af, "Didn't read input file " + inFile);
      af.loadJalviewDataFile(inAnnot, DataSourceType.FILE, null, null);
--    assertSame(af.getViewport().getGlobalColourScheme().getClass(),
++    AlignViewport viewport = af.getViewport();
++    assertSame(viewport.getGlobalColourScheme().getClass(),
              TCoffeeColourScheme.class, "Didn't set T-coffee colourscheme");
      assertNotNull(
-             ColourSchemeProperty.getColourScheme(
-                     af.getViewport().getAlignment(),
-                     af.getViewport().getGlobalColourScheme()
 -            ColourSchemeProperty.getColourScheme(af.getViewport(),
 -                    af.getViewport()
 -            .getAlignment(), af.getViewport().getGlobalColourScheme()
 -            .getSchemeName()), "Recognise T-Coffee score from string");
++            ColourSchemeProperty.getColourScheme(viewport,
++                    viewport.getAlignment(),
++                    viewport.getGlobalColourScheme()
 +                            .getSchemeName()),
 +            "Recognise T-Coffee score from string");
  
      assertTrue(af.saveAlignment(tfile, FileFormat.Jalview),
              "Failed to store as a project.");
      af.closeMenuItem_actionPerformed(true);
      af = null;
 -    af = new FileLoader()
 -            .LoadFileWaitTillLoaded(tfile, DataSourceType.FILE);
 +    af = new FileLoader().LoadFileWaitTillLoaded(tfile,
 +            DataSourceType.FILE);
      assertNotNull(af, "Failed to import new project");
--    assertSame(af.getViewport().getGlobalColourScheme().getClass(),
++    assertSame(viewport.getGlobalColourScheme().getClass(),
              TCoffeeColourScheme.class,
              "Didn't set T-coffee colourscheme for imported project.");
 -    System.out
 -            .println("T-Coffee score shading successfully recovered from project.");
 +    System.out.println(
 +            "T-Coffee score shading successfully recovered from project.");
    }
  
    @Test(groups = { "Functional" })
    public void testColourByAnnotScores() throws Exception
    {
 -    String inFile = "examples/uniref50.fa", inAnnot = "examples/testdata/uniref50_iupred.jva";
 +    String inFile = "examples/uniref50.fa",
 +            inAnnot = "examples/testdata/uniref50_iupred.jva";
      String tfile = File.createTempFile("JalviewTest", ".jvp")
              .getAbsolutePath();
      AlignFrame af = new FileLoader().LoadFileWaitTillLoaded(inFile,
              .getSequenceAt(0).getAnnotation("IUPredWS (Short)");
      assertTrue(
  
 -    aa != null && aa.length > 0,
 +            aa != null && aa.length > 0,
              "Didn't find any IUPred annotation to use to shade alignment.");
      AnnotationColourGradient cs = new AnnotationColourGradient(aa[0], null,
              AnnotationColourGradient.ABOVE_THRESHOLD);
 -    AnnotationColourGradient gcs = new AnnotationColourGradient(aa[0],
 -            null, AnnotationColourGradient.BELOW_THRESHOLD);
 +    AnnotationColourGradient gcs = new AnnotationColourGradient(aa[0], null,
 +            AnnotationColourGradient.BELOW_THRESHOLD);
      cs.setSeqAssociated(true);
      gcs.setSeqAssociated(true);
      af.changeColour(cs);
              "Failed to store as a project.");
      af.closeMenuItem_actionPerformed(true);
      af = null;
 -    af = new FileLoader()
 -            .LoadFileWaitTillLoaded(tfile, DataSourceType.FILE);
 +    af = new FileLoader().LoadFileWaitTillLoaded(tfile,
 +            DataSourceType.FILE);
      assertNotNull(af, "Failed to import new project");
  
      // check for group and alignment colourschemes
  
      ColourSchemeI _rcs = af.getViewport().getGlobalColourScheme();
 -    ColourSchemeI _rgcs = af.getViewport().getAlignment().getGroups()
 -            .get(0).getColourScheme();
 +    ColourSchemeI _rgcs = af.getViewport().getAlignment().getGroups().get(0)
 +            .getColourScheme();
      assertNotNull(_rcs, "Didn't recover global colourscheme");
      assertTrue(_rcs instanceof AnnotationColourGradient,
              "Didn't recover annotation colour global scheme");
  
      boolean diffseqcols = false, diffgseqcols = false;
      SequenceI[] sqs = af.getViewport().getAlignment().getSequencesArray();
 -    for (int p = 0, pSize = af.getViewport().getAlignment().getWidth(); p < pSize
 -            && (!diffseqcols || !diffgseqcols); p++)
 +    for (int p = 0, pSize = af.getViewport().getAlignment()
 +            .getWidth(); p < pSize && (!diffseqcols || !diffgseqcols); p++)
      {
        if (_rcs.findColour(sqs[0].getCharAt(p), p, sqs[0], null, 0f) != _rcs
                .findColour(sqs[5].getCharAt(p), p, sqs[5], null, 0f))
        }
      }
      assertTrue(diffseqcols, "Got Different sequence colours");
 -    System.out
 -            .println("Per sequence colourscheme (Background) successfully applied and recovered.");
 +    System.out.println(
 +            "Per sequence colourscheme (Background) successfully applied and recovered.");
  
      assertNotNull(_rgcs, "Didn't recover group colourscheme");
      assertTrue(_rgcs instanceof AnnotationColourGradient,
      assertTrue(__rcs.isSeqAssociated(),
              "Group Annotation colourscheme wasn't sequence associated");
  
 -    for (int p = 0, pSize = af.getViewport().getAlignment().getWidth(); p < pSize
 -            && (!diffseqcols || !diffgseqcols); p++)
 +    for (int p = 0, pSize = af.getViewport().getAlignment()
 +            .getWidth(); p < pSize && (!diffseqcols || !diffgseqcols); p++)
      {
 -      if (_rgcs.findColour(sqs[1].getCharAt(p), p, sqs[1], null, 0f) != _rgcs
 -              .findColour(sqs[2].getCharAt(p), p, sqs[2], null, 0f))
 +      if (_rgcs.findColour(sqs[1].getCharAt(p), p, sqs[1], null,
 +              0f) != _rgcs.findColour(sqs[2].getCharAt(p), p, sqs[2], null,
 +                      0f))
        {
          diffgseqcols = true;
        }
      }
      assertTrue(diffgseqcols, "Got Different group sequence colours");
 -    System.out
 -            .println("Per sequence (Group) colourscheme successfully applied and recovered.");
 +    System.out.println(
 +            "Per sequence (Group) colourscheme successfully applied and recovered.");
    }
  
    @Test(groups = { "Functional" })
    public void gatherViewsHere() throws Exception
    {
 -    int origCount = Desktop.getAlignFrames() == null ? 0 : Desktop
 -            .getAlignFrames().length;
 +    int origCount = Desktop.getAlignFrames() == null ? 0
 +            : Desktop.getAlignFrames().length;
      AlignFrame af = new FileLoader().LoadFileWaitTillLoaded(
              "examples/exampleFile_2_7.jar", DataSourceType.FILE);
      assertNotNull(af, "Didn't read in the example file correctly.");
            sq.findPosition(p);
            try
            {
 -            assertTrue(
 -                    (alaa.annotations[p] == null && refan.annotations[p] == null)
 -                            || alaa.annotations[p].value == refan.annotations[p].value,
 +            assertTrue((alaa.annotations[p] == null
 +                    && refan.annotations[p] == null)
 +                    || alaa.annotations[p].value == refan.annotations[p].value,
                      "Mismatch at alignment position " + p);
            } catch (NullPointerException q)
            {
 -            Assert.fail("Mismatch of alignment annotations at position "
 -                    + p + " Ref seq ann: " + refan.annotations[p]
 +            Assert.fail("Mismatch of alignment annotations at position " + p
 +                    + " Ref seq ann: " + refan.annotations[p]
                      + " alignment " + alaa.annotations[p]);
            }
          }
      AssertJUnit.assertFalse(structureStyle.sameStyle(groupStyle));
  
      groups.getAlignViewport().setViewStyle(structureStyle);
 -    AssertJUnit.assertFalse(groupStyle.sameStyle(groups.getAlignViewport()
 -            .getViewStyle()));
 -    Assert.assertTrue(structureStyle.sameStyle(groups.getAlignViewport()
 -            .getViewStyle()));
 +    AssertJUnit.assertFalse(
 +            groupStyle.sameStyle(groups.getAlignViewport().getViewStyle()));
 +    Assert.assertTrue(structureStyle
 +            .sameStyle(groups.getAlignViewport().getViewStyle()));
  
    }
  
  
      // check FileLoader returned a reference to the one alignFrame that is
      // actually on the Desktop
 -    assertSame(
 -            af,
 -            Desktop.getAlignFrameFor(af.getViewport()),
 +    assertSame(af, Desktop.getAlignFrameFor(af.getViewport()),
              "Jalview2XML.loadAlignFrame() didn't return correct AlignFrame reference for multiple view window");
  
      Desktop.explodeViews(af);
      af = new FileLoader().LoadFileWaitTillLoaded(tfile.getAbsolutePath(),
              DataSourceType.FILE);
      Assert.assertNotNull(af);
 +    Assert.assertEquals(Desktop.getAlignFrames().length,
 +            Desktop.getAlignmentPanels(
 +                    af.getViewport().getSequenceSetId()).length);
      Assert.assertEquals(
 -            Desktop.getAlignFrames().length,
 -            Desktop.getAlignmentPanels(af.getViewport().getSequenceSetId()).length);
 -    Assert.assertEquals(
 -            Desktop.getAlignmentPanels(af.getViewport().getSequenceSetId()).length,
 +            Desktop.getAlignmentPanels(
 +                    af.getViewport().getSequenceSetId()).length,
              oldviews);
    }
  
      assertTrue(Jalview2XML.isVersionStringLaterThan(null, "Test"));
      assertTrue(Jalview2XML.isVersionStringLaterThan(null, "TEST"));
      assertTrue(Jalview2XML.isVersionStringLaterThan("2.8.3", "Test"));
 -    assertTrue(Jalview2XML
 -            .isVersionStringLaterThan(null, "Automated Build"));
 +    assertTrue(
 +            Jalview2XML.isVersionStringLaterThan(null, "Automated Build"));
      assertTrue(Jalview2XML.isVersionStringLaterThan("2.8.3",
              "Automated Build"));
      assertTrue(Jalview2XML.isVersionStringLaterThan("2.8.3",
  
        n++;
      }
 -    File tfile = File
 -            .createTempFile("testStoreAndRecoverGroupReps", ".jvp");
 +    File tfile = File.createTempFile("testStoreAndRecoverGroupReps",
 +            ".jvp");
      try
      {
        new Jalview2XML(false).saveState(tfile);
         */
        List<String> hidden = hiddenSeqNames.get(ap.getViewName());
        HiddenSequences hs = alignment.getHiddenSequences();
 -      assertEquals(
 -              hidden.size(),
 -              hs.getSize(),
 +      assertEquals(hidden.size(), hs.getSize(),
                "wrong number of restored hidden sequences in "
                        + ap.getViewName());
      }
      pdbEntries[1] = new PDBEntry("3W5V", "B", Type.PDB, testFile);
      pdbEntries[2] = new PDBEntry("3W5V", "C", Type.PDB, testFile);
      pdbEntries[3] = new PDBEntry("3W5V", "D", Type.PDB, testFile);
 -    Assert.assertEquals(seqs[0].getDatasetSequence().getAllPDBEntries()
 -            .get(0), pdbEntries[0]);
 -    Assert.assertEquals(seqs[1].getDatasetSequence().getAllPDBEntries()
 -            .get(0), pdbEntries[1]);
 -    Assert.assertEquals(seqs[2].getDatasetSequence().getAllPDBEntries()
 -            .get(0), pdbEntries[2]);
 -    Assert.assertEquals(seqs[3].getDatasetSequence().getAllPDBEntries()
 -            .get(0), pdbEntries[3]);
 +    Assert.assertEquals(
 +            seqs[0].getDatasetSequence().getAllPDBEntries().get(0),
 +            pdbEntries[0]);
 +    Assert.assertEquals(
 +            seqs[1].getDatasetSequence().getAllPDBEntries().get(0),
 +            pdbEntries[1]);
 +    Assert.assertEquals(
 +            seqs[2].getDatasetSequence().getAllPDBEntries().get(0),
 +            pdbEntries[2]);
 +    Assert.assertEquals(
 +            seqs[3].getDatasetSequence().getAllPDBEntries().get(0),
 +            pdbEntries[3]);
  
      File tfile = File.createTempFile("testStoreAndRecoverPDBEntry", ".jvp");
      try
      sg.setEndRes(25);
      av.setSelectionGroup(sg);
      PopupMenu popupMenu = new PopupMenu(af.alignPanel, null, null);
 -    popupMenu.changeColour_actionPerformed(JalviewColourScheme.Strand
 -            .toString());
 +    popupMenu.changeColour_actionPerformed(
 +            JalviewColourScheme.Strand.toString());
      assertTrue(sg.getColourScheme() instanceof StrandColourScheme);
      assertEquals(al.getGroups().size(), 1);
      assertSame(al.getGroups().get(0), sg);
      fr.setColour("type2", byLabel);
  
      // type3: by score above threshold
 -    FeatureColourI byScore = new FeatureColour(Color.BLACK, Color.BLUE, 1,
 -            10);
 +    FeatureColourI byScore = new FeatureColour(null, Color.BLACK,
 +            Color.BLUE, null, 1, 10);
      byScore.setAboveThreshold(true);
      byScore.setThreshold(2f);
      fr.setColour("type3", byScore);
      fr.setColour("type4", byAF);
  
      // type5: by attribute CSQ:PolyPhen below threshold
 -    FeatureColourI byPolyPhen = new FeatureColour(Color.BLACK, Color.BLUE,
 -            1, 10);
 +    FeatureColourI byPolyPhen = new FeatureColour(null, Color.BLACK,
 +            Color.BLUE, null, 1, 10);
      byPolyPhen.setBelowThreshold(true);
      byPolyPhen.setThreshold(3f);
      byPolyPhen.setAttributeName("CSQ", "PolyPhen");
       */
      af.closeMenuItem_actionPerformed(true);
      af = null;
 -    af = new FileLoader()
 -            .LoadFileWaitTillLoaded(filePath, DataSourceType.FILE);
 +    af = new FileLoader().LoadFileWaitTillLoaded(filePath,
 +            DataSourceType.FILE);
      assertNotNull(af, "Failed to import new project");
  
      /*
      addFeature(seq, featureType, score++);
      addFeature(seq, featureType, score);
    }
 +
 +  /**
 +   * pre 2.11 - jalview 2.10 erroneously created new dataset entries for each
 +   * view (JAL-3171) this test ensures we can import and merge those views
 +   */
 +  @Test(groups = { "Functional" })
 +  public void testMergeDatasetsforViews() throws IOException
 +  {
 +    // simple project - two views on one alignment
 +    AlignFrame af = new FileLoader(false).LoadFileWaitTillLoaded(
 +            "examples/testdata/projects/twoViews.jvp", DataSourceType.FILE);
 +    assertNotNull(af);
 +    assertTrue(af.getAlignPanels().size() > 1);
 +    verifyDs(af);
 +  }
 +
 +  /**
 +   * pre 2.11 - jalview 2.10 erroneously created new dataset entries for each
 +   * view (JAL-3171) this test ensures we can import and merge those views This
 +   * is a more complex project
 +   */
 +  @Test(groups = { "Functional" })
 +  public void testMergeDatasetsforManyViews() throws IOException
 +  {
 +    Desktop.instance.closeAll_actionPerformed(null);
 +
 +    // complex project - one dataset, several views on several alignments
 +    AlignFrame af = new FileLoader(false).LoadFileWaitTillLoaded(
 +            "examples/testdata/projects/manyViews.jvp",
 +            DataSourceType.FILE);
 +    assertNotNull(af);
 +
 +    AlignmentI ds = null;
 +    for (AlignFrame alignFrame : Desktop.getAlignFrames())
 +    {
 +      if (ds == null)
 +      {
 +        ds = verifyDs(alignFrame);
 +      }
 +      else
 +      {
 +        // check that this frame's dataset matches the last
 +        assertTrue(ds == verifyDs(alignFrame));
 +      }
 +    }
 +  }
 +
 +  private AlignmentI verifyDs(AlignFrame af)
 +  {
 +    AlignmentI ds = null;
 +    for (AlignmentViewPanel ap : af.getAlignPanels())
 +    {
 +      if (ds == null)
 +      {
 +        ds = ap.getAlignment().getDataset();
 +      }
 +      else
 +      {
 +        assertTrue(ap.getAlignment().getDataset() == ds,
 +                "Dataset was not the same for imported 2.10.5 project with several alignment views");
 +      }
 +    }
 +    return ds;
 +  }
 +
 +  @Test(groups = "Functional")
 +  public void testPcaViewAssociation() throws IOException
 +  {
 +    Desktop.instance.closeAll_actionPerformed(null);
 +    final String PCAVIEWNAME = "With PCA";
 +    // create a new tempfile
 +    File tempfile = File.createTempFile("jvPCAviewAssoc", "jvp");
 +
 +    {
 +      String exampleFile = "examples/uniref50.fa";
 +      AlignFrame af = new FileLoader().LoadFileWaitTillLoaded(exampleFile,
 +              DataSourceType.FILE);
 +      assertNotNull(af, "Didn't read in the example file correctly.");
 +      AlignmentPanel origView = (AlignmentPanel) af.getAlignPanels().get(0);
 +      AlignmentPanel newview = af.newView(PCAVIEWNAME, true);
 +      // create another for good measure
 +      af.newView("Not the PCA View", true);
 +      PCAPanel pcaPanel = new PCAPanel(origView, "BLOSUM62",
 +              new SimilarityParams(true, true, true, false));
 +      // we're in the test exec thread, so we can just run synchronously here
 +      pcaPanel.run();
 +
 +      // now switch the linked view
 +      pcaPanel.selectAssociatedView(newview);
 +
 +      assertTrue(pcaPanel.getAlignViewport() == newview.getAlignViewport(),
 +              "PCA should be associated with 'With PCA' view: test is broken");
 +
 +      // now save and reload project
 +      Jalview2XML jv2xml = new jalview.project.Jalview2XML(false);
 +      tempfile.delete();
 +      jv2xml.saveState(tempfile);
 +      assertTrue(jv2xml.errorMessage == null,
 +              "Failed to save dummy project with PCA: test broken");
 +    }
 +
 +    // load again.
 +    Desktop.instance.closeAll_actionPerformed(null);
 +    AlignFrame af = new FileLoader().LoadFileWaitTillLoaded(
 +            tempfile.getCanonicalPath(), DataSourceType.FILE);
 +    JInternalFrame[] frames = Desktop.instance.getAllFrames();
 +    // PCA and the tabbed alignment view should be the only two windows on the
 +    // desktop
 +    assertEquals(frames.length, 2,
 +            "PCA and the tabbed alignment view should be the only two windows on the desktop");
 +    PCAPanel pcaPanel = (PCAPanel) frames[frames[0] == af ? 1 : 0];
 +
 +    AlignmentViewPanel restoredNewView = null;
 +    for (AlignmentViewPanel alignpanel : Desktop.getAlignmentPanels(null))
 +    {
 +      if (alignpanel.getAlignViewport() == pcaPanel.getAlignViewport())
 +      {
 +        restoredNewView = alignpanel;
 +      }
 +    }
 +    assertEquals(restoredNewView.getViewName(), PCAVIEWNAME);
 +    assertTrue(
 +            restoredNewView.getAlignViewport() == pcaPanel
 +                    .getAlignViewport(),
 +            "Didn't restore correct view association for the PCA view");
 +  }
  }
@@@ -124,18 -124,6 +124,18 @@@ public class AnnotationColourGradientTe
        Color result = testee.shadeCalculation(ann, col);
        assertEquals(result, expected, "for column " + col);
      }
 +
 +    /*
 +     * test for boundary case threshold == graphMax (JAL-3206)
 +     */
 +    float thresh = ann.threshold.value;
 +    ann.threshold.value = ann.graphMax;
 +    Color result = testee.shadeCalculation(ann, WIDTH - 1);
 +    assertEquals(result, maxColour);
 +    testee.setThresholdIsMinMax(false);
 +    result = testee.shadeCalculation(ann, WIDTH - 1);
 +    assertEquals(result, maxColour);
 +    ann.threshold.value = thresh; // reset
    }
  
    /**
        Color result = testee.shadeCalculation(ann, col);
        assertEquals(result, expected, "for column " + col);
      }
 +
 +    /*
 +     * test for boundary case threshold == graphMin (JAL-3206)
 +     */
 +    float thresh = ann.threshold.value;
 +    ann.threshold.value = ann.graphMin;
 +    Color result = testee.shadeCalculation(ann, 0);
 +    assertEquals(result, minColour);
 +    testee.setThresholdIsMinMax(false);
 +    result = testee.shadeCalculation(ann, 0);
 +    assertEquals(result, minColour);
 +    ann.threshold.value = thresh; // reset
    }
  
    /**
    {
      AnnotationColourGradient testee = new AnnotationColourGradient(ann,
              minColour, maxColour, AnnotationColourGradient.ABOVE_THRESHOLD);
-     testee = (AnnotationColourGradient) testee.getInstance(al, null);
+     testee = (AnnotationColourGradient) testee.getInstance(null, al);
  
      for (int col = 0; col < WIDTH; col++)
      {
        Color result = testee.findColour('a', col, seq);
        /*
 -       * expect white below threshold of 5
 +       * expect white at or below threshold of 5
         */
 -      Color expected = col < 5 ? Color.white : new Color(50 + 10 * col,
 +      Color expected = col <= 5 ? Color.white
 +              : new Color(50 + 10 * col,
                200 - 10 * col,
                150 + 10 * col);
        assertEquals(result, expected, "for column " + col);
      for (int col = 0; col < WIDTH; col++)
      {
        /*
 -       * colours for values >= threshold are graduated
 +       * colours for values > threshold are graduated
         * range is 6-10 so steps of 100/5 = 20
         */
        int factor = col - THRESHOLD_FIVE;
 -      Color expected = col < 5 ? Color.white : new Color(50 + 20 * factor,
 +      Color expected = col <= 5 ? Color.white
 +              : new Color(50 + 20 * factor,
                200 - 20 * factor,
                150 + 20 * factor);
        Color result = testee.findColour('a', col, seq);
    {
      AnnotationColourGradient testee = new AnnotationColourGradient(ann,
              minColour, maxColour, AnnotationColourGradient.BELOW_THRESHOLD);
-     testee = (AnnotationColourGradient) testee.getInstance(al, null);
+     testee = (AnnotationColourGradient) testee.getInstance(null, al);
    
      for (int col = 0; col < WIDTH; col++)
      {
        Color result = testee.findColour('a', col, seq);
 -      Color expected = col > 5 ? Color.white : new Color(50 + 10 * col,
 +      Color expected = col >= 5 ? Color.white
 +              : new Color(50 + 10 * col,
                200 - 10 * col, 150 + 10 * col);
        assertEquals(result, expected, "for column " + col);
      }
      for (int col = 0; col < WIDTH; col++)
      {
        /*
 -       * colours for values <= threshold are graduated
 +       * colours for values < threshold are graduated
         * range is 0-5 so steps of 100/5 = 20
         */
 -      Color expected = col > 5 ? Color.white : new Color(50 + 20 * col,
 +      Color expected = col >= 5 ? Color.white
 +              : new Color(50 + 20 * col,
                200 - 20 * col, 150 + 20 * col);
        Color result = testee.findColour('a', col, seq);
        assertEquals(result, expected, "for column " + col);
    {
      AnnotationColourGradient testee = new AnnotationColourGradient(ann,
              minColour, maxColour, AnnotationColourGradient.NO_THRESHOLD);
-     testee = (AnnotationColourGradient) testee.getInstance(al, null);
+     testee = (AnnotationColourGradient) testee.getInstance(null, al);
  
      for (int col = 0; col < WIDTH; col++)
      {
    {
      AnnotationColourGradient testee = new AnnotationColourGradient(ann,
              minColour, maxColour, AnnotationColourGradient.NO_THRESHOLD);
-     testee = (AnnotationColourGradient) testee.getInstance(al, null);
+     testee = (AnnotationColourGradient) testee.getInstance(null, al);
  
      /*
       * flag corresponding to 'use original colours' checkbox