Merge branch 'feature/JAL-3063jaxbNoCastor' into develop
authorJim Procter <jprocter@issues.jalview.org>
Wed, 16 Jan 2019 11:50:22 +0000 (11:50 +0000)
committerJim Procter <jprocter@issues.jalview.org>
Wed, 16 Jan 2019 11:50:22 +0000 (11:50 +0000)
JAL-3063 todo: add castor-1.1-cycle.jar back to libraries inorder to ensure VAMSAS functionality remains

120 files changed:
.gitignore
examples/testdata/projects/manyViews.jvp [new file with mode: 0644]
examples/testdata/projects/twoViews.jvp [new file with mode: 0644]
help/html/calculations/pca.html
help/html/releases.html
resources/lang/Messages.properties
resources/lang/Messages_es.properties
schemas/jalview.xsd
src/jalview/analysis/PCA.java
src/jalview/analysis/scoremodels/ScoreModels.java
src/jalview/analysis/scoremodels/SimilarityParams.java
src/jalview/api/FeatureRenderer.java
src/jalview/api/RotatableCanvasI.java
src/jalview/appletgui/AppletJmolBinding.java
src/jalview/appletgui/ExtJmol.java
src/jalview/appletgui/OverviewCanvas.java
src/jalview/appletgui/OverviewPanel.java
src/jalview/appletgui/PCAPanel.java
src/jalview/appletgui/RotatableCanvas.java
src/jalview/commands/EditCommand.java
src/jalview/datamodel/Point.java [new file with mode: 0644]
src/jalview/datamodel/Sequence.java
src/jalview/datamodel/SequenceGroup.java
src/jalview/datamodel/SequenceI.java
src/jalview/datamodel/SequencePoint.java
src/jalview/datamodel/features/FeatureStore.java
src/jalview/datamodel/features/SequenceFeatures.java
src/jalview/datamodel/features/SequenceFeaturesI.java
src/jalview/ext/jmol/JalviewJmolBinding.java
src/jalview/gui/CalculationChooser.java
src/jalview/gui/FeatureSettings.java
src/jalview/gui/FeatureTypeSettings.java
src/jalview/gui/OverviewCanvas.java
src/jalview/gui/PCAPanel.java
src/jalview/gui/RotatableCanvas.java
src/jalview/gui/ScalePanel.java
src/jalview/gui/TreeCanvas.java
src/jalview/gui/TreePanel.java
src/jalview/jbgui/GPCAPanel.java
src/jalview/math/Matrix.java
src/jalview/math/MatrixI.java
src/jalview/math/RotatableMatrix.java
src/jalview/math/SparseMatrix.java
src/jalview/project/Jalview2XML.java
src/jalview/schemabinding/version2/Axis.java [new file with mode: 0644]
src/jalview/schemabinding/version2/D.java [new file with mode: 0644]
src/jalview/schemabinding/version2/DoubleMatrix.java [new file with mode: 0644]
src/jalview/schemabinding/version2/DoubleVector.java [new file with mode: 0644]
src/jalview/schemabinding/version2/E.java [new file with mode: 0644]
src/jalview/schemabinding/version2/EigenMatrix.java [new file with mode: 0644]
src/jalview/schemabinding/version2/PairwiseMatrix.java [new file with mode: 0644]
src/jalview/schemabinding/version2/PcaData.java [new file with mode: 0644]
src/jalview/schemabinding/version2/PcaDataType.java [new file with mode: 0644]
src/jalview/schemabinding/version2/PcaViewer.java [new file with mode: 0644]
src/jalview/schemabinding/version2/Row.java [new file with mode: 0644]
src/jalview/schemabinding/version2/SeqPointMax.java [new file with mode: 0644]
src/jalview/schemabinding/version2/SeqPointMin.java [new file with mode: 0644]
src/jalview/schemabinding/version2/SequencePoint.java [new file with mode: 0644]
src/jalview/schemabinding/version2/TridiagonalMatrix.java [new file with mode: 0644]
src/jalview/schemabinding/version2/descriptors/AxisDescriptor.java [new file with mode: 0644]
src/jalview/schemabinding/version2/descriptors/DDescriptor.java [new file with mode: 0644]
src/jalview/schemabinding/version2/descriptors/DoubleMatrixDescriptor.java [new file with mode: 0644]
src/jalview/schemabinding/version2/descriptors/DoubleVectorDescriptor.java [new file with mode: 0644]
src/jalview/schemabinding/version2/descriptors/EDescriptor.java [new file with mode: 0644]
src/jalview/schemabinding/version2/descriptors/EigenMatrixDescriptor.java [new file with mode: 0644]
src/jalview/schemabinding/version2/descriptors/PairwiseMatrixDescriptor.java [new file with mode: 0644]
src/jalview/schemabinding/version2/descriptors/PcaDataDescriptor.java [new file with mode: 0644]
src/jalview/schemabinding/version2/descriptors/PcaDataTypeDescriptor.java [new file with mode: 0644]
src/jalview/schemabinding/version2/descriptors/PcaViewerDescriptor.java [new file with mode: 0644]
src/jalview/schemabinding/version2/descriptors/RowDescriptor.java [new file with mode: 0644]
src/jalview/schemabinding/version2/descriptors/SeqPointMaxDescriptor.java [new file with mode: 0644]
src/jalview/schemabinding/version2/descriptors/SeqPointMinDescriptor.java [new file with mode: 0644]
src/jalview/schemabinding/version2/descriptors/SequencePointDescriptor.java [new file with mode: 0644]
src/jalview/schemabinding/version2/descriptors/TridiagonalMatrixDescriptor.java [new file with mode: 0644]
src/jalview/viewmodel/PCAModel.java
src/jalview/ws/DBRefFetcher.java
src/jalview/xml/binding/jalview/AlcodonFrame.java
src/jalview/xml/binding/jalview/Annotation.java
src/jalview/xml/binding/jalview/AnnotationColourScheme.java
src/jalview/xml/binding/jalview/AnnotationElement.java
src/jalview/xml/binding/jalview/DoubleMatrix.java [new file with mode: 0644]
src/jalview/xml/binding/jalview/DoubleVector.java [new file with mode: 0644]
src/jalview/xml/binding/jalview/Feature.java
src/jalview/xml/binding/jalview/FeatureMatcher.java
src/jalview/xml/binding/jalview/FeatureMatcherSet.java
src/jalview/xml/binding/jalview/FilterBy.java
src/jalview/xml/binding/jalview/JalviewModel.java
src/jalview/xml/binding/jalview/JalviewUserColours.java
src/jalview/xml/binding/jalview/MapListType.java
src/jalview/xml/binding/jalview/Mapping.java
src/jalview/xml/binding/jalview/NoValueColour.java
src/jalview/xml/binding/jalview/ObjectFactory.java
src/jalview/xml/binding/jalview/PcaDataType.java [new file with mode: 0644]
src/jalview/xml/binding/jalview/Pdbentry.java
src/jalview/xml/binding/jalview/Sequence.java
src/jalview/xml/binding/jalview/SequenceSet.java
src/jalview/xml/binding/jalview/SequenceType.java
src/jalview/xml/binding/jalview/ThresholdType.java
src/jalview/xml/binding/jalview/VAMSAS.java
src/jalview/xml/binding/jalview/WebServiceParameterSet.java
src/jalview/xml/binding/jalview/package-info.java
test/jalview/analysis/scoremodels/ScoreModelsTest.java
test/jalview/commands/EditCommandTest.java
test/jalview/datamodel/SequenceTest.java
test/jalview/datamodel/features/FeatureStoreTest.java
test/jalview/datamodel/features/SequenceFeaturesTest.java
test/jalview/ext/htsjdk/TestHtsContigDb.java
test/jalview/ext/jmol/JmolParserTest.java
test/jalview/gui/AlignFrameTest.java
test/jalview/gui/CalculationChooserTest.java [new file with mode: 0644]
test/jalview/gui/FreeUpMemoryTest.java
test/jalview/gui/ScalePanelTest.java [new file with mode: 0644]
test/jalview/math/MatrixTest.java
test/jalview/math/RotatableMatrixTest.java [new file with mode: 0644]
test/jalview/project/Jalview2xmlTests.java
test/jalview/viewmodel/styles/ViewStyleTest.java
utils/checkstyle/README.txt
utils/checkstyle/checkstyle-suppress.xml
utils/checkstyle/checkstyle.xml
utils/checkstyle/import-control.xml

index 86637df..d355a80 100644 (file)
@@ -14,3 +14,4 @@ TESTNG
 /jalviewApplet.jar
 /benchmarking/lib
 *.class
+/site
diff --git a/examples/testdata/projects/manyViews.jvp b/examples/testdata/projects/manyViews.jvp
new file mode 100644 (file)
index 0000000..065b29c
Binary files /dev/null and b/examples/testdata/projects/manyViews.jvp differ
diff --git a/examples/testdata/projects/twoViews.jvp b/examples/testdata/projects/twoViews.jvp
new file mode 100644 (file)
index 0000000..80333cd
Binary files /dev/null and b/examples/testdata/projects/twoViews.jvp differ
index 0104078..5b76d10 100755 (executable)
     <em>Calculating PCAs for aligned sequences</em><br />Jalview can
     perform PCA analysis on both proteins and nucleotide sequence
     alignments. In both cases, components are generated by an
-    eigenvector decomposition of the matrix formed from the sum of
-    substitution matrix scores at each aligned position between each
-    pair of sequences - computed with one of the available score
-    matrices, such as <a href="scorematrices.html#blosum62">BLOSUM62</a>,
+    eigenvector decomposition of the matrix formed from pairwise similarity
+    scores between each pair of sequences. The similarity score model is 
+    selected on the <a href="calculations.html">calculations dialog</a>, and
+    may use one of the available score matrices, such as 
+    <a href="scorematrices.html#blosum62">BLOSUM62</a>,
     <a href="scorematrices.html#pam250">PAM250</a>, or the <a
       href="scorematrices.html#simplenucleotide">simple single
-      nucleotide substitution matrix</a>. The options available for
-    calculation are given in the <strong><em>Change
-        Parameters</em></strong> menu.
+      nucleotide substitution matrix</a>, or by sequence percentage identity,
+      or sequence feature similarity. 
   </p>
   <img src="pcaviewer.gif">
   <p>
index af417a7..0fba08a 100755 (executable)
@@ -71,25 +71,64 @@ li:before {
       <td width="60" nowrap>
         <div align="center">
           <strong><a name="Jalview.2.11.0">2.11.0</a><br />
-            <em>8/09/2018</em></strong>
+            <em>29/01/2019</em></strong>
         </div>
       </td>
-      <td><div align="left">
-          <em></em>
-          <ul>
-            <li>
-              <!-- JAL-2865 -->Jalview doesn't hang when closing windows or the overview updates with large alignments.
-            </li>
-          </ul>
-        </div></td>
-      <td><div align="left">
-          <em></em>
-          <ul>
-            <li>
-              <!-- JAL-3035 -->DAS sequence retrieval and annotation capabilities removed from the Jalview Desktop
-            </li>
-          </ul>
-        </div></td>
+    <td><div align="left">
+        <em>Deprecations</em>
+        <ul>
+          <li>
+            <!-- JAL-3035 -->DAS sequence retrieval and annotation
+            capabilities removed from the Jalview Desktop
+          </li>
+        </ul>
+        <em>Release Processes</em>
+        <ul>
+        <li>Atlassian Bamboo continuous integration server for unattended Test Suite execution</li>
+        <li><!-- JAL-2864 -->Memory test suite to detect leaks in common operations</li> 
+        </ul>
+      </div></td>
+    <td><div align="left">
+        <em></em>
+        <ul>
+          <li>
+            <!-- JAL-2865 -->Jalview hangs when closing windows
+            or the overview updates with large alignments.
+          </li>
+          <li>
+            <!-- JAL-2865 -->Tree and PCA calculation fails for selected
+            region if columns were selected by dragging right-to-left
+            and the mouse moved to the left of the first column.
+          </li>
+          <li>
+            <!-- JAL-2846 -->Error message for trying to load in invalid
+            URLs doesn't tell users the invalid URL
+          </li>
+        </ul>
+        <em>Editing</em>
+        <ul>
+          <li>
+            <!-- JAL-2822 -->Start and End should be updated when
+            sequence data at beginning or end of alignment added/removed
+            via 'Edit' sequence
+          </li>
+          <li>
+            <!-- JAL-2541 -->Delete/Cut selection doesn't relocate
+            sequence features correctly when start of sequence is
+            removed (Known defect since 2.10)
+          </li>
+          <li>
+            <!-- JAL- -->
+          </li>
+        </ul>
+        <em>New Known Defects</em>
+        <ul>
+          <li>
+            <!-- JAL-3178 -->Nonpositional features lose feature group
+            on export as jalview features file
+          </li>
+        </ul>
+      </div></td>
     </tr>
     <tr>
     <td width="60" nowrap>
index ae5b0e7..43e055d 100644 (file)
@@ -172,10 +172,9 @@ label.principal_component_analysis = Principal Component Analysis
 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
@@ -416,7 +415,7 @@ 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
@@ -879,7 +878,6 @@ label.error_unsupported_owwner_user_colour_scheme = Unsupported owner for User C
 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
@@ -1284,7 +1282,6 @@ label.SEQUENCE_ID_for_DB_ACCESSION1 = Please review your URL links in the 'Conne
 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:
@@ -1352,7 +1349,6 @@ label.colour_by_text = Colour by text
 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
@@ -1363,3 +1359,5 @@ label.most_bound_molecules = Most Bound Molecules
 label.most_polymer_residues = Most Polymer Residues
 label.cached_structures = Cached Structures
 label.free_text_search = Free Text Search
+label.configuration = Configuration
+label.configure_feature_tooltip = Click to configure variable colour or filters
index 555977d..5aed0cb 100644 (file)
@@ -169,10 +169,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
@@ -804,7 +803,6 @@ label.error_unsupported_owwner_user_colour_scheme = Propietario no soportado par
 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
@@ -1285,7 +1283,6 @@ label.SEQUENCE_ID_for_DB_ACCESSION1 = Por favor, revise sus URLs en la pesta
 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:
@@ -1353,7 +1350,6 @@ label.colour_by_text = Colorear por texto
 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
@@ -1364,3 +1360,5 @@ label.most_bound_molecules = M
 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.configuration = Configuración
+label.configure_feature_tooltip = Haga clic para configurar el color o los filtros
index 7511ad2..07dee98 100755 (executable)
                                                        </xs:annotation>
                                                </xs:attribute>
                                                <xs:attributeGroup ref="jv:swingwindow" />
+                                               <xs:attribute name="linkToAllViews" use="optional" default="false" type="xs:boolean" />
+                                       </xs:complexType>
+                               </xs:element>
+                               <xs:element name="PcaViewer" minOccurs="0" maxOccurs="unbounded">
+                                       <xs:complexType>
+                                               <xs:sequence>
+                                                       <xs:element name="sequencePoint" minOccurs="1" maxOccurs="unbounded">
+                                                               <xs:complexType>
+                                                                       <xs:attribute name="sequenceRef" type="xs:string" />
+                                                                       <xs:attributeGroup ref="jv:position" />
+                                                               </xs:complexType>
+                                                       </xs:element>
+                                                       <xs:element name="axis" minOccurs="3" maxOccurs="3">
+                                                               <xs:annotation>
+                                                                       <xs:documentation>
+                                                                               endpoints of X, Y and Z axes in that order
+                                                                       </xs:documentation>
+                                                               </xs:annotation>
+                                                               <xs:complexType>
+                                                                       <xs:attributeGroup ref="jv:position" />
+                                                               </xs:complexType>
+                                                       </xs:element>
+                                                       <xs:element name="seqPointMin">
+                                                               <xs:complexType>
+                                                                       <xs:attributeGroup ref="jv:position" />
+                                                               </xs:complexType>
+                                                       </xs:element>
+                                                       <xs:element name="seqPointMax">
+                                                               <xs:complexType>
+                                                                       <xs:attributeGroup ref="jv:position" />
+                                                               </xs:complexType>
+                                                       </xs:element>
+                                                       <xs:element name="pcaData" type="jv:PcaDataType" />
+                                               </xs:sequence>
+                                               <xs:attribute name="title" type="xs:string" />
+                                               <xs:attribute name="scoreModelName" type="xs:string" />
+                                               <xs:attribute name="xDim" type="xs:int" />
+                                               <xs:attribute name="yDim" type="xs:int" />
+                                               <xs:attribute name="zDim" type="xs:int" />
+                                               <xs:attribute name="bgColour" type="xs:int" />
+                                               <xs:attribute name="scaleFactor" type="xs:float" />
+                                               <xs:attribute name="showLabels" type="xs:boolean" />
+                                               <xs:attribute name="linkToAllViews" type="xs:boolean" />
+                                               <xs:attributeGroup ref="jv:SimilarityParams" />
+                                               <xs:attributeGroup ref="jv:swingwindow" />
                                        </xs:complexType>
                                </xs:element>
                                <xs:element name="FeatureSettings" minOccurs="0">
                <xs:attribute name="predefinedColours" type="xs:boolean"
                        use="optional" />
        </xs:complexType>
-
+       <xs:attributeGroup name="SimilarityParams">
+               <xs:annotation>
+                       <xs:documentation>
+                               parameters that condition a similarity score calculation
+                       </xs:documentation>
+               </xs:annotation>
+               <xs:attribute name="includeGaps" type="xs:boolean" />
+               <xs:attribute name="matchGaps" type="xs:boolean" />
+               <xs:attribute name="includeGappedColumns" type="xs:boolean" />
+               <xs:attribute name="denominateByShortestLength" type="xs:boolean" />
+       </xs:attributeGroup>
+       <xs:attributeGroup name="position">
+               <xs:attribute name="xPos" type="xs:float" />
+               <xs:attribute name="yPos" type="xs:float" />
+               <xs:attribute name="zPos" type="xs:float" />
+       </xs:attributeGroup>
+       <xs:complexType name="PcaDataType">
+               <xs:annotation>
+                       <xs:documentation>
+                               The results of a PCA calculation
+                       </xs:documentation>
+               </xs:annotation>
+               <xs:sequence>
+                       <xs:element name="pairwiseMatrix" type="jv:DoubleMatrix" />
+                       <xs:element name="tridiagonalMatrix" type="jv:DoubleMatrix" />
+                       <xs:element name="eigenMatrix" type="jv:DoubleMatrix" />
+               </xs:sequence>
+       </xs:complexType>
+       <xs:complexType name="DoubleVector">
+               <xs:sequence>
+                       <xs:element name="v" type="xs:double" minOccurs="0" maxOccurs="unbounded" />
+               </xs:sequence>
+       </xs:complexType>
+       <xs:complexType name="DoubleMatrix">
+               <xs:sequence>
+                       <xs:element name="row" type="jv:DoubleVector" minOccurs="0" maxOccurs="unbounded" />
+                       <xs:element name="D" minOccurs="0" type="jv:DoubleVector" />
+                       <xs:element name="E" minOccurs="0" type="jv:DoubleVector" />
+               </xs:sequence>
+               <xs:attribute name="rows"  type="xs:int" />
+               <xs:attribute name="columns" type="xs:int" />
+       </xs:complexType>
 </xs:schema>
index 42a168d..d51f00e 100755 (executable)
@@ -22,7 +22,9 @@ package jalview.analysis;
 
 import jalview.api.analysis.ScoreModelI;
 import jalview.api.analysis.SimilarityParamsI;
+import jalview.bin.Cache;
 import jalview.datamodel.AlignmentView;
+import jalview.datamodel.Point;
 import jalview.math.MatrixI;
 
 import java.io.PrintStream;
@@ -32,28 +34,37 @@ import java.io.PrintStream;
  */
 public class PCA implements Runnable
 {
-  MatrixI symm;
-
-  double[] eigenvalue;
+  /*
+   * inputs
+   */
+  final private AlignmentView seqs;
 
-  MatrixI eigenvector;
+  final private ScoreModelI scoreModel;
 
-  StringBuilder details = new StringBuilder(1024);
+  final private SimilarityParamsI similarityParams;
 
-  final private AlignmentView seqs;
+  /*
+   * outputs
+   */
+  private MatrixI pairwiseScores;
 
-  private ScoreModelI scoreModel;
+  private MatrixI tridiagonal;
 
-  private SimilarityParamsI similarityParams;
+  private MatrixI eigenMatrix;
 
-  public PCA(AlignmentView s, ScoreModelI sm, SimilarityParamsI options)
+  /**
+   * Constructor given the sequences to compute for, the similarity model to
+   * use, and a set of parameters for sequence comparison
+   * 
+   * @param sequences
+   * @param sm
+   * @param options
+   */
+  public PCA(AlignmentView sequences, ScoreModelI sm, SimilarityParamsI options)
   {
-    this.seqs = s;
-    this.similarityParams = options;
+    this.seqs = sequences;
     this.scoreModel = sm;
-
-    details.append("PCA calculation using " + sm.getName()
-            + " sequence similarity matrix\n========\n\n");
+    this.similarityParams = options;
   }
 
   /**
@@ -66,7 +77,7 @@ public class PCA implements Runnable
    */
   public double getEigenvalue(int i)
   {
-    return eigenvector.getD()[i];
+    return eigenMatrix.getD()[i];
   }
 
   /**
@@ -83,15 +94,16 @@ public class PCA implements Runnable
    * 
    * @return DOCUMENT ME!
    */
-  public float[][] getComponents(int l, int n, int mm, float factor)
+  public Point[] getComponents(int l, int n, int mm, float factor)
   {
-    float[][] out = new float[getHeight()][3];
+    Point[] out = new Point[getHeight()];
 
     for (int i = 0; i < getHeight(); i++)
     {
-      out[i][0] = (float) component(i, l) * factor;
-      out[i][1] = (float) component(i, n) * factor;
-      out[i][2] = (float) component(i, mm) * factor;
+      float x = (float) component(i, l) * factor;
+      float y = (float) component(i, n) * factor;
+      float z = (float) component(i, mm) * factor;
+      out[i] = new Point(x, y, z);
     }
 
     return out;
@@ -132,84 +144,111 @@ public class PCA implements Runnable
   {
     double out = 0.0;
 
-    for (int i = 0; i < symm.width(); i++)
+    for (int i = 0; i < pairwiseScores.width(); i++)
     {
-      out += (symm.getValue(row, i) * eigenvector.getValue(i, n));
+      out += (pairwiseScores.getValue(row, i) * eigenMatrix.getValue(i, n));
     }
 
-    return out / eigenvector.getD()[n];
+    return out / eigenMatrix.getD()[n];
   }
 
+  /**
+   * Answers a formatted text report of the PCA calculation results (matrices
+   * and eigenvalues) suitable for display
+   * 
+   * @return
+   */
   public String getDetails()
   {
-    return details.toString();
+    StringBuilder sb = new StringBuilder(1024);
+    sb.append("PCA calculation using ").append(scoreModel.getName())
+            .append(" sequence similarity matrix\n========\n\n");
+    PrintStream ps = wrapOutputBuffer(sb);
+    
+    /*
+     * pairwise similarity scores
+     */
+    sb.append(" --- OrigT * Orig ---- \n");
+    pairwiseScores.print(ps, "%8.2f");
+    
+    /*
+     * tridiagonal matrix, with D and E vectors
+     */
+    sb.append(" ---Tridiag transform matrix ---\n");
+    sb.append(" --- D vector ---\n");
+    tridiagonal.printD(ps, "%15.4e");
+    ps.println();
+    sb.append("--- E vector ---\n");
+    tridiagonal.printE(ps, "%15.4e");
+    ps.println();
+    
+    /*
+     * eigenvalues matrix, with D vector
+     */
+    sb.append(" --- New diagonalization matrix ---\n");
+    eigenMatrix.print(ps, "%8.2f");
+    sb.append(" --- Eigenvalues ---\n");
+    eigenMatrix.printD(ps, "%15.4e");
+    ps.println();
+    
+    return sb.toString();
   }
 
   /**
-   * DOCUMENT ME!
+   * Performs the PCA calculation
    */
   @Override
   public void run()
   {
+    try
+    {
+      /*
+       * sequence pairwise similarity scores
+       */
+      pairwiseScores = scoreModel.findSimilarities(seqs, similarityParams);
+
+      /*
+       * tridiagonal matrix
+       */
+      tridiagonal = pairwiseScores.copy();
+      tridiagonal.tred();
+
+      /*
+       * the diagonalization matrix
+       */
+      eigenMatrix = tridiagonal.copy();
+      eigenMatrix.tqli();
+    } catch (Exception q)
+    {
+      Cache.log.error("Error computing PCA:  " + q.getMessage());
+      q.printStackTrace();
+    }
+  }
+
+  /**
+   * Returns a PrintStream that wraps (appends its output to) the given
+   * StringBuilder
+   * 
+   * @param sb
+   * @return
+   */
+  protected PrintStream wrapOutputBuffer(StringBuilder sb)
+  {
     PrintStream ps = new PrintStream(System.out)
     {
       @Override
       public void print(String x)
       {
-        details.append(x);
+        sb.append(x);
       }
 
       @Override
       public void println()
       {
-        details.append("\n");
+        sb.append("\n");
       }
     };
-
-    // long now = System.currentTimeMillis();
-    try
-    {
-      eigenvector = scoreModel.findSimilarities(seqs, similarityParams);
-
-      details.append(" --- OrigT * Orig ---- \n");
-      eigenvector.print(ps, "%8.2f");
-
-      symm = eigenvector.copy();
-
-      eigenvector.tred();
-
-      details.append(" ---Tridiag transform matrix ---\n");
-      details.append(" --- D vector ---\n");
-      eigenvector.printD(ps, "%15.4e");
-      ps.println();
-      details.append("--- E vector ---\n");
-      eigenvector.printE(ps, "%15.4e");
-      ps.println();
-
-      // Now produce the diagonalization matrix
-      eigenvector.tqli();
-    } catch (Exception q)
-    {
-      q.printStackTrace();
-      details.append("\n*** Unexpected exception when performing PCA ***\n"
-              + q.getLocalizedMessage());
-      details.append(
-              "*** Matrices below may not be fully diagonalised. ***\n");
-    }
-
-    details.append(" --- New diagonalization matrix ---\n");
-    eigenvector.print(ps, "%8.2f");
-    details.append(" --- Eigenvalues ---\n");
-    eigenvector.printD(ps, "%15.4e");
-    ps.println();
-    /*
-     * for (int seq=0;seq<symm.rows;seq++) { ps.print("\"Seq"+seq+"\""); for
-     * (int ev=0;ev<symm.rows; ev++) {
-     * 
-     * ps.print(","+component(seq, ev)); } ps.println(); }
-     */
-    // System.out.println(("PCA.run() took "
-    // + (System.currentTimeMillis() - now) + "ms"));
+    return ps;
   }
 
   /**
@@ -221,6 +260,42 @@ public class PCA implements Runnable
   public int getHeight()
   {
     // TODO can any of seqs[] be null?
-    return seqs.getSequences().length;
+    return pairwiseScores.height();// seqs.getSequences().length;
+  }
+
+  /**
+   * Answers the sequence pairwise similarity scores which were the first step
+   * of the PCA calculation
+   * 
+   * @return
+   */
+  public MatrixI getPairwiseScores()
+  {
+    return pairwiseScores;
+  }
+
+  public void setPairwiseScores(MatrixI m)
+  {
+    pairwiseScores = m;
+  }
+
+  public MatrixI getEigenmatrix()
+  {
+    return eigenMatrix;
+  }
+
+  public void setEigenmatrix(MatrixI m)
+  {
+    eigenMatrix = m;
+  }
+
+  public MatrixI getTridiagonal()
+  {
+    return tridiagonal;
+  }
+
+  public void setTridiagonal(MatrixI tridiagonal)
+  {
+    this.tridiagonal = tridiagonal;
   }
 }
index 7262fb8..3cbd5f1 100644 (file)
@@ -66,11 +66,11 @@ public class ScoreModels
     /*
      * using LinkedHashMap keeps models ordered as added
      */
-    models = new LinkedHashMap<String, ScoreModelI>();
+    models = new LinkedHashMap<>();
     BLOSUM62 = loadScoreMatrix("scoreModel/blosum62.scm");
     PAM250 = loadScoreMatrix("scoreModel/pam250.scm");
-    registerScoreModel(new PIDModel());
     DNA = loadScoreMatrix("scoreModel/dna.scm");
+    registerScoreModel(new PIDModel());
     registerScoreModel(new FeatureDistanceModel());
   }
 
index 58b08dd..5c47703 100644 (file)
@@ -147,4 +147,57 @@ public class SimilarityParams implements SimilarityParamsI
   {
     return matchGaps;
   }
+
+  /**
+   * IDE-generated hashCode method
+   */
+  @Override
+  public int hashCode()
+  {
+    final int prime = 31;
+    int result = 1;
+    result = prime * result + (denominateByShortestLength ? 1231 : 1237);
+    result = prime * result + (includeGappedColumns ? 1231 : 1237);
+    result = prime * result + (includeGaps ? 1231 : 1237);
+    result = prime * result + (matchGaps ? 1231 : 1237);
+    return result;
+  }
+
+  /**
+   * IDE-generated equals method
+   */
+  @Override
+  public boolean equals(Object obj)
+  {
+    if (this == obj)
+    {
+      return true;
+    }
+    if (obj == null)
+    {
+      return false;
+    }
+    if (getClass() != obj.getClass())
+    {
+      return false;
+    }
+    SimilarityParams other = (SimilarityParams) obj;
+    if (denominateByShortestLength != other.denominateByShortestLength)
+    {
+      return false;
+    }
+    if (includeGappedColumns != other.includeGappedColumns)
+    {
+      return false;
+    }
+    if (includeGaps != other.includeGaps)
+    {
+      return false;
+    }
+    if (matchGaps != other.matchGaps)
+    {
+      return false;
+    }
+    return true;
+  }
 }
index cf3c8da..868f196 100644 (file)
@@ -255,11 +255,11 @@ public interface FeatureRenderer
    * <p>
    * Returns null if
    * <ul>
-   * <li>feature type is not visible, or</li>
    * <li>feature group is not visible, or</li>
    * <li>feature values lie outside any colour threshold, or</li>
    * <li>feature is excluded by filter conditions</li>
    * </ul>
+   * This method does not check feature type visibility.
    * 
    * @param feature
    * @return
index a57bcdb..c6eb6de 100644 (file)
@@ -1,6 +1,6 @@
 /*
- * Jalview - A Sequence Alignment Editor and Viewer ($$Version-Rel$$)
- * Copyright (C) $$Year-Rel$$ The Jalview Authors
+ * Jalview - A Sequence Alignment Editor and Viewer (Version 2.8.2b1)
+ * Copyright (C) 2014 The Jalview Authors
  * 
  * This file is part of Jalview.
  * 
@@ -22,7 +22,7 @@ package jalview.api;
 
 import jalview.datamodel.SequencePoint;
 
-import java.util.Vector;
+import java.util.List;
 
 /**
  * interface implemented by RotatatableCanvas GUI elements (such as point clouds
@@ -33,7 +33,23 @@ import java.util.Vector;
  */
 public interface RotatableCanvasI
 {
+  void setPoints(List<SequencePoint> points, int rows);
 
-  void setPoints(Vector<SequencePoint> points, int rows);
+  /**
+   * Zoom the view in (or out) by the given factor, which should be >= 0. A
+   * factor greater than 1 zooms in (expands the display), a factor less than 1
+   * zooms out (shrinks the display).
+   * 
+   * @param factor
+   */
+  void zoom(float factor);
 
+  /**
+   * Rotates the view by the specified number of degrees about the x and/or y
+   * axis
+   * 
+   * @param x
+   * @param y
+   */
+  void rotate(float x, float y);
 }
index 2f61b24..e5767b6 100644 (file)
@@ -24,7 +24,6 @@ import jalview.api.AlignmentViewPanel;
 import jalview.datamodel.PDBEntry;
 import jalview.datamodel.SequenceI;
 import jalview.ext.jmol.JalviewJmolBinding;
-import jalview.gui.IProgressIndicator;
 import jalview.io.DataSourceType;
 import jalview.structure.StructureSelectionManager;
 
@@ -174,21 +173,12 @@ class AppletJmolBinding extends JalviewJmolBinding
   @Override
   public int[] resizeInnerPanel(String data)
   {
-    // TODO Auto-generated method stub
     return null;
   }
 
   @Override
   public Map<String, Object> getJSpecViewProperty(String arg0)
   {
-    // TODO Auto-generated method stub
-    return null;
-  }
-
-  @Override
-  protected IProgressIndicator getIProgressIndicator()
-  {
-    // no progress indicators on the applet
     return null;
   }
 }
index 89228d5..b0d3f7a 100644 (file)
@@ -26,7 +26,6 @@ import jalview.api.SequenceRenderer;
 import jalview.datamodel.PDBEntry;
 import jalview.datamodel.SequenceI;
 import jalview.ext.jmol.JalviewJmolBinding;
-import jalview.gui.IProgressIndicator;
 import jalview.io.DataSourceType;
 
 import java.awt.Container;
@@ -66,18 +65,8 @@ public class ExtJmol extends JalviewJmolBinding
   }
 
   @Override
-  protected IProgressIndicator getIProgressIndicator()
-  {
-    // no progress indicators on applet (could access javascript for this)
-    return null;
-  }
-
-  @Override
   public void updateColours(Object source)
   {
-
-    // TODO Auto-generated method stub
-
   }
 
   @Override
@@ -190,7 +179,6 @@ public class ExtJmol extends JalviewJmolBinding
   protected JmolAppConsoleInterface createJmolConsole(
           Container consolePanel, String buttonsToShow)
   {
-    // TODO Auto-generated method stub
     return null;
   }
 
@@ -205,14 +193,11 @@ public class ExtJmol extends JalviewJmolBinding
   @Override
   public void releaseReferences(Object svl)
   {
-    // TODO Auto-generated method stub
-
   }
 
   @Override
   public Map<String, Object> getJSpecViewProperty(String arg0)
   {
-    // TODO Auto-generated method stub
     return null;
   }
 
index e99c021..07f5919 100644 (file)
@@ -162,4 +162,12 @@ public class OverviewCanvas extends Component
     }
   }
 
+  /**
+   * Nulls references to protect against potential memory leaks
+   */
+  void dispose()
+  {
+    od = null;
+  }
+
 }
index 3bbbe95..5081509 100755 (executable)
@@ -334,6 +334,10 @@ public class OverviewPanel extends Panel implements Runnable,
     } finally
     {
       av = null;
+      if (oviewCanvas != null)
+      {
+        oviewCanvas.dispose();
+      }
       oviewCanvas = null;
       ap = null;
       od = null;
index fc1d359..7c0dfa9 100644 (file)
@@ -134,7 +134,7 @@ public class PCAPanel extends EmbmenuFrame
     {
       nuclSetting.setState(pcaModel.isNucleotide());
       protSetting.setState(!pcaModel.isNucleotide());
-      pcaModel.run();
+      pcaModel.calculate();
       // ////////////////
       xCombobox.select(0);
       yCombobox.select(1);
@@ -167,9 +167,7 @@ public class PCAPanel extends EmbmenuFrame
     int dim2 = top - yCombobox.getSelectedIndex();
     int dim3 = top - zCombobox.getSelectedIndex();
     pcaModel.updateRcView(dim1, dim2, dim3);
-    rc.img = null;
-    rc.rotmat.setIdentity();
-    rc.initAxes();
+    rc.resetView();
     rc.paint(rc.getGraphics());
   }
 
@@ -281,7 +279,7 @@ public class PCAPanel extends EmbmenuFrame
     {
     }
     ;
-    Object[] alAndColsel = pcaModel.getSeqtrings()
+    Object[] alAndColsel = pcaModel.getInputData()
             .getAlignmentAndHiddenColumns(gc);
 
     if (alAndColsel != null && alAndColsel[0] != null)
index afb4e95..34f8ea5 100755 (executable)
 package jalview.appletgui;
 
 import jalview.api.RotatableCanvasI;
+import jalview.datamodel.Point;
 import jalview.datamodel.SequenceGroup;
 import jalview.datamodel.SequenceI;
 import jalview.datamodel.SequencePoint;
 import jalview.math.RotatableMatrix;
-import jalview.util.Format;
+import jalview.math.RotatableMatrix.Axis;
 import jalview.util.MessageManager;
 import jalview.viewmodel.AlignmentViewport;
 
@@ -40,32 +41,26 @@ import java.awt.event.KeyListener;
 import java.awt.event.MouseEvent;
 import java.awt.event.MouseListener;
 import java.awt.event.MouseMotionListener;
-import java.util.Vector;
+import java.util.List;
 
 public class RotatableCanvas extends Panel implements MouseListener,
         MouseMotionListener, KeyListener, RotatableCanvasI
 {
-  RotatableMatrix idmat = new RotatableMatrix(3, 3);
-
-  RotatableMatrix objmat = new RotatableMatrix(3, 3);
-
-  RotatableMatrix rotmat = new RotatableMatrix(3, 3);
+  private static final int DIMS = 3;
 
   String tooltip;
 
-  int toolx, tooly;
+  int toolx;
+
+  int tooly;
 
   // RubberbandRectangle rubberband;
 
   boolean drawAxes = true;
 
-  int omx = 0;
-
-  int mx = 0;
-
-  int omy = 0;
+  int mouseX = 0;
 
-  int my = 0;
+  int mouseY = 0;
 
   Image img;
 
@@ -73,13 +68,13 @@ public class RotatableCanvas extends Panel implements MouseListener,
 
   Dimension prefsize;
 
-  float centre[] = new float[3];
+  Point centre;
 
-  float width[] = new float[3];
+  float[] width = new float[DIMS];
 
-  float max[] = new float[3];
+  float[] max = new float[DIMS];
 
-  float min[] = new float[3];
+  float[] min = new float[DIMS];
 
   float maxwidth;
 
@@ -87,11 +82,11 @@ public class RotatableCanvas extends Panel implements MouseListener,
 
   int npoint;
 
-  Vector points;
+  List<SequencePoint> points;
 
-  float[][] orig;
+  Point[] orig;
 
-  float[][] axes;
+  Point[] axisEndPoints;
 
   int startx;
 
@@ -115,9 +110,10 @@ public class RotatableCanvas extends Panel implements MouseListener,
 
   boolean showLabels = false;
 
-  public RotatableCanvas(AlignmentViewport av)
+  public RotatableCanvas(AlignmentViewport viewport)
   {
-    this.av = av;
+    this.av = viewport;
+    axisEndPoints = new Point[DIMS];
   }
 
   public void showLabels(boolean b)
@@ -126,46 +122,23 @@ public class RotatableCanvas extends Panel implements MouseListener,
     repaint();
   }
 
-  public void setPoints(Vector points, int npoint)
+  @Override
+  public void setPoints(List<SequencePoint> points, int npoint)
   {
     this.points = points;
     this.npoint = npoint;
     PaintRefresher.Register(this, av.getSequenceSetId());
 
     prefsize = getPreferredSize();
-    orig = new float[npoint][3];
+    orig = new Point[npoint];
 
     for (int i = 0; i < npoint; i++)
     {
-      SequencePoint sp = (SequencePoint) points.elementAt(i);
-      for (int j = 0; j < 3; j++)
-      {
-        orig[i][j] = sp.coord[j];
-      }
-    }
-    // Initialize the matrices to identity
-
-    for (int i = 0; i < 3; i++)
-    {
-      for (int j = 0; j < 3; j++)
-      {
-        if (i != j)
-        {
-          idmat.addElement(i, j, 0);
-          objmat.addElement(i, j, 0);
-          rotmat.addElement(i, j, 0);
-        }
-        else
-        {
-          idmat.addElement(i, j, 0);
-          objmat.addElement(i, j, 0);
-          rotmat.addElement(i, j, 0);
-        }
-      }
+      SequencePoint sp = points.get(i);
+      orig[i] = sp.coord;
     }
 
-    axes = new float[3][3];
-    initAxes();
+    resetAxes();
 
     findCentre();
     findWidth();
@@ -195,115 +168,93 @@ public class RotatableCanvas extends Panel implements MouseListener,
    * super.removeNotify(); }
    */
 
-  public void initAxes()
+  /**
+   * Resets axes to the initial state: x-axis to the right, y-axis up, z-axis to
+   * back (so obscured in a 2-D display)
+   */
+  public void resetAxes()
   {
-    for (int i = 0; i < 3; i++)
-    {
-      for (int j = 0; j < 3; j++)
-      {
-        if (i != j)
-        {
-          axes[i][j] = 0;
-        }
-        else
-        {
-          axes[i][j] = 1;
-        }
-      }
-    }
+    axisEndPoints[0] = new Point(1f, 0f, 0f);
+    axisEndPoints[1] = new Point(0f, 1f, 0f);
+    axisEndPoints[2] = new Point(0f, 0f, 1f);
   }
 
+  /**
+   * Computes and saves the maximum and minimum (x, y, z) positions of any
+   * sequence point, and also the min-max range (width) for each dimension, and
+   * the maximum width for all dimensions
+   */
   public void findWidth()
   {
     max = new float[3];
     min = new float[3];
 
-    max[0] = (float) -1e30;
-    max[1] = (float) -1e30;
-    max[2] = (float) -1e30;
+    max[0] = Float.MIN_VALUE;
+    max[1] = Float.MIN_VALUE;
+    max[2] = Float.MIN_VALUE;
 
-    min[0] = (float) 1e30;
-    min[1] = (float) 1e30;
-    min[2] = (float) 1e30;
+    min[0] = Float.MAX_VALUE;
+    min[1] = Float.MAX_VALUE;
+    min[2] = Float.MAX_VALUE;
 
-    for (int i = 0; i < 3; i++)
+    for (SequencePoint sp : points)
     {
-      for (int j = 0; j < npoint; j++)
-      {
-        SequencePoint sp = (SequencePoint) points.elementAt(j);
-        if (sp.coord[i] >= max[i])
-        {
-          max[i] = sp.coord[i];
-        }
-        if (sp.coord[i] <= min[i])
-        {
-          min[i] = sp.coord[i];
-        }
-      }
+      max[0] = Math.max(max[0], sp.coord.x);
+      max[1] = Math.max(max[1], sp.coord.y);
+      max[2] = Math.max(max[2], sp.coord.z);
+      min[0] = Math.min(min[0], sp.coord.x);
+      min[1] = Math.min(min[1], sp.coord.y);
+      min[2] = Math.min(min[2], sp.coord.z);
     }
 
-    // System.out.println("xmax " + max[0] + " min " + min[0]);
-    // System.out.println("ymax " + max[1] + " min " + min[1]);
-    // System.out.println("zmax " + max[2] + " min " + min[2]);
-
     width[0] = Math.abs(max[0] - min[0]);
     width[1] = Math.abs(max[1] - min[1]);
     width[2] = Math.abs(max[2] - min[2]);
 
-    maxwidth = width[0];
-
-    if (width[1] > width[0])
-    {
-      maxwidth = width[1];
-    }
-    if (width[2] > width[1])
-    {
-      maxwidth = width[2];
-    }
-
-    // System.out.println("Maxwidth = " + maxwidth);
+    maxwidth = Math.max(width[0], Math.max(width[1], width[2]));
   }
 
   public float findScale()
   {
-    int dim, width, height;
+    int dim, w, height;
     if (getSize().width != 0)
     {
-      width = getSize().width;
+      w = getSize().width;
       height = getSize().height;
     }
     else
     {
-      width = prefsize.width;
+      w = prefsize.width;
       height = prefsize.height;
     }
 
-    if (width < height)
+    if (w < height)
     {
-      dim = width;
+      dim = w;
     }
     else
     {
       dim = height;
     }
 
-    return (float) (dim * scalefactor / (2 * maxwidth));
+    return dim * scalefactor / (2 * maxwidth);
   }
 
+  /**
+   * Computes and saves the position of the centre of the view
+   */
   public void findCentre()
   {
-    // Find centre coordinate
     findWidth();
 
-    centre[0] = (max[0] + min[0]) / 2;
-    centre[1] = (max[1] + min[1]) / 2;
-    centre[2] = (max[2] + min[2]) / 2;
+    float x = (max[0] + min[0]) / 2;
+    float y = (max[1] + min[1]) / 2;
+    float z = (max[2] + min[2]) / 2;
 
-    // System.out.println("Centre x " + centre[0]);
-    // System.out.println("Centre y " + centre[1]);
-    // System.out.println("Centre z " + centre[2]);
+    centre = new Point(x, y, z);
   }
 
+  @Override
   public Dimension getPreferredSize()
   {
     if (prefsize != null)
@@ -316,16 +267,19 @@ public class RotatableCanvas extends Panel implements MouseListener,
     }
   }
 
+  @Override
   public Dimension getMinimumSize()
   {
     return getPreferredSize();
   }
 
+  @Override
   public void update(Graphics g)
   {
     paint(g);
   }
 
+  @Override
   public void paint(Graphics g)
   {
     if (points == null)
@@ -355,7 +309,7 @@ public class RotatableCanvas extends Panel implements MouseListener,
 
       drawBackground(ig, Color.black);
       drawScene(ig);
-      if (drawAxes == true)
+      if (drawAxes)
       {
         drawAxes(ig);
       }
@@ -377,8 +331,8 @@ public class RotatableCanvas extends Panel implements MouseListener,
     for (int i = 0; i < 3; i++)
     {
       g.drawLine(getSize().width / 2, getSize().height / 2,
-              (int) (axes[i][0] * scale * max[0] + getSize().width / 2),
-              (int) (axes[i][1] * scale * max[1] + getSize().height / 2));
+              (int) (axisEndPoints[i].x * scale * max[0] + getSize().width / 2),
+              (int) (axisEndPoints[i].y * scale * max[1] + getSize().height / 2));
     }
   }
 
@@ -390,81 +344,85 @@ public class RotatableCanvas extends Panel implements MouseListener,
 
   public void drawScene(Graphics g)
   {
-    // boolean darker = false;
-
-    int halfwidth = getSize().width / 2;
-    int halfheight = getSize().height / 2;
-
     for (int i = 0; i < npoint; i++)
     {
-      SequencePoint sp = (SequencePoint) points.elementAt(i);
-      int x = (int) ((float) (sp.coord[0] - centre[0]) * scale) + halfwidth;
-      int y = (int) ((float) (sp.coord[1] - centre[1]) * scale)
-              + halfheight;
-      float z = sp.coord[1] - centre[2];
-
-      if (av.getSequenceColour(sp.sequence) == Color.black)
-      {
-        g.setColor(Color.white);
-      }
-      else
-      {
-        g.setColor(av.getSequenceColour(sp.sequence));
-      }
-
+      SequencePoint sp = points.get(i);
+      SequenceI sequence = sp.getSequence();
+      Color sequenceColour = av.getSequenceColour(sequence);
+      g.setColor(
+              sequenceColour == Color.black ? Color.white : sequenceColour);
       if (av.getSelectionGroup() != null)
       {
         if (av.getSelectionGroup().getSequences(null)
-                .contains(((SequencePoint) points.elementAt(i)).sequence))
+                .contains(sequence))
         {
           g.setColor(Color.gray);
         }
       }
-      if (z < 0)
+
+      if (sp.coord.z < centre.z)
       {
         g.setColor(g.getColor().darker());
       }
 
+      int halfwidth = getSize().width / 2;
+      int halfheight = getSize().height / 2;
+      int x = (int) ((sp.coord.x - centre.x) * scale) + halfwidth;
+      int y = (int) ((sp.coord.y - centre.y) * scale) + halfheight;
       g.fillRect(x - 3, y - 3, 6, 6);
+
       if (showLabels)
       {
         g.setColor(Color.red);
-        g.drawString(
-                ((SequencePoint) points.elementAt(i)).sequence.getName(),
-                x - 3, y - 4);
+        g.drawString(sequence.getName(), x - 3, y - 4);
       }
     }
   }
 
-  public Dimension minimumsize()
-  {
-    return prefsize;
-  }
-
-  public Dimension preferredsize()
-  {
-    return prefsize;
-  }
-
+  @Override
   public void keyTyped(KeyEvent evt)
   {
   }
 
+  @Override
   public void keyReleased(KeyEvent evt)
   {
   }
 
+  @Override
   public void keyPressed(KeyEvent evt)
   {
-    if (evt.getKeyCode() == KeyEvent.VK_UP)
+    boolean shiftDown = evt.isShiftDown();
+    int keyCode = evt.getKeyCode();
+    if (keyCode == KeyEvent.VK_UP)
+    {
+      if (shiftDown)
+      {
+        rotate(0f, -1f);
+      }
+      else
+      {
+        zoom(1.1f);
+      }
+    }
+    else if (keyCode == KeyEvent.VK_DOWN)
     {
-      scalefactor = (float) (scalefactor * 1.1);
-      scale = findScale();
+      if (shiftDown)
+      {
+        rotate(0f, 1f);
+      }
+      else
+      {
+        zoom(0.9f);
+      }
     }
-    else if (evt.getKeyCode() == KeyEvent.VK_DOWN)
+    else if (shiftDown && keyCode == KeyEvent.VK_LEFT)
     {
-      scalefactor = (float) (scalefactor * 0.9);
-      scale = findScale();
+      rotate(1f, 0f);
+    }
+    else if (shiftDown && keyCode == KeyEvent.VK_RIGHT)
+    {
+      rotate(-1f, 0f);
     }
     else if (evt.getKeyChar() == 's')
     {
@@ -478,46 +436,34 @@ public class RotatableCanvas extends Panel implements MouseListener,
     repaint();
   }
 
-  public void printPoints()
-  {
-    for (int i = 0; i < npoint; i++)
-    {
-      SequencePoint sp = (SequencePoint) points.elementAt(i);
-      Format.print(System.out, "%5d ", i);
-      for (int j = 0; j < 3; j++)
-      {
-        Format.print(System.out, "%13.3f  ", sp.coord[j]);
-      }
-      System.out.println();
-    }
-  }
-
+  @Override
   public void mouseClicked(MouseEvent evt)
   {
   }
 
+  @Override
   public void mouseEntered(MouseEvent evt)
   {
   }
 
+  @Override
   public void mouseExited(MouseEvent evt)
   {
   }
 
+  @Override
   public void mouseReleased(MouseEvent evt)
   {
   }
 
+  @Override
   public void mousePressed(MouseEvent evt)
   {
     int x = evt.getX();
     int y = evt.getY();
 
-    mx = x;
-    my = y;
-
-    omx = mx;
-    omy = my;
+    mouseX = x;
+    mouseY = y;
 
     startx = x;
     starty = y;
@@ -528,7 +474,7 @@ public class RotatableCanvas extends Panel implements MouseListener,
     rectx2 = -1;
     recty2 = -1;
 
-    SequenceI found = findPoint(x, y);
+    SequenceI found = findSequenceAtPoint(x, y);
 
     if (found != null)
     {
@@ -552,9 +498,10 @@ public class RotatableCanvas extends Panel implements MouseListener,
     repaint();
   }
 
+  @Override
   public void mouseMoved(MouseEvent evt)
   {
-    SequenceI found = findPoint(evt.getX(), evt.getY());
+    SequenceI found = findSequenceAtPoint(evt.getX(), evt.getY());
     if (found == null)
     {
       tooltip = null;
@@ -568,40 +515,22 @@ public class RotatableCanvas extends Panel implements MouseListener,
     repaint();
   }
 
+  @Override
   public void mouseDragged(MouseEvent evt)
   {
-    mx = evt.getX();
-    my = evt.getY();
-
-    rotmat.setIdentity();
+    int xPos = evt.getX();
+    int yPos = evt.getY();
 
-    rotmat.rotate((float) (my - omy), 'x');
-    rotmat.rotate((float) (mx - omx), 'y');
-
-    for (int i = 0; i < npoint; i++)
+    if (xPos == mouseX && yPos == mouseY)
     {
-      SequencePoint sp = (SequencePoint) points.elementAt(i);
-      sp.coord[0] -= centre[0];
-      sp.coord[1] -= centre[1];
-      sp.coord[2] -= centre[2];
-
-      // Now apply the rotation matrix
-      sp.coord = rotmat.vectorMultiply(sp.coord);
-
-      // Now translate back again
-      sp.coord[0] += centre[0];
-      sp.coord[1] += centre[1];
-      sp.coord[2] += centre[2];
+      return;
     }
 
-    for (int i = 0; i < 3; i++)
-    {
-      axes[i] = rotmat.vectorMultiply(axes[i]);
-    }
-    omx = mx;
-    omy = my;
+    int xDelta = xPos - mouseX;
+    int yDelta = yPos - mouseY;
 
-    paint(this.getGraphics());
+    rotate(xDelta, yDelta);
+    repaint();
   }
 
   public void rectSelect(int x1, int y1, int x2, int y2)
@@ -609,29 +538,38 @@ public class RotatableCanvas extends Panel implements MouseListener,
     // boolean changedSel = false;
     for (int i = 0; i < npoint; i++)
     {
-      SequencePoint sp = (SequencePoint) points.elementAt(i);
-      int tmp1 = (int) ((sp.coord[0] - centre[0]) * scale
-              + (float) getSize().width / 2.0);
-      int tmp2 = (int) ((sp.coord[1] - centre[1]) * scale
-              + (float) getSize().height / 2.0);
+      SequencePoint sp = points.get(i);
+      int tmp1 = (int) ((sp.coord.x - centre.x) * scale
+              + getSize().width / 2.0);
+      int tmp2 = (int) ((sp.coord.y - centre.y) * scale
+              + getSize().height / 2.0);
 
+      SequenceI sequence = sp.getSequence();
       if (tmp1 > x1 && tmp1 < x2 && tmp2 > y1 && tmp2 < y2)
       {
         if (av != null)
         {
           if (!av.getSelectionGroup().getSequences(null)
-                  .contains(sp.sequence))
+                  .contains(sequence))
           {
-            av.getSelectionGroup().addSequence(sp.sequence, true);
+            av.getSelectionGroup().addSequence(sequence, true);
           }
         }
       }
     }
   }
 
-  public SequenceI findPoint(int x, int y)
+  /**
+   * Answers the first sequence found whose point on the display is within 2
+   * pixels of the given coordinates, or null if none is found
+   * 
+   * @param x
+   * @param y
+   * 
+   * @return
+   */
+  public SequenceI findSequenceAtPoint(int x, int y)
   {
-
     int halfwidth = getSize().width / 2;
     int halfheight = getSize().height / 2;
 
@@ -640,20 +578,22 @@ public class RotatableCanvas extends Panel implements MouseListener,
     for (int i = 0; i < npoint; i++)
     {
 
-      SequencePoint sp = (SequencePoint) points.elementAt(i);
-      int px = (int) ((float) (sp.coord[0] - centre[0]) * scale)
+      SequencePoint sp = points.get(i);
+      int px = (int) ((sp.coord.x - centre.x) * scale)
               + halfwidth;
-      int py = (int) ((float) (sp.coord[1] - centre[1]) * scale)
+      int py = (int) ((sp.coord.y - centre.y) * scale)
               + halfheight;
 
       if (Math.abs(px - x) < 3 && Math.abs(py - y) < 3)
       {
         found = i;
+        break;
       }
     }
+
     if (found != -1)
     {
-      return ((SequencePoint) points.elementAt(found)).sequence;
+      return points.get(found).getSequence();
     }
     else
     {
@@ -661,4 +601,79 @@ public class RotatableCanvas extends Panel implements MouseListener,
     }
   }
 
+  /**
+   * Resets the view to initial state (no rotation)
+   */
+  public void resetView()
+  {
+    img = null;
+    resetAxes();
+  }
+
+  @Override
+  public void zoom(float factor)
+  {
+    if (factor > 0f)
+    {
+      scalefactor *= factor;
+    }
+    scale = findScale();
+  }
+
+  @Override
+  public void rotate(float x, float y)
+  {
+    if (x == 0f && y == 0f)
+    {
+      return;
+    }
+  
+    /*
+     * get the identity transformation...
+     */
+    RotatableMatrix rotmat = new RotatableMatrix();
+  
+    /*
+     * rotate around the X axis for change in Y
+     * (mouse movement up/down); note we are equating a
+     * number of pixels with degrees of rotation here!
+     */
+    if (y != 0)
+    {
+      rotmat.rotate(y, Axis.X);
+    }
+  
+    /*
+     * rotate around the Y axis for change in X
+     * (mouse movement left/right)
+     */
+    if (x != 0)
+    {
+      rotmat.rotate(x, Axis.Y);
+    }
+  
+    /*
+     * apply the composite transformation to sequence points
+     */
+    for (int i = 0; i < npoint; i++)
+    {
+      SequencePoint sp = points.get(i);
+      sp.translate(-centre.x, -centre.y, -centre.z);
+
+      // Now apply the rotation matrix
+      sp.coord = rotmat.vectorMultiply(sp.coord);
+
+      // Now translate back again
+      sp.translate(centre.x, centre.y, centre.z);
+    }
+  
+    /*
+     * rotate the x/y/z axis positions
+     */
+    for (int i = 0; i < DIMS; i++)
+    {
+      axisEndPoints[i] = rotmat.vectorMultiply(axisEndPoints[i]);
+    }
+  }
+
 }
index cac843f..1a227c5 100644 (file)
  */
 package jalview.commands;
 
+import jalview.analysis.AlignSeq;
 import jalview.datamodel.AlignmentAnnotation;
 import jalview.datamodel.AlignmentI;
 import jalview.datamodel.Annotation;
+import jalview.datamodel.Range;
 import jalview.datamodel.Sequence;
 import jalview.datamodel.SequenceFeature;
 import jalview.datamodel.SequenceI;
+import jalview.datamodel.features.SequenceFeaturesI;
+import jalview.util.Comparison;
 import jalview.util.ReverseListIterator;
 import jalview.util.StringUtils;
 
@@ -114,7 +118,7 @@ public class EditCommand implements CommandI
     public abstract Action getUndoAction();
   };
 
-  private List<Edit> edits = new ArrayList<Edit>();
+  private List<Edit> edits = new ArrayList<>();
 
   String description;
 
@@ -330,20 +334,8 @@ public class EditCommand implements CommandI
           int position, int number, AlignmentI al, boolean performEdit,
           AlignmentI[] views)
   {
-    Edit edit = new Edit(command, seqs, position, number,
-            al.getGapCharacter());
-    if (al.getHeight() == seqs.length)
-    {
-      edit.al = al;
-      edit.fullAlignmentHeight = true;
-    }
-
-    addEdit(edit);
-
-    if (performEdit)
-    {
-      performEdit(edit, views);
-    }
+    Edit edit = new Edit(command, seqs, position, number, al);
+    appendEdit(edit, al, performEdit, views);
   }
 
   /**
@@ -534,39 +526,62 @@ public class EditCommand implements CommandI
         command.string[i] = sequence.getSequence(command.position,
                 command.position + command.number);
         SequenceI oldds = sequence.getDatasetSequence();
-        if (command.oldds != null && command.oldds[i] != null)
-        {
-          // we are redoing an undone cut.
-          sequence.setDatasetSequence(null);
-        }
-        sequence.deleteChars(command.position,
+        Range cutPositions = sequence.findPositions(command.position + 1,
                 command.position + command.number);
+        boolean cutIsInternal = cutPositions != null
+                && sequence.getStart() != cutPositions
+                .getBegin() && sequence.getEnd() != cutPositions.getEnd();
+
+        /*
+         * perform the cut; if this results in a new dataset sequence, add
+         * that to the alignment dataset
+         */
+        SequenceI ds = sequence.getDatasetSequence();
+        sequence.deleteChars(command.position, command.position
+                + command.number);
+
         if (command.oldds != null && command.oldds[i] != null)
         {
-          // oldds entry contains the cut dataset sequence.
+          /*
+           * we are Redoing a Cut, or Undoing a Paste - so
+           * oldds entry contains the cut dataset sequence,
+           * with sequence features in expected place
+           */
           sequence.setDatasetSequence(command.oldds[i]);
           command.oldds[i] = oldds;
         }
         else
         {
-          // modify the oldds if necessary
+          /* 
+           * new cut operation: save the dataset sequence 
+           * so it can be restored in an Undo
+           */
+          if (command.oldds == null)
+          {
+            command.oldds = new SequenceI[command.seqs.length];
+          }
+          command.oldds[i] = oldds;// todo not if !cutIsInternal?
+
+          // do we need to edit sequence features for new sequence ?
           if (oldds != sequence.getDatasetSequence()
-                  || sequence.getFeatures().hasFeatures())
+                  || (cutIsInternal
+                          && sequence.getFeatures().hasFeatures()))
+          // todo or just test cutIsInternal && cutPositions != null ?
           {
-            if (command.oldds == null)
+            if (cutPositions != null)
             {
-              command.oldds = new SequenceI[command.seqs.length];
+              cutFeatures(command, sequence, cutPositions.getBegin(),
+                              cutPositions.getEnd(), cutIsInternal);
             }
-            command.oldds[i] = oldds;
-            // FIXME JAL-2541 JAL-2526 get correct positions if on a gap
-            adjustFeatures(
-                    command,
-                    i,
-                    sequence.findPosition(command.position),
-                    sequence.findPosition(command.position + command.number),
-                    false);
           }
         }
+        SequenceI newDs = sequence.getDatasetSequence();
+        if (newDs != ds && command.al != null
+                && command.al.getDataset() != null
+                && !command.al.getDataset().getSequences().contains(newDs))
+        {
+          command.al.getDataset().addSequence(newDs);
+        }
       }
 
       if (sequence.getLength() < 1)
@@ -588,21 +603,19 @@ public class EditCommand implements CommandI
    */
   static void paste(Edit command, AlignmentI[] views)
   {
-    StringBuffer tmp;
-    boolean newDSNeeded;
-    boolean newDSWasNeeded;
-    int newstart, newend;
     boolean seqWasDeleted = false;
-    int start = 0, end = 0;
 
     for (int i = 0; i < command.seqs.length; i++)
     {
-      newDSNeeded = false;
-      newDSWasNeeded = command.oldds != null && command.oldds[i] != null;
-      if (command.seqs[i].getLength() < 1)
+      boolean newDSNeeded = false;
+      boolean newDSWasNeeded = command.oldds != null
+              && command.oldds[i] != null;
+      SequenceI sequence = command.seqs[i];
+      if (sequence.getLength() < 1)
       {
-        // ie this sequence was deleted, we need to
-        // readd it to the alignment
+        /*
+         * sequence was deleted; re-add it to the alignment
+         */
         if (command.alIndex[i] < command.al.getHeight())
         {
           List<SequenceI> sequences;
@@ -610,68 +623,78 @@ public class EditCommand implements CommandI
           {
             if (!(command.alIndex[i] < 0))
             {
-              sequences.add(command.alIndex[i], command.seqs[i]);
+              sequences.add(command.alIndex[i], sequence);
             }
           }
         }
         else
         {
-          command.al.addSequence(command.seqs[i]);
+          command.al.addSequence(sequence);
         }
         seqWasDeleted = true;
       }
-      newstart = command.seqs[i].getStart();
-      newend = command.seqs[i].getEnd();
+      int newStart = sequence.getStart();
+      int newEnd = sequence.getEnd();
 
-      tmp = new StringBuffer();
-      tmp.append(command.seqs[i].getSequence());
+      StringBuilder tmp = new StringBuilder();
+      tmp.append(sequence.getSequence());
       // Undo of a delete does not replace original dataset sequence on to
       // alignment sequence.
 
+      int start = 0;
+      int length = 0;
+
       if (command.string != null && command.string[i] != null)
       {
         if (command.position >= tmp.length())
         {
           // This occurs if padding is on, and residues
           // are removed from end of alignment
-          int length = command.position - tmp.length();
-          while (length > 0)
+          int len = command.position - tmp.length();
+          while (len > 0)
           {
             tmp.append(command.gapChar);
-            length--;
+            len--;
           }
         }
         tmp.insert(command.position, command.string[i]);
         for (int s = 0; s < command.string[i].length; s++)
         {
-          if (jalview.schemes.ResidueProperties.aaIndex[command.string[i][s]] != 23)
+          if (!Comparison.isGap(command.string[i][s]))
           {
+            length++;
             if (!newDSNeeded)
             {
               newDSNeeded = true;
-              start = command.seqs[i].findPosition(command.position);
-              end = command.seqs[i]
-                      .findPosition(command.position + command.number);
+              start = sequence.findPosition(command.position);
+              // end = sequence
+              // .findPosition(command.position + command.number);
             }
-            if (command.seqs[i].getStart() == start)
+            if (sequence.getStart() == start)
             {
-              newstart--;
+              newStart--;
             }
             else
             {
-              newend++;
+              newEnd++;
             }
           }
         }
         command.string[i] = null;
       }
 
-      command.seqs[i].setSequence(tmp.toString());
-      command.seqs[i].setStart(newstart);
-      command.seqs[i].setEnd(newend);
+      sequence.setSequence(tmp.toString());
+      sequence.setStart(newStart);
+      sequence.setEnd(newEnd);
+
+      /*
+       * command and Undo share the same dataset sequence if cut was
+       * at start or end of sequence
+       */
+      boolean sameDatasetSequence = false;
       if (newDSNeeded)
       {
-        if (command.seqs[i].getDatasetSequence() != null)
+        if (sequence.getDatasetSequence() != null)
         {
           SequenceI ds;
           if (newDSWasNeeded)
@@ -682,21 +705,29 @@ public class EditCommand implements CommandI
           {
             // make a new DS sequence
             // use new ds mechanism here
-            ds = new Sequence(command.seqs[i].getName(),
-                    jalview.analysis.AlignSeq.extractGaps(
-                            jalview.util.Comparison.GapChars,
-                            command.seqs[i].getSequenceAsString()),
-                    command.seqs[i].getStart(), command.seqs[i].getEnd());
-            ds.setDescription(command.seqs[i].getDescription());
+            String ungapped = AlignSeq.extractGaps(Comparison.GapChars,
+                    sequence.getSequenceAsString());
+            ds = new Sequence(sequence.getName(), ungapped,
+                    sequence.getStart(), sequence.getEnd());
+            ds.setDescription(sequence.getDescription());
           }
           if (command.oldds == null)
           {
             command.oldds = new SequenceI[command.seqs.length];
           }
-          command.oldds[i] = command.seqs[i].getDatasetSequence();
-          command.seqs[i].setDatasetSequence(ds);
+          command.oldds[i] = sequence.getDatasetSequence();
+          sameDatasetSequence = ds == sequence.getDatasetSequence();
+          ds.setSequenceFeatures(sequence.getSequenceFeatures());
+          if (!sameDatasetSequence && command.al.getDataset() != null)
+          {
+            // delete 'undone' sequence from alignment dataset
+            command.al.getDataset()
+                    .deleteSequence(sequence.getDatasetSequence());
+          }
+          sequence.setDatasetSequence(ds);
         }
-        adjustFeatures(command, i, start, end, true);
+        undoCutFeatures(command, command.seqs[i], start, length,
+                sameDatasetSequence);
       }
     }
     adjustAnnotations(command, true, seqWasDeleted, views);
@@ -706,7 +737,7 @@ public class EditCommand implements CommandI
 
   static void replace(Edit command)
   {
-    StringBuffer tmp;
+    StringBuilder tmp;
     String oldstring;
     int start = command.position;
     int end = command.number;
@@ -719,6 +750,7 @@ public class EditCommand implements CommandI
     {
       boolean newDSWasNeeded = command.oldds != null
               && command.oldds[i] != null;
+      boolean newStartEndWasNeeded = command.oldStartEnd!=null && command.oldStartEnd[i]!=null;
 
       /**
        * cut addHistoryItem(new EditCommand("Cut Sequences", EditCommand.CUT,
@@ -731,49 +763,147 @@ public class EditCommand implements CommandI
        * EditCommand.PASTE, sequences, 0, alignment.getWidth(), alignment) );
        * 
        */
+
+      Range beforeEditedPositions = command.seqs[i].findPositions(1, start);
+      Range afterEditedPositions = command.seqs[i]
+              .findPositions(end + 1, command.seqs[i].getLength());
+      
       oldstring = command.seqs[i].getSequenceAsString();
-      tmp = new StringBuffer(oldstring.substring(0, start));
+      tmp = new StringBuilder(oldstring.substring(0, start));
       tmp.append(command.string[i]);
-      String nogaprep = jalview.analysis.AlignSeq.extractGaps(
-              jalview.util.Comparison.GapChars,
+      String nogaprep = AlignSeq.extractGaps(Comparison.GapChars,
               new String(command.string[i]));
-      int ipos = command.seqs[i].findPosition(start)
-              - command.seqs[i].getStart();
-      tmp.append(oldstring.substring(end));
+      if (end < oldstring.length())
+      {
+        tmp.append(oldstring.substring(end));
+      }
+      // stash end prior to updating the sequence object so we can save it if
+      // need be.
+      Range oldstartend = new Range(command.seqs[i].getStart(),
+              command.seqs[i].getEnd());
       command.seqs[i].setSequence(tmp.toString());
-      command.string[i] = oldstring.substring(start, end).toCharArray();
-      String nogapold = jalview.analysis.AlignSeq.extractGaps(
-              jalview.util.Comparison.GapChars,
+      command.string[i] = oldstring
+              .substring(start, Math.min(end, oldstring.length()))
+              .toCharArray();
+      String nogapold = AlignSeq.extractGaps(Comparison.GapChars,
               new String(command.string[i]));
+
       if (!nogaprep.toLowerCase().equals(nogapold.toLowerCase()))
       {
-        if (newDSWasNeeded)
+        // we may already have dataset and limits stashed...
+        if (newDSWasNeeded || newStartEndWasNeeded)
         {
+          if (newDSWasNeeded)
+          {
+          // then just switch the dataset sequence
           SequenceI oldds = command.seqs[i].getDatasetSequence();
           command.seqs[i].setDatasetSequence(command.oldds[i]);
           command.oldds[i] = oldds;
+          }
+          if (newStartEndWasNeeded)
+          {
+            Range newStart = command.oldStartEnd[i];
+            command.oldStartEnd[i] = oldstartend;
+            command.seqs[i].setStart(newStart.getBegin());
+            command.seqs[i].setEnd(newStart.getEnd());
+          }
         }
-        else
+        else         
         {
-          if (command.oldds == null)
+          // decide if we need a new dataset sequence or modify start/end
+          // first edit the original dataset sequence string
+          SequenceI oldds = command.seqs[i].getDatasetSequence();
+          String osp = oldds.getSequenceAsString();
+          int beforeStartOfEdit = -oldds.getStart() + 1
+                  + (beforeEditedPositions == null
+                          ? ((afterEditedPositions != null)
+                                  ? afterEditedPositions.getBegin() - 1
+                                  : oldstartend.getBegin()
+                                          + nogapold.length())
+                          : beforeEditedPositions.getEnd()
+                  );
+          int afterEndOfEdit = -oldds.getStart() + 1
+                  + ((afterEditedPositions == null)
+                  ? oldstartend.getEnd()
+                          : afterEditedPositions.getBegin() - 1);
+          String fullseq = osp.substring(0,
+                  beforeStartOfEdit)
+                  + nogaprep
+                  + osp.substring(afterEndOfEdit);
+
+          // and check if new sequence data is different..
+          if (!fullseq.equalsIgnoreCase(osp))
           {
-            command.oldds = new SequenceI[command.seqs.length];
-          }
-          command.oldds[i] = command.seqs[i].getDatasetSequence();
-          SequenceI newds = new Sequence(
-                  command.seqs[i].getDatasetSequence());
-          String fullseq, osp = newds.getSequenceAsString();
-          fullseq = osp.substring(0, ipos) + nogaprep
-                  + osp.substring(ipos + nogaprep.length());
-          newds.setSequence(fullseq.toUpperCase());
-          // TODO: JAL-1131 ensure newly created dataset sequence is added to
-          // the set of
-          // dataset sequences associated with the alignment.
-          // TODO: JAL-1131 fix up any annotation associated with new dataset
-          // sequence to ensure that original sequence/annotation relationships
-          // are preserved.
-          command.seqs[i].setDatasetSequence(newds);
+            // old ds and edited ds are different, so
+            // create the new dataset sequence
+            SequenceI newds = new Sequence(oldds);
+            newds.setSequence(fullseq);
+
+            if (command.oldds == null)
+            {
+              command.oldds = new SequenceI[command.seqs.length];
+            }
+            command.oldds[i] = command.seqs[i].getDatasetSequence();
+
+            // And preserve start/end for good-measure
 
+            if (command.oldStartEnd == null)
+            {
+              command.oldStartEnd = new Range[command.seqs.length];
+            }
+            command.oldStartEnd[i] = oldstartend;
+            // TODO: JAL-1131 ensure newly created dataset sequence is added to
+            // the set of
+            // dataset sequences associated with the alignment.
+            // TODO: JAL-1131 fix up any annotation associated with new dataset
+            // sequence to ensure that original sequence/annotation
+            // relationships
+            // are preserved.
+            command.seqs[i].setDatasetSequence(newds);
+          }
+          else
+          {
+            if (command.oldStartEnd == null)
+            {
+              command.oldStartEnd = new Range[command.seqs.length];
+            }
+            command.oldStartEnd[i] = new Range(command.seqs[i].getStart(),
+                    command.seqs[i].getEnd());
+            if (beforeEditedPositions != null
+                    && afterEditedPositions == null)
+            {
+              // modification at end
+              command.seqs[i].setEnd(
+                      beforeEditedPositions.getEnd() + nogaprep.length()
+                              - nogapold.length());
+            }
+            else if (afterEditedPositions != null
+                    && beforeEditedPositions == null)
+            {
+              // modification at start
+              command.seqs[i].setStart(
+                      afterEditedPositions.getBegin() - nogaprep.length());
+            }
+            else
+            {
+              // edit covered both start and end. Here we can only guess the
+              // new
+              // start/end
+              String nogapalseq = AlignSeq.extractGaps(Comparison.GapChars,
+                      command.seqs[i].getSequenceAsString().toUpperCase());
+              int newStart = command.seqs[i].getDatasetSequence()
+                      .getSequenceAsString().indexOf(nogapalseq);
+              if (newStart == -1)
+              {
+                throw new Error(
+                        "Implementation Error: could not locate start/end "
+                                + "in dataset sequence after an edit of the sequence string");
+              }
+              int newEnd = newStart + nogapalseq.length() - 1;
+              command.seqs[i].setStart(newStart);
+              command.seqs[i].setEnd(newEnd);
+            }
+          }
         }
       }
       tmp = null;
@@ -789,7 +919,7 @@ public class EditCommand implements CommandI
     if (modifyVisibility && !insert)
     {
       // only occurs if a sequence was added or deleted.
-      command.deletedAnnotationRows = new Hashtable<SequenceI, AlignmentAnnotation[]>();
+      command.deletedAnnotationRows = new Hashtable<>();
     }
     if (command.fullAlignmentHeight)
     {
@@ -892,8 +1022,7 @@ public class EditCommand implements CommandI
                 }
                 // and then duplicate added annotation on every other alignment
                 // view
-                for (int vnum = 0; views != null
-                        && vnum < views.length; vnum++)
+                for (int vnum = 0; views != null && vnum < views.length; vnum++)
                 {
                   if (views[vnum] != command.al)
                   {
@@ -948,7 +1077,7 @@ public class EditCommand implements CommandI
 
     if (!insert)
     {
-      command.deletedAnnotations = new Hashtable<String, Annotation[]>();
+      command.deletedAnnotations = new Hashtable<>();
     }
 
     int aSize;
@@ -1109,98 +1238,97 @@ public class EditCommand implements CommandI
     }
   }
 
-  final static void adjustFeatures(Edit command, int index, final int i,
-          final int j, boolean insert)
+  /**
+   * Restores features to the state before a Cut.
+   * <ul>
+   * <li>re-add any features deleted by the cut</li>
+   * <li>remove any truncated features created by the cut</li>
+   * <li>shift right any features to the right of the cut</li>
+   * </ul>
+   * 
+   * @param command
+   *          the Cut command
+   * @param seq
+   *          the sequence the Cut applied to
+   * @param start
+   *          the start residue position of the cut
+   * @param length
+   *          the number of residues cut
+   * @param sameDatasetSequence
+   *          true if dataset sequence and frame of reference were left
+   *          unchanged by the Cut
+   */
+  final static void undoCutFeatures(Edit command, SequenceI seq,
+          final int start, final int length, boolean sameDatasetSequence)
   {
-    SequenceI seq = command.seqs[index];
     SequenceI sequence = seq.getDatasetSequence();
     if (sequence == null)
     {
       sequence = seq;
     }
 
-    if (insert)
+    /*
+     * shift right features that lie to the right of the restored cut (but not 
+     * if dataset sequence unchanged - so coordinates were changed by Cut)
+     */
+    if (!sameDatasetSequence)
     {
-      if (command.editedFeatures != null
-              && command.editedFeatures.containsKey(seq))
+      /*
+       * shift right all features right of and not 
+       * contiguous with the cut position
+       */
+      seq.getFeatures().shiftFeatures(start + 1, length);
+
+      /*
+       * shift right any features that start at the cut position,
+       * unless they were truncated
+       */
+      List<SequenceFeature> sfs = seq.getFeatures().findFeatures(start,
+              start);
+      for (SequenceFeature sf : sfs)
       {
-        sequence.setSequenceFeatures(command.editedFeatures.get(seq));
+        if (sf.getBegin() == start)
+        {
+          if (!command.truncatedFeatures.containsKey(seq)
+                  || !command.truncatedFeatures.get(seq).contains(sf))
+          {
+            /*
+             * feature was shifted left to cut position (not truncated),
+             * so shift it back right
+             */
+            SequenceFeature shifted = new SequenceFeature(sf, sf.getBegin()
+                    + length, sf.getEnd() + length, sf.getFeatureGroup(),
+                    sf.getScore());
+            seq.addSequenceFeature(shifted);
+            seq.deleteFeature(sf);
+          }
+        }
       }
-
-      return;
     }
 
-    List<SequenceFeature> sf = sequence.getFeatures()
-            .getPositionalFeatures();
-
-    if (sf.isEmpty())
-    {
-      return;
-    }
-
-    List<SequenceFeature> oldsf = new ArrayList<SequenceFeature>();
-
-    int cSize = j - i;
-
-    for (SequenceFeature feature : sf)
+    /*
+     * restore any features that were deleted or truncated
+     */
+    if (command.deletedFeatures != null
+            && command.deletedFeatures.containsKey(seq))
     {
-      SequenceFeature copy = new SequenceFeature(feature);
-
-      oldsf.add(copy);
-
-      if (feature.getEnd() < i)
-      {
-        continue;
-      }
-
-      if (feature.getBegin() > j)
-      {
-        int newBegin = copy.getBegin() - cSize;
-        int newEnd = copy.getEnd() - cSize;
-        SequenceFeature newSf = new SequenceFeature(feature, newBegin,
-                newEnd, feature.getFeatureGroup(), feature.getScore());
-        sequence.deleteFeature(feature);
-        sequence.addSequenceFeature(newSf);
-        // feature.setBegin(newBegin);
-        // feature.setEnd(newEnd);
-        continue;
-      }
-
-      int newBegin = feature.getBegin();
-      int newEnd = feature.getEnd();
-      if (newBegin >= i)
-      {
-        newBegin = i;
-        // feature.setBegin(i);
-      }
-
-      if (newEnd < j)
+      for (SequenceFeature deleted : command.deletedFeatures.get(seq))
       {
-        newEnd = j - 1;
-        // feature.setEnd(j - 1);
+        sequence.addSequenceFeature(deleted);
       }
-      newEnd = newEnd - cSize;
-      // feature.setEnd(feature.getEnd() - (cSize));
-
-      sequence.deleteFeature(feature);
-      if (newEnd >= newBegin)
-      {
-        sequence.addSequenceFeature(new SequenceFeature(feature, newBegin,
-                newEnd, feature.getFeatureGroup(), feature.getScore()));
-      }
-      // if (feature.getBegin() > feature.getEnd())
-      // {
-      // sequence.deleteFeature(feature);
-      // }
     }
 
-    if (command.editedFeatures == null)
+    /*
+     * delete any truncated features
+     */
+    if (command.truncatedFeatures != null
+            && command.truncatedFeatures.containsKey(seq))
     {
-      command.editedFeatures = new Hashtable<SequenceI, List<SequenceFeature>>();
+      for (SequenceFeature amended : command.truncatedFeatures.get(seq))
+      {
+        sequence.deleteFeature(amended);
+      }
     }
-
-    command.editedFeatures.put(seq, oldsf);
-
   }
 
   /**
@@ -1233,7 +1361,7 @@ public class EditCommand implements CommandI
    */
   public Map<SequenceI, SequenceI> priorState(boolean forUndo)
   {
-    Map<SequenceI, SequenceI> result = new HashMap<SequenceI, SequenceI>();
+    Map<SequenceI, SequenceI> result = new HashMap<>();
     if (getEdits() == null)
     {
       return result;
@@ -1266,7 +1394,7 @@ public class EditCommand implements CommandI
      * Work backwards through the edit list, deriving the sequences before each
      * was applied. The final result is the sequence set before any edits.
      */
-    Iterator<Edit> editList = new ReverseListIterator<Edit>(getEdits());
+    Iterator<Edit> editList = new ReverseListIterator<>(getEdits());
     while (editList.hasNext())
     {
       Edit oldEdit = editList.next();
@@ -1315,29 +1443,45 @@ public class EditCommand implements CommandI
 
   public class Edit
   {
-    public SequenceI[] oldds;
+    private SequenceI[] oldds;
+
+    /**
+     * start and end of sequence prior to edit
+     */
+    private Range[] oldStartEnd;
+
+    private boolean fullAlignmentHeight = false;
 
-    boolean fullAlignmentHeight = false;
+    private Map<SequenceI, AlignmentAnnotation[]> deletedAnnotationRows;
 
-    Hashtable<SequenceI, AlignmentAnnotation[]> deletedAnnotationRows;
+    private Map<String, Annotation[]> deletedAnnotations;
 
-    Hashtable<String, Annotation[]> deletedAnnotations;
+    /*
+     * features deleted by the cut (re-add on Undo)
+     * (including the original of any shortened features)
+     */
+    private Map<SequenceI, List<SequenceFeature>> deletedFeatures;
 
-    Hashtable<SequenceI, List<SequenceFeature>> editedFeatures;
+    /*
+     * shortened features added by the cut (delete on Undo)
+     */
+    private Map<SequenceI, List<SequenceFeature>> truncatedFeatures;
 
-    AlignmentI al;
+    private AlignmentI al;
 
-    Action command;
+    final private Action command;
 
     char[][] string;
 
     SequenceI[] seqs;
 
-    int[] alIndex;
+    private int[] alIndex;
 
-    int position, number;
+    private int position;
 
-    char gapChar;
+    private int number;
+
+    private char gapChar;
 
     public Edit(Action cmd, SequenceI[] sqs, int pos, int count,
             char gap)
@@ -1352,11 +1496,8 @@ public class EditCommand implements CommandI
     Edit(Action cmd, SequenceI[] sqs, int pos, int count,
             AlignmentI align)
     {
-      this.gapChar = align.getGapCharacter();
-      this.command = cmd;
-      this.seqs = sqs;
-      this.position = pos;
-      this.number = count;
+      this(cmd, sqs, pos, count, align.getGapCharacter());
+
       this.al = align;
 
       alIndex = new int[sqs.length];
@@ -1368,22 +1509,26 @@ public class EditCommand implements CommandI
       fullAlignmentHeight = (align.getHeight() == sqs.length);
     }
 
+    /**
+     * Constructor given a REPLACE command and the replacement string
+     * 
+     * @param cmd
+     * @param sqs
+     * @param pos
+     * @param count
+     * @param align
+     * @param replace
+     */
     Edit(Action cmd, SequenceI[] sqs, int pos, int count,
             AlignmentI align, String replace)
     {
-      this.command = cmd;
-      this.seqs = sqs;
-      this.position = pos;
-      this.number = count;
-      this.al = align;
-      this.gapChar = align.getGapCharacter();
+      this(cmd, sqs, pos, count, align);
+
       string = new char[sqs.length][];
       for (int i = 0; i < sqs.length; i++)
       {
         string[i] = replace.toCharArray();
       }
-
-      fullAlignmentHeight = (align.getHeight() == sqs.length);
     }
 
     public SequenceI[] getSequences()
@@ -1427,7 +1572,163 @@ public class EditCommand implements CommandI
     }
     else
     {
-      return new ReverseListIterator<Edit>(getEdits());
+      return new ReverseListIterator<>(getEdits());
+    }
+  }
+
+  /**
+   * Adjusts features for Cut, and saves details of changes made to allow Undo
+   * <ul>
+   * <li>features left of the cut are unchanged</li>
+   * <li>features right of the cut are shifted left</li>
+   * <li>features internal to the cut region are deleted</li>
+   * <li>features that overlap or span the cut are shortened</li>
+   * <li>the originals of any deleted or shortened features are saved, to re-add
+   * on Undo</li>
+   * <li>any added (shortened) features are saved, to delete on Undo</li>
+   * </ul>
+   * 
+   * @param command
+   * @param seq
+   * @param fromPosition
+   * @param toPosition
+   * @param cutIsInternal
+   */
+  protected static void cutFeatures(Edit command, SequenceI seq,
+          int fromPosition, int toPosition, boolean cutIsInternal)
+  {
+    /* 
+     * if the cut is at start or end of sequence
+     * then we don't modify the sequence feature store
+     */
+    if (!cutIsInternal)
+    {
+      return;
+    }
+    List<SequenceFeature> added = new ArrayList<>();
+    List<SequenceFeature> removed = new ArrayList<>();
+  
+    SequenceFeaturesI featureStore = seq.getFeatures();
+    if (toPosition < fromPosition || featureStore == null)
+    {
+      return;
+    }
+  
+    int cutStartPos = fromPosition;
+    int cutEndPos = toPosition;
+    int cutWidth = cutEndPos - cutStartPos + 1;
+  
+    synchronized (featureStore)
+    {
+      /*
+       * get features that overlap the cut region
+       */
+      List<SequenceFeature> toAmend = featureStore.findFeatures(
+              cutStartPos, cutEndPos);
+  
+      /*
+       * add any contact features that span the cut region
+       * (not returned by findFeatures)
+       */
+      for (SequenceFeature contact : featureStore.getContactFeatures())
+      {
+        if (contact.getBegin() < cutStartPos
+                && contact.getEnd() > cutEndPos)
+        {
+          toAmend.add(contact);
+        }
+      }
+
+      /*
+       * adjust start-end of overlapping features;
+       * delete features enclosed by the cut;
+       * delete partially overlapping contact features
+       */
+      for (SequenceFeature sf : toAmend)
+      {
+        int sfBegin = sf.getBegin();
+        int sfEnd = sf.getEnd();
+        int newBegin = sfBegin;
+        int newEnd = sfEnd;
+        boolean toDelete = false;
+        boolean follows = false;
+        
+        if (sfBegin >= cutStartPos && sfEnd <= cutEndPos)
+        {
+          /*
+           * feature lies within cut region - delete it
+           */
+          toDelete = true;
+        }
+        else if (sfBegin < cutStartPos && sfEnd > cutEndPos)
+        {
+          /*
+           * feature spans cut region - left-shift the end
+           */
+          newEnd -= cutWidth;
+        }
+        else if (sfEnd <= cutEndPos)
+        {
+          /*
+           * feature overlaps left of cut region - truncate right
+           */
+          newEnd = cutStartPos - 1;
+          if (sf.isContactFeature())
+          {
+            toDelete = true;
+          }
+        }
+        else if (sfBegin >= cutStartPos)
+        {
+          /*
+           * remaining case - feature overlaps right
+           * truncate left, adjust end of feature
+           */
+          newBegin = cutIsInternal ? cutStartPos : cutEndPos + 1;
+          newEnd = newBegin + sfEnd - cutEndPos - 1;
+          if (sf.isContactFeature())
+          {
+            toDelete = true;
+          }
+        }
+  
+        seq.deleteFeature(sf);
+        if (!follows)
+        {
+          removed.add(sf);
+        }
+        if (!toDelete)
+        {
+          SequenceFeature copy = new SequenceFeature(sf, newBegin, newEnd,
+                  sf.getFeatureGroup(), sf.getScore());
+          seq.addSequenceFeature(copy);
+          if (!follows)
+          {
+            added.add(copy);
+          }
+        }
+      }
+  
+      /*
+       * and left shift any features lying to the right of the cut region
+       */
+
+      featureStore.shiftFeatures(cutEndPos + 1, -cutWidth);
+    }
+
+    /*
+     * save deleted and amended features, so that Undo can 
+     * re-add or delete them respectively
+     */
+    if (command.deletedFeatures == null)
+    {
+      command.deletedFeatures = new HashMap<>();
+    }
+    if (command.truncatedFeatures == null)
+    {
+      command.truncatedFeatures = new HashMap<>();
     }
+    command.deletedFeatures.put(seq, removed);
+    command.truncatedFeatures.put(seq, added);
   }
 }
diff --git a/src/jalview/datamodel/Point.java b/src/jalview/datamodel/Point.java
new file mode 100644 (file)
index 0000000..e7c77c0
--- /dev/null
@@ -0,0 +1,71 @@
+package jalview.datamodel;
+
+/**
+ * A bean that models an (x, y, z) position in 3-D space
+ */
+public final class Point
+{
+  public final float x;
+
+  public final float y;
+
+  public final float z;
+
+  public Point(float xVal, float yVal, float zVal)
+  {
+    x = xVal;
+    y = yVal;
+    z = zVal;
+  }
+
+  /**
+   * toString for convenience of inspection in debugging or logging
+   */
+  @Override
+  public String toString()
+  {
+    return String.format("[%f, %f, %f]", x, y, z);
+  }
+
+  @Override
+  public int hashCode()
+  {
+    final int prime = 31;
+    int result = 1;
+    result = prime * result + Float.floatToIntBits(x);
+    result = prime * result + Float.floatToIntBits(y);
+    result = prime * result + Float.floatToIntBits(z);
+    return result;
+  }
+
+  @Override
+  public boolean equals(Object obj)
+  {
+    if (this == obj)
+    {
+      return true;
+    }
+    if (obj == null)
+    {
+      return false;
+    }
+    if (getClass() != obj.getClass())
+    {
+      return false;
+    }
+    Point other = (Point) obj;
+    if (Float.floatToIntBits(x) != Float.floatToIntBits(other.x))
+    {
+      return false;
+    }
+    if (Float.floatToIntBits(y) != Float.floatToIntBits(other.y))
+    {
+      return false;
+    }
+    if (Float.floatToIntBits(z) != Float.floatToIntBits(other.z))
+    {
+      return false;
+    }
+    return true;
+  }
+}
index 33de452..f555855 100755 (executable)
@@ -43,10 +43,7 @@ import fr.orsay.lri.varna.models.rna.RNA;
 
 /**
  * 
- * Implements the SequenceI interface for a char[] based sequence object.
- * 
- * @author $author$
- * @version $Revision$
+ * Implements the SequenceI interface for a char[] based sequence object
  */
 public class Sequence extends ASequence implements SequenceI
 {
@@ -797,6 +794,7 @@ public class Sequence extends ASequence implements SequenceI
      * preserve end residue column provided cursor was valid
      */
     int endColumn = isValidCursor(cursor) ? cursor.lastColumnPosition : 0;
+
     if (residuePos == this.end)
     {
       endColumn = column;
@@ -833,8 +831,7 @@ public class Sequence extends ASequence implements SequenceI
     /*
      * move left or right to find pos from hint.position
      */
-    int col = curs.columnPosition - 1; // convert from base 1 to 0-based array
-                                       // index
+    int col = curs.columnPosition - 1; // convert from base 1 to base 0
     int newPos = curs.residuePosition;
     int delta = newPos > pos ? -1 : 1;
 
@@ -1263,12 +1260,13 @@ public class Sequence extends ASequence implements SequenceI
     boolean createNewDs = false;
     // TODO: take a (second look) at the dataset creation validation method for
     // the very large sequence case
+
     int startIndex = findIndex(start) - 1;
     int endIndex = findIndex(end) - 1;
     int startDeleteColumn = -1; // for dataset sequence deletions
     int deleteCount = 0;
 
-    for (int s = i; s < j; s++)
+    for (int s = i; s < j && s < sequence.length; s++)
     {
       if (Comparison.isGap(sequence[s]))
       {
@@ -1913,6 +1911,15 @@ public class Sequence extends ASequence implements SequenceI
 
     List<SequenceFeature> result = getFeatures().findFeatures(startPos,
             endPos, types);
+    if (datasetSequence != null)
+    {
+      result = datasetSequence.getFeatures().findFeatures(startPos, endPos,
+              types);
+    }
+    else
+    {
+      result = sequenceFeatureStore.findFeatures(startPos, endPos, types);
+    }
 
     /*
      * if end column is gapped, endPos may be to the right, 
index 944f263..fc8ac49 100755 (executable)
@@ -102,11 +102,15 @@ public class SequenceGroup implements AnnotatedCollectionI
    */
   public ResidueShaderI cs;
 
-  // start column (base 0)
-  int startRes = 0;
+  /**
+   * start column (base 0)
+   */
+  private int startRes = 0;
 
-  // end column (base 0)
-  int endRes = 0;
+  /**
+   *  end column (base 0)
+   */
+  private int endRes = 0;
 
   public Color outlineColour = Color.black;
 
@@ -209,6 +213,7 @@ public class SequenceGroup implements AnnotatedCollectionI
       displayBoxes = seqsel.displayBoxes;
       displayText = seqsel.displayText;
       colourText = seqsel.colourText;
+      
       startRes = seqsel.startRes;
       endRes = seqsel.endRes;
       cs = new ResidueShader((ResidueShader) seqsel.cs);
@@ -752,13 +757,16 @@ public class SequenceGroup implements AnnotatedCollectionI
   /**
    * Set the first column selected by this group. Runs from 0<=i<N_cols
    * 
-   * @param i
+   * @param newStart
    */
-  public void setStartRes(int i)
+  public void setStartRes(int newStart)
   {
     int before = startRes;
-    startRes = i;
-    changeSupport.firePropertyChange(SEQ_GROUP_CHANGED, before, startRes);
+   startRes= Math.max(0,newStart); // sanity check for negative start column positions
+   changeSupport.firePropertyChange(SEQ_GROUP_CHANGED, before, startRes);
+    
+
+
   }
 
   /**
index 8dce31e..48615f0 100755 (executable)
@@ -206,11 +206,14 @@ public interface SequenceI extends ASequenceI
   public int findPosition(int i);
 
   /**
-   * Returns the from-to sequence positions (start..) for the given column
-   * positions (1..), or null if no residues are included in the range
+   * Returns the sequence positions for first and last residues lying within the
+   * given column positions [fromColum,toColumn] (where columns are numbered
+   * from 1), or null if no residues are included in the range
    * 
    * @param fromColum
+   *          - first column base 1
    * @param toColumn
+   *          - last column, base 1
    * @return
    */
   public Range findPositions(int fromColum, int toColumn);
index a6b967e..3db7cee 100755 (executable)
 package jalview.datamodel;
 
 /**
- * DOCUMENT ME!
- * 
- * @author $author$
- * @version $Revision$
+ * A bean that models a set of (x, y, z) values and a reference to a sequence.
+ * As used in Principal Component Analysis, the (x, y, z) values are the
+ * sequence's score for the currently selected first, second and third
+ * dimensions of the PCA.
  */
 public class SequencePoint
 {
-  // SMJS PUBLIC
+  /*
+   * Associated alignment sequence, or dummy sequence object
+   */
+  private final SequenceI sequence;
+
+  /*
+   * x, y, z values
+   */
+  public Point coord;
+
   /**
-   * for points with no real physical association with an alignment sequence
+   * Constructor
+   * 
+   * @param sequence
+   * @param coord
    */
-  public boolean isPlaceholder = false;
+  public SequencePoint(SequenceI sequence, Point pt)
+  {
+    this.sequence = sequence;
+    this.coord = pt;
+  }
 
   /**
-   * Associated alignment sequence, or dummy sequence object.
+   * Constructor given a sequence and an array of x, y, z coordinate positions
+   * 
+   * @param sequence
+   * @param coords
+   * @throws ArrayIndexOutOfBoundsException
+   *           if array length is less than 3
    */
-  public SequenceI sequence;
+  public SequencePoint(SequenceI sequence, float[] coords)
+  {
+    this(sequence, new Point(coords[0], coords[1], coords[2]));
+  }
+
+  public SequenceI getSequence()
+  {
+    return sequence;
+  }
 
   /**
-   * array of coordinates in embedded sequence space.
+   * Applies a translation to the (x, y, z) coordinates
+   * 
+   * @param centre
    */
-  public float[] coord;
+  public void translate(float x, float y, float z)
+  {
+    coord = new Point(coord.x + x, coord.y + y, coord.z + z);
+  }
 
-  // SMJS ENDPUBLIC
-  public SequencePoint(SequenceI sequence, float[] coord)
+  /**
+   * string representation for ease of inspection in debugging or logging only
+   */
+  @Override
+  public String toString()
   {
-    this.sequence = sequence;
-    this.coord = coord;
+    return sequence.getName() + " " + coord.toString();
   }
 }
index 02ce1c5..951b7a5 100644 (file)
@@ -1047,13 +1047,15 @@ public class FeatureStore
   }
 
   /**
-   * Adds the shift value to the start and end of all positional features.
-   * Returns true if at least one feature was updated, else false.
+   * Adds the shift amount to the start and end of all positional features whose
+   * start position is at or after fromPosition. Returns true if at least one
+   * feature was shifted, else false.
    * 
-   * @param shift
+   * @param fromPosition
+   * @param shiftBy
    * @return
    */
-  public synchronized boolean shiftFeatures(int shift)
+  public synchronized boolean shiftFeatures(int fromPosition, int shiftBy)
   {
     /*
      * Because begin and end are final fields (to ensure the data store's
@@ -1063,21 +1065,24 @@ public class FeatureStore
     boolean modified = false;
     for (SequenceFeature sf : getPositionalFeatures())
     {
-      modified = true;
-      int newBegin = sf.getBegin() + shift;
-      int newEnd = sf.getEnd() + shift;
-
-      /*
-       * sanity check: don't shift left of the first residue
-       */
-      if (newEnd > 0)
+      if (sf.getBegin() >= fromPosition)
       {
-        newBegin = Math.max(1, newBegin);
-        SequenceFeature sf2 = new SequenceFeature(sf, newBegin, newEnd,
-                sf.getFeatureGroup(), sf.getScore());
-        addFeature(sf2);
+        modified = true;
+        int newBegin = sf.getBegin() + shiftBy;
+        int newEnd = sf.getEnd() + shiftBy;
+
+        /*
+         * sanity check: don't shift left of the first residue
+         */
+        if (newEnd > 0)
+        {
+          newBegin = Math.max(1, newBegin);
+          SequenceFeature sf2 = new SequenceFeature(sf, newBegin, newEnd,
+                  sf.getFeatureGroup(), sf.getScore());
+          addFeature(sf2);
+        }
+        delete(sf);
       }
-      delete(sf);
     }
     return modified;
   }
index 727d3ef..8f965b4 100644 (file)
@@ -472,13 +472,22 @@ public class SequenceFeatures implements SequenceFeaturesI
    * {@inheritDoc}
    */
   @Override
-  public boolean shiftFeatures(int shift)
+  public boolean shiftFeatures(int fromPosition, int shiftBy)
   {
     boolean modified = false;
     for (FeatureStore fs : featureStore.values())
     {
-      modified |= fs.shiftFeatures(shift);
+      modified |= fs.shiftFeatures(fromPosition, shiftBy);
     }
     return modified;
   }
-}
\ No newline at end of file
+
+  /**
+   * {@inheritDoc}
+   */
+  @Override
+  public void deleteAll()
+  {
+    featureStore.clear();
+  }
+}
index 31712b9..ca0283e 100644 (file)
@@ -215,10 +215,17 @@ public interface SequenceFeaturesI
   float getMaximumScore(String type, boolean positional);
 
   /**
-   * Adds the shift amount to the start and end of all positional features,
-   * returning true if at least one feature was shifted, else false
+   * Adds the shift amount to the start and end of all positional features whose
+   * start position is at or after fromPosition. Returns true if at least one
+   * feature was shifted, else false.
    * 
-   * @param shift
+   * @param fromPosition
+   * @param shiftBy
    */
-  abstract boolean shiftFeatures(int shift);
-}
\ No newline at end of file
+  boolean shiftFeatures(int fromPosition, int shiftBy);
+
+  /**
+   * Deletes all positional and non-positional features
+   */
+  void deleteAll();
+}
index 8832278..a5b1110 100644 (file)
@@ -1254,7 +1254,10 @@ public abstract class JalviewJmolBinding extends AAStructureBindingModel
     return chainNames;
   }
 
-  protected abstract IProgressIndicator getIProgressIndicator();
+  protected IProgressIndicator getIProgressIndicator()
+  {
+    return null;
+  }
 
   public void notifyNewPickingModeMeasurement(int iatom, String strMeasure)
   {
index 183419e..336a312 100644 (file)
@@ -25,6 +25,7 @@ import jalview.analysis.scoremodels.ScoreModels;
 import jalview.analysis.scoremodels.SimilarityParams;
 import jalview.api.analysis.ScoreModelI;
 import jalview.api.analysis.SimilarityParamsI;
+import jalview.bin.Cache;
 import jalview.datamodel.SequenceGroup;
 import jalview.util.MessageManager;
 
@@ -103,7 +104,7 @@ public class CalculationChooser extends JPanel
 
   final ComboBoxTooltipRenderer renderer = new ComboBoxTooltipRenderer();
 
-  List<String> tips = new ArrayList<String>();
+  List<String> tips = new ArrayList<>();
 
   /*
    * the most recently opened PCA results panel
@@ -375,7 +376,7 @@ public class CalculationChooser extends JPanel
    */
   protected JComboBox<String> buildModelOptionsList()
   {
-    final JComboBox<String> scoreModelsCombo = new JComboBox<String>();
+    final JComboBox<String> scoreModelsCombo = new JComboBox<>();
     scoreModelsCombo.setRenderer(renderer);
 
     /*
@@ -418,39 +419,42 @@ public class CalculationChooser extends JPanel
   {
     Object curSel = comboBox.getSelectedItem();
     toolTips.clear();
-    DefaultComboBoxModel<String> model = new DefaultComboBoxModel<String>();
+    DefaultComboBoxModel<String> model = new DefaultComboBoxModel<>();
+
+    /*
+     * select the score models applicable to the alignment type
+     */
+    boolean nucleotide = af.getViewport().getAlignment().isNucleotide();
+    List<ScoreModelI> models = getApplicableScoreModels(nucleotide,
+            pca.isSelected());
 
     /*
      * now we can actually add entries to the combobox,
      * remembering their descriptions for tooltips
      */
-    ScoreModels scoreModels = ScoreModels.getInstance();
     boolean selectedIsPresent = false;
-    for (ScoreModelI sm : scoreModels.getModels())
+    for (ScoreModelI sm : models)
     {
-      boolean nucleotide = af.getViewport().getAlignment().isNucleotide();
-      if (sm.isDNA() && nucleotide || sm.isProtein() && !nucleotide)
+      if (curSel != null && sm.getName().equals(curSel))
+      {
+        selectedIsPresent = true;
+        curSel = sm.getName();
+      }
+      model.addElement(sm.getName());
+
+      /*
+       * tooltip is description if provided, else text lookup with
+       * fallback on the model name
+       */
+      String tooltip = sm.getDescription();
+      if (tooltip == null)
       {
-        if (curSel != null && sm.getName().equals(curSel))
-        {
-          selectedIsPresent = true;
-          curSel = sm.getName();
-        }
-        model.addElement(sm.getName());
-
-        /*
-         * tooltip is description if provided, else text lookup with
-         * fallback on the model name
-         */
-        String tooltip = sm.getDescription();
-        if (tooltip == null)
-        {
-          tooltip = MessageManager.getStringOrReturn("label.score_model_",
-                  sm.getName());
-        }
-        toolTips.add(tooltip);
+        tooltip = MessageManager.getStringOrReturn("label.score_model_",
+                sm.getName());
       }
+      toolTips.add(tooltip);
     }
+
     if (selectedIsPresent)
     {
       model.setSelectedItem(curSel);
@@ -460,6 +464,47 @@ public class CalculationChooser extends JPanel
   }
 
   /**
+   * Builds a list of score models which are applicable for the alignment and
+   * calculation type (peptide or generic models for protein, nucleotide or
+   * generic models for nucleotide).
+   * <p>
+   * As a special case, includes BLOSUM62 as an extra option for nucleotide PCA.
+   * This is for backwards compatibility with Jalview prior to 2.8 when BLOSUM62
+   * was the only score matrix supported. This is included if property
+   * BLOSUM62_PCA_FOR_NUCLEOTIDE is set to true in the Jalview properties file.
+   * 
+   * @param nucleotide
+   * @param forPca
+   * @return
+   */
+  protected static List<ScoreModelI> getApplicableScoreModels(
+          boolean nucleotide, boolean forPca)
+  {
+    List<ScoreModelI> filtered = new ArrayList<>();
+
+    ScoreModels scoreModels = ScoreModels.getInstance();
+    for (ScoreModelI sm : scoreModels.getModels())
+    {
+      if (!nucleotide && sm.isProtein() || nucleotide && sm.isDNA())
+      {
+        filtered.add(sm);
+      }
+    }
+
+    /*
+     * special case: add BLOSUM62 as last option for nucleotide PCA, 
+     * for backwards compatibility with Jalview < 2.8 (JAL-2962)
+     */
+    if (nucleotide && forPca
+            && Cache.getDefault("BLOSUM62_PCA_FOR_NUCLEOTIDE", false))
+    {
+      filtered.add(scoreModels.getBlosum62());
+    }
+
+    return filtered;
+  }
+
+  /**
    * Open and calculate the selected tree or PCA on 'OK'
    */
   protected void calculate_actionPerformed()
@@ -539,7 +584,13 @@ public class CalculationChooser extends JPanel
               JvOptionPane.WARNING_MESSAGE);
       return;
     }
+
+    /*
+     * construct the panel and kick off its calculation thread
+     */
     pcaPanel = new PCAPanel(af.alignPanel, modelName, params);
+    new Thread(pcaPanel).start();
+
   }
 
   /**
index a135785..dbe3317 100644 (file)
@@ -79,7 +79,6 @@ import javax.swing.BorderFactory;
 import javax.swing.Icon;
 import javax.swing.JButton;
 import javax.swing.JCheckBox;
-import javax.swing.JCheckBoxMenuItem;
 import javax.swing.JColorChooser;
 import javax.swing.JDialog;
 import javax.swing.JInternalFrame;
@@ -219,7 +218,8 @@ public class FeatureSettings extends JPanel
           FeatureMatcherSet o = (FeatureMatcherSet) table.getValueAt(row,
                   column);
           tip = o.isEmpty()
-                  ? MessageManager.getString("label.filters_tooltip")
+                  ? MessageManager
+                          .getString("label.configure_feature_tooltip")
                   : o.toString();
           break;
         default:
@@ -415,69 +415,6 @@ public class FeatureSettings extends JPanel
     });
     men.add(dens);
 
-    /*
-     * variable colour options include colour by label, by score,
-     * by selected attribute text, or attribute value
-     */
-    final JCheckBoxMenuItem mxcol = new JCheckBoxMenuItem(
-            MessageManager.getString("label.variable_colour"));
-    mxcol.setSelected(!featureColour.isSimpleColour());
-    men.add(mxcol);
-    mxcol.addActionListener(new ActionListener()
-    {
-      JColorChooser colorChooser;
-
-      @Override
-      public void actionPerformed(ActionEvent e)
-      {
-        if (e.getSource() == mxcol)
-        {
-          if (featureColour.isSimpleColour())
-          {
-            FeatureTypeSettings fc = new FeatureTypeSettings(me.fr, type);
-            fc.addActionListener(this);
-          }
-          else
-          {
-            // bring up simple color chooser
-            colorChooser = new JColorChooser();
-            String title = MessageManager
-                    .getString("label.select_colour");
-            JDialog dialog = JColorChooser.createDialog(me,
-                    title, true, // modal
-                    colorChooser, this, // OK button handler
-                    null); // no CANCEL button handler
-            colorChooser.setColor(featureColour.getMaxColour());
-            dialog.setVisible(true);
-          }
-        }
-        else
-        {
-          if (e.getSource() instanceof FeatureTypeSettings)
-          {
-            /*
-             * update after OK in feature colour dialog; the updated
-             * colour will have already been set in the FeatureRenderer
-             */
-            FeatureColourI fci = fr.getFeatureColours().get(type);
-            table.setValueAt(fci, rowSelected, 1);
-            table.validate();
-          }
-          else
-          {
-            // probably the color chooser!
-            table.setValueAt(new FeatureColour(colorChooser.getColor()),
-                    rowSelected, 1);
-            table.validate();
-            me.updateFeatureRenderer(
-                    ((FeatureTableModel) table.getModel()).getData(),
-                    false);
-          }
-        }
-      }
-
-    });
-
     JMenuItem selCols = new JMenuItem(
             MessageManager.getString("label.select_columns_containing"));
     selCols.addActionListener(new ActionListener()
@@ -1354,7 +1291,7 @@ public class FeatureSettings extends JPanel
     private String[] columnNames = {
         MessageManager.getString("label.feature_type"),
         MessageManager.getString("action.colour"),
-        MessageManager.getString("label.filter"),
+        MessageManager.getString("label.configuration"),
         MessageManager.getString("label.show") };
 
     private Object[][] data;
index 55bc519..58bbbe8 100644 (file)
@@ -242,8 +242,7 @@ public class FeatureTypeSettings extends JalviewDialog
     String title = MessageManager
             .formatMessage("label.display_settings_for", new String[]
             { theType });
-    initDialogFrame(this, true, false, title, 500, 500);
-    
+    initDialogFrame(this, true, false, title, 580, 500);
     waitForInput();
   }
 
@@ -366,7 +365,7 @@ public class FeatureTypeSettings extends JalviewDialog
                         : BELOW_THRESHOLD_OPTION);
         slider.setEnabled(true);
         slider.setValue((int) (fc.getThreshold() * scaleFactor));
-        thresholdValue.setText(String.valueOf(getRoundedSliderValue()));
+        thresholdValue.setText(String.valueOf(fc.getThreshold()));
         thresholdValue.setEnabled(true);
         thresholdIsMin.setEnabled(true);
       }
@@ -652,6 +651,7 @@ public class FeatureTypeSettings extends JalviewDialog
         {
           thresholdValue
                   .setText(String.valueOf(slider.getValue() / scaleFactor));
+          thresholdValue.setBackground(Color.white); // to reset red for invalid
           sliderValueChanged();
         }
       }
@@ -1019,21 +1019,23 @@ public class FeatureTypeSettings extends JalviewDialog
   {
     try
     {
+      /*
+       * set 'adjusting' flag while moving the slider, so it 
+       * doesn't then in turn change the value (with rounding)
+       */
       adjusting = true;
       float f = Float.parseFloat(thresholdValue.getText());
+      f = Float.max(f,  this.min);
+      f = Float.min(f, this.max);
+      thresholdValue.setText(String.valueOf(f));
       slider.setValue((int) (f * scaleFactor));
       threshline.value = f;
       thresholdValue.setBackground(Color.white); // ok
-
-      /*
-       * force repaint of any Overview window or structure
-       */
-      ap.paintAlignment(true, true);
+      adjusting = false;
+      colourChanged(true);
     } catch (NumberFormatException ex)
     {
       thresholdValue.setBackground(Color.red); // not ok
-    } finally
-    {
       adjusting = false;
     }
   }
index cc361a5..89088b8 100644 (file)
@@ -257,6 +257,7 @@ public class OverviewCanvas extends JComponent
   public void dispose()
   {
     dispose = true;
+    od = null;
     synchronized (this)
     {
       restart = true;
index c1e935a..3388d4d 100644 (file)
 package jalview.gui;
 
 import jalview.analysis.scoremodels.ScoreModels;
-import jalview.analysis.scoremodels.SimilarityParams;
+import jalview.api.AlignViewportI;
 import jalview.api.analysis.ScoreModelI;
 import jalview.api.analysis.SimilarityParamsI;
+import jalview.bin.Cache;
 import jalview.datamodel.Alignment;
 import jalview.datamodel.AlignmentI;
 import jalview.datamodel.AlignmentView;
 import jalview.datamodel.HiddenColumns;
 import jalview.datamodel.SequenceI;
 import jalview.jbgui.GPCAPanel;
+import jalview.math.RotatableMatrix.Axis;
+import jalview.util.ImageMaker;
 import jalview.util.MessageManager;
 import jalview.viewmodel.AlignmentViewport;
 import jalview.viewmodel.PCAModel;
@@ -46,7 +49,6 @@ import java.awt.print.PrinterException;
 import java.awt.print.PrinterJob;
 
 import javax.swing.ButtonGroup;
-import javax.swing.JCheckBoxMenuItem;
 import javax.swing.JColorChooser;
 import javax.swing.JMenuItem;
 import javax.swing.JRadioButtonMenuItem;
@@ -54,49 +56,30 @@ import javax.swing.event.InternalFrameAdapter;
 import javax.swing.event.InternalFrameEvent;
 
 /**
- * DOCUMENT ME!
- * 
- * @author $author$
- * @version $Revision$
+ * The panel holding the Principal Component Analysis 3-D visualisation
  */
 public class PCAPanel extends GPCAPanel
         implements Runnable, IProgressIndicator
 {
+  private static final int MIN_WIDTH = 470;
 
-  private IProgressIndicator progressBar;
+  private static final int MIN_HEIGHT = 250;
 
-  RotatableCanvas rc;
+  private RotatableCanvas rc;
 
   AlignmentPanel ap;
 
   AlignmentViewport av;
 
-  PCAModel pcaModel;
+  private PCAModel pcaModel;
 
-  private static final int MIN_WIDTH = 470;
-
-  private static final int MIN_HEIGHT = 250;
+  private int top = 0;
 
-  int top = 0;
+  private IProgressIndicator progressBar;
 
   private boolean working;
 
   /**
-   * Creates a new PCAPanel object using default score model and parameters
-   * 
-   * @param alignPanel
-   */
-  public PCAPanel(AlignmentPanel alignPanel)
-  {
-    this(alignPanel,
-            ScoreModels.getInstance()
-                    .getDefaultModel(
-                            !alignPanel.av.getAlignment().isNucleotide())
-                    .getName(),
-            SimilarityParams.SeqSpace);
-  }
-
-  /**
    * Constructor given sequence data, a similarity (or distance) score model
    * name, and score calculation parameters
    * 
@@ -138,14 +121,17 @@ public class PCAPanel extends GPCAPanel
 
     ScoreModelI scoreModel = ScoreModels.getInstance()
             .getScoreModel(modelName, ap);
-    pcaModel = new PCAModel(seqstrings, seqs, nucleotide, scoreModel,
-            params);
+    setPcaModel(new PCAModel(seqstrings, seqs, nucleotide, scoreModel,
+            params));
     PaintRefresher.Register(this, av.getSequenceSetId());
 
-    rc = new RotatableCanvas(alignPanel);
-    this.getContentPane().add(rc, BorderLayout.CENTER);
-    Thread worker = new Thread(this);
-    worker.start();
+    setRotatableCanvas(new RotatableCanvas(alignPanel));
+    this.getContentPane().add(getRotatableCanvas(), BorderLayout.CENTER);
+
+    addKeyListener(getRotatableCanvas());
+    validate();
+
+    this.setMinimumSize(new Dimension(MIN_WIDTH, MIN_HEIGHT));
   }
 
   /**
@@ -154,79 +140,30 @@ public class PCAPanel extends GPCAPanel
    */
   protected void close_actionPerformed()
   {
-    pcaModel = null;
-  }
-
-  /**
-   * Repopulate the options and actions under the score model menu when it is
-   * selected. Options will depend on whether 'nucleotide' or 'peptide'
-   * modelling is selected (and also possibly on whether any additional score
-   * models have been added).
-   */
-  @Override
-  protected void scoreModel_menuSelected()
-  {
-    scoreModelMenu.removeAll();
-    for (final ScoreModelI sm : ScoreModels.getInstance().getModels())
-    {
-      final String name = sm.getName();
-      JCheckBoxMenuItem jm = new JCheckBoxMenuItem(name);
-
-      /*
-       * if the score model doesn't provide a description, try to look one
-       * up in the text bundle, falling back on its name
-       */
-      String tooltip = sm.getDescription();
-      if (tooltip == null)
-      {
-        tooltip = MessageManager.getStringOrReturn("label.score_model_",
-                name);
-      }
-      jm.setToolTipText(tooltip);
-      jm.setSelected(pcaModel.getScoreModelName().equals(name));
-      if ((pcaModel.isNucleotide() && sm.isDNA())
-              || (!pcaModel.isNucleotide() && sm.isProtein()))
-      {
-        jm.addActionListener(new ActionListener()
-        {
-          @Override
-          public void actionPerformed(ActionEvent e)
-          {
-            if (!pcaModel.getScoreModelName().equals(name))
-            {
-              ScoreModelI sm2 = ScoreModels.getInstance()
-                      .getScoreModel(name, ap);
-              pcaModel.setScoreModel(sm2);
-              Thread worker = new Thread(PCAPanel.this);
-              worker.start();
-            }
-          }
-        });
-        scoreModelMenu.add(jm);
-      }
-    }
+    setPcaModel(null);
   }
 
   @Override
-  public void bgcolour_actionPerformed(ActionEvent e)
+  protected void bgcolour_actionPerformed()
   {
     Color col = JColorChooser.showDialog(this,
             MessageManager.getString("label.select_background_colour"),
-            rc.bgColour);
+            getRotatableCanvas().getBgColour());
 
     if (col != null)
     {
-      rc.bgColour = col;
+      getRotatableCanvas().setBgColour(col);
     }
-    rc.repaint();
+    getRotatableCanvas().repaint();
   }
 
   /**
-   * DOCUMENT ME!
+   * Calculates the PCA and displays the results
    */
   @Override
   public void run()
   {
+    working = true;
     long progId = System.currentTimeMillis();
     IProgressIndicator progress = this;
     String message = MessageManager.getString("label.pca_recalculating");
@@ -236,21 +173,17 @@ public class PCAPanel extends GPCAPanel
       message = MessageManager.getString("label.pca_calculating");
     }
     progress.setProgressBar(message, progId);
-    working = true;
     try
     {
-      calcSettings.setEnabled(false);
-      pcaModel.run();
-      // ////////////////
+      getPcaModel().calculate();
+
       xCombobox.setSelectedIndex(0);
       yCombobox.setSelectedIndex(1);
       zCombobox.setSelectedIndex(2);
 
-      pcaModel.updateRc(rc);
+      getPcaModel().updateRc(getRotatableCanvas());
       // rc.invalidate();
-      nuclSetting.setSelected(pcaModel.isNucleotide());
-      protSetting.setSelected(!pcaModel.isNucleotide());
-      top = pcaModel.getTop();
+      setTop(getPcaModel().getTop());
 
     } catch (OutOfMemoryError er)
     {
@@ -261,109 +194,68 @@ public class PCAPanel extends GPCAPanel
     {
       progress.setProgressBar("", progId);
     }
-    calcSettings.setEnabled(true);
+
     repaint();
     if (getParent() == null)
     {
-      addKeyListener(rc);
-      Desktop.addInternalFrame(this, MessageManager
-              .getString("label.principal_component_analysis"), 475, 450);
-      this.setMinimumSize(new Dimension(MIN_WIDTH, MIN_HEIGHT));
+      Desktop.addInternalFrame(this,
+              MessageManager.formatMessage("label.calc_title", "PCA",
+                      getPcaModel().getScoreModelName()),
+              475, 450);
     }
     working = false;
   }
 
-  @Override
-  protected void nuclSetting_actionPerfomed(ActionEvent arg0)
-  {
-    if (!pcaModel.isNucleotide())
-    {
-      pcaModel.setNucleotide(true);
-      pcaModel.setScoreModel(
-              ScoreModels.getInstance().getDefaultModel(false));
-      Thread worker = new Thread(this);
-      worker.start();
-    }
-
-  }
-
-  @Override
-  protected void protSetting_actionPerfomed(ActionEvent arg0)
-  {
-
-    if (pcaModel.isNucleotide())
-    {
-      pcaModel.setNucleotide(false);
-      pcaModel.setScoreModel(
-              ScoreModels.getInstance().getDefaultModel(true));
-      Thread worker = new Thread(this);
-      worker.start();
-    }
-  }
-
   /**
-   * DOCUMENT ME!
+   * Updates the PCA display after a change of component to use for x, y or z
+   * axis
    */
-  void doDimensionChange()
+  @Override
+  protected void doDimensionChange()
   {
-    if (top == 0)
+    if (getTop() == 0)
     {
       return;
     }
 
-    int dim1 = top - xCombobox.getSelectedIndex();
-    int dim2 = top - yCombobox.getSelectedIndex();
-    int dim3 = top - zCombobox.getSelectedIndex();
-    pcaModel.updateRcView(dim1, dim2, dim3);
-    rc.img = null;
-    rc.rotmat.setIdentity();
-    rc.initAxes();
-    rc.paint(rc.getGraphics());
-  }
-
-  /**
-   * DOCUMENT ME!
-   * 
-   * @param e
-   *          DOCUMENT ME!
-   */
-  @Override
-  protected void xCombobox_actionPerformed(ActionEvent e)
-  {
-    doDimensionChange();
-  }
-
-  /**
-   * DOCUMENT ME!
-   * 
-   * @param e
-   *          DOCUMENT ME!
-   */
-  @Override
-  protected void yCombobox_actionPerformed(ActionEvent e)
-  {
-    doDimensionChange();
+    int dim1 = getTop() - xCombobox.getSelectedIndex();
+    int dim2 = getTop() - yCombobox.getSelectedIndex();
+    int dim3 = getTop() - zCombobox.getSelectedIndex();
+    getPcaModel().updateRcView(dim1, dim2, dim3);
+    getRotatableCanvas().resetView();
   }
 
   /**
-   * DOCUMENT ME!
+   * Sets the selected checkbox item index for PCA dimension (1, 2, 3...) for
+   * the given axis (X/Y/Z)
    * 
-   * @param e
-   *          DOCUMENT ME!
+   * @param index
+   * @param axis
    */
-  @Override
-  protected void zCombobox_actionPerformed(ActionEvent e)
+  public void setSelectedDimensionIndex(int index, Axis axis)
   {
-    doDimensionChange();
+    switch (axis)
+    {
+    case X:
+      xCombobox.setSelectedIndex(index);
+      break;
+    case Y:
+      yCombobox.setSelectedIndex(index);
+      break;
+    case Z:
+      zCombobox.setSelectedIndex(index);
+      break;
+    default:
+    }
   }
 
   @Override
-  public void outputValues_actionPerformed(ActionEvent e)
+  protected void outputValues_actionPerformed()
   {
     CutAndPasteTransfer cap = new CutAndPasteTransfer();
     try
     {
-      cap.setText(pcaModel.getDetails());
+      cap.setText(getPcaModel().getDetails());
       Desktop.addInternalFrame(cap,
               MessageManager.getString("label.pca_details"), 500, 500);
     } catch (OutOfMemoryError oom)
@@ -374,32 +266,35 @@ public class PCAPanel extends GPCAPanel
   }
 
   @Override
-  public void showLabels_actionPerformed(ActionEvent e)
+  protected void showLabels_actionPerformed()
   {
-    rc.showLabels(showLabels.getState());
+    getRotatableCanvas().showLabels(showLabels.getState());
   }
 
   @Override
-  public void print_actionPerformed(ActionEvent e)
+  protected void print_actionPerformed()
   {
     PCAPrinter printer = new PCAPrinter();
     printer.start();
   }
 
+  /**
+   * If available, shows the data which formed the inputs for the PCA as a new
+   * alignment
+   */
   @Override
-  public void originalSeqData_actionPerformed(ActionEvent e)
+  public void originalSeqData_actionPerformed()
   {
-    // this was cut'n'pasted from the equivalent TreePanel method - we should
-    // make this an abstract function of all jalview analysis windows
-    if (pcaModel.getSeqtrings() == null)
+    // JAL-2647 disabled after load from project (until save to project done)
+    if (getPcaModel().getInputData() == null)
     {
-      jalview.bin.Cache.log.info(
+      Cache.log.info(
               "Unexpected call to originalSeqData_actionPerformed - should have hidden this menu action.");
       return;
     }
     // decide if av alignment is sufficiently different to original data to
     // warrant a new window to be created
-    // create new alignmnt window with hidden regions (unhiding hidden regions
+    // create new alignment window with hidden regions (unhiding hidden regions
     // yields unaligned seqs)
     // or create a selection box around columns in alignment view
     // test Alignment(SeqCigar[])
@@ -412,8 +307,8 @@ public class PCAPanel extends GPCAPanel
     } catch (Exception ex)
     {
     }
-    ;
-    Object[] alAndColsel = pcaModel.getSeqtrings()
+
+    Object[] alAndColsel = getPcaModel().getInputData()
             .getAlignmentAndHiddenColumns(gc);
 
     if (alAndColsel != null && alAndColsel[0] != null)
@@ -495,11 +390,11 @@ public class PCAPanel extends GPCAPanel
     {
       pg.translate((int) pf.getImageableX(), (int) pf.getImageableY());
 
-      rc.drawBackground(pg, rc.bgColour);
-      rc.drawScene(pg);
-      if (rc.drawAxes == true)
+      getRotatableCanvas().drawBackground(pg);
+      getRotatableCanvas().drawScene(pg);
+      if (getRotatableCanvas().drawAxes)
       {
-        rc.drawAxes(pg);
+        getRotatableCanvas().drawAxes(pg);
       }
 
       if (pi == 0)
@@ -514,79 +409,75 @@ public class PCAPanel extends GPCAPanel
   }
 
   /**
-   * DOCUMENT ME!
-   * 
-   * @param e
-   *          DOCUMENT ME!
+   * Handler for 'Save as EPS' option
    */
   @Override
-  public void eps_actionPerformed(ActionEvent e)
+  protected void eps_actionPerformed()
   {
-    makePCAImage(jalview.util.ImageMaker.TYPE.EPS);
+    makePCAImage(ImageMaker.TYPE.EPS);
   }
 
   /**
-   * DOCUMENT ME!
-   * 
-   * @param e
-   *          DOCUMENT ME!
+   * Handler for 'Save as PNG' option
    */
   @Override
-  public void png_actionPerformed(ActionEvent e)
+  protected void png_actionPerformed()
   {
-    makePCAImage(jalview.util.ImageMaker.TYPE.PNG);
+    makePCAImage(ImageMaker.TYPE.PNG);
   }
 
-  void makePCAImage(jalview.util.ImageMaker.TYPE type)
+  void makePCAImage(ImageMaker.TYPE type)
   {
-    int width = rc.getWidth();
-    int height = rc.getHeight();
-
-    jalview.util.ImageMaker im;
-
-    if (type == jalview.util.ImageMaker.TYPE.PNG)
-    {
-      im = new jalview.util.ImageMaker(this,
-              jalview.util.ImageMaker.TYPE.PNG, "Make PNG image from PCA",
-              width, height, null, null, null, 0, false);
-    }
-    else if (type == jalview.util.ImageMaker.TYPE.EPS)
-    {
-      im = new jalview.util.ImageMaker(this,
-              jalview.util.ImageMaker.TYPE.EPS, "Make EPS file from PCA",
-              width, height, null, this.getTitle(), null, 0, false);
-    }
-    else
-    {
-      im = new jalview.util.ImageMaker(this,
-              jalview.util.ImageMaker.TYPE.SVG, "Make SVG file from PCA",
-              width, height, null, this.getTitle(), null, 0, false);
-
+    int width = getRotatableCanvas().getWidth();
+    int height = getRotatableCanvas().getHeight();
+
+    ImageMaker im;
+
+    switch (type)
+    {
+    case PNG:
+      im = new ImageMaker(this, ImageMaker.TYPE.PNG,
+              "Make PNG image from PCA", width, height, null, null, null, 0,
+              false);
+      break;
+    case EPS:
+      im = new ImageMaker(this, ImageMaker.TYPE.EPS,
+              "Make EPS file from PCA", width, height, null,
+              this.getTitle(), null, 0, false);
+      break;
+    default:
+      im = new ImageMaker(this, ImageMaker.TYPE.SVG,
+              "Make SVG file from PCA", width, height, null,
+              this.getTitle(), null, 0, false);
     }
 
     if (im.getGraphics() != null)
     {
-      rc.drawBackground(im.getGraphics(), Color.black);
-      rc.drawScene(im.getGraphics());
-      if (rc.drawAxes == true)
+      getRotatableCanvas().drawBackground(im.getGraphics());
+      getRotatableCanvas().drawScene(im.getGraphics());
+      if (getRotatableCanvas().drawAxes)
       {
-        rc.drawAxes(im.getGraphics());
+        getRotatableCanvas().drawAxes(im.getGraphics());
       }
       im.writeImage();
     }
   }
 
   @Override
-  public void viewMenu_menuSelected()
+  protected void viewMenu_menuSelected()
   {
     buildAssociatedViewMenu();
   }
 
+  /**
+   * Builds the menu showing the choice of possible views (for the associated
+   * sequence data) to which the PCA may be linked
+   */
   void buildAssociatedViewMenu()
   {
     AlignmentPanel[] aps = PaintRefresher
             .getAssociatedPanels(av.getSequenceSetId());
-    if (aps.length == 1 && rc.av == aps[0].av)
+    if (aps.length == 1 && getRotatableCanvas().av == aps[0].av)
     {
       associateViewsMenu.setVisible(false);
       return;
@@ -604,22 +495,20 @@ public class PCAPanel extends GPCAPanel
 
     JRadioButtonMenuItem item;
     ButtonGroup buttonGroup = new ButtonGroup();
-    int i, iSize = aps.length;
-    final PCAPanel thisPCAPanel = this;
-    for (i = 0; i < iSize; i++)
+    int iSize = aps.length;
+
+    for (int i = 0; i < iSize; i++)
     {
-      final AlignmentPanel ap = aps[i];
-      item = new JRadioButtonMenuItem(ap.av.getViewName(), ap.av == rc.av);
+      final AlignmentPanel panel = aps[i];
+      item = new JRadioButtonMenuItem(panel.av.getViewName(),
+              panel.av == getRotatableCanvas().av);
       buttonGroup.add(item);
       item.addActionListener(new ActionListener()
       {
         @Override
         public void actionPerformed(ActionEvent evt)
         {
-          rc.applyToAllViews = false;
-          rc.av = ap.av;
-          rc.ap = ap;
-          PaintRefresher.Register(thisPCAPanel, ap.av.getSequenceSetId());
+          selectAssociatedView(panel);
         }
       });
 
@@ -631,13 +520,13 @@ public class PCAPanel extends GPCAPanel
 
     buttonGroup.add(itemf);
 
-    itemf.setSelected(rc.applyToAllViews);
+    itemf.setSelected(getRotatableCanvas().isApplyToAllViews());
     itemf.addActionListener(new ActionListener()
     {
       @Override
       public void actionPerformed(ActionEvent evt)
       {
-        rc.applyToAllViews = itemf.isSelected();
+        getRotatableCanvas().setApplyToAllViews(itemf.isSelected());
       }
     });
     associateViewsMenu.add(itemf);
@@ -652,12 +541,12 @@ public class PCAPanel extends GPCAPanel
    * )
    */
   @Override
-  protected void outputPoints_actionPerformed(ActionEvent e)
+  protected void outputPoints_actionPerformed()
   {
     CutAndPasteTransfer cap = new CutAndPasteTransfer();
     try
     {
-      cap.setText(pcaModel.getPointsasCsv(false,
+      cap.setText(getPcaModel().getPointsasCsv(false,
               xCombobox.getSelectedIndex(), yCombobox.getSelectedIndex(),
               zCombobox.getSelectedIndex()));
       Desktop.addInternalFrame(cap, MessageManager
@@ -678,12 +567,12 @@ public class PCAPanel extends GPCAPanel
    * .ActionEvent)
    */
   @Override
-  protected void outputProjPoints_actionPerformed(ActionEvent e)
+  protected void outputProjPoints_actionPerformed()
   {
     CutAndPasteTransfer cap = new CutAndPasteTransfer();
     try
     {
-      cap.setText(pcaModel.getPointsasCsv(true,
+      cap.setText(getPcaModel().getPointsasCsv(true,
               xCombobox.getSelectedIndex(), yCombobox.getSelectedIndex(),
               zCombobox.getSelectedIndex()));
       Desktop.addInternalFrame(cap, MessageManager.formatMessage(
@@ -793,13 +682,13 @@ public class PCAPanel extends GPCAPanel
   }
 
   @Override
-  protected void resetButton_actionPerformed(ActionEvent e)
+  protected void resetButton_actionPerformed()
   {
-    int t = top;
-    top = 0; // ugly - prevents dimensionChanged events from being processed
+    int t = getTop();
+    setTop(0); // ugly - prevents dimensionChanged events from being processed
     xCombobox.setSelectedIndex(0);
     yCombobox.setSelectedIndex(1);
-    top = t;
+    setTop(t);
     zCombobox.setSelectedIndex(2);
   }
 
@@ -812,4 +701,94 @@ public class PCAPanel extends GPCAPanel
   {
     return working;
   }
+
+  /**
+   * Answers the selected checkbox item index for PCA dimension for the X, Y or
+   * Z axis of the display
+   * 
+   * @param axis
+   * @return
+   */
+  public int getSelectedDimensionIndex(Axis axis)
+  {
+    switch (axis)
+    {
+    case X:
+      return xCombobox.getSelectedIndex();
+    case Y:
+      return yCombobox.getSelectedIndex();
+    default:
+      return zCombobox.getSelectedIndex();
+    }
+  }
+
+  public void setShowLabels(boolean show)
+  {
+    showLabels.setSelected(show);
+  }
+
+  /**
+   * Sets the input data used to calculate the PCA. This is provided for
+   * 'restore from project', which does not currently support this (AL-2647), so
+   * sets the value to null, and hides the menu option for "Input Data...". J
+   * 
+   * @param data
+   */
+  public void setInputData(AlignmentView data)
+  {
+    getPcaModel().setInputData(data);
+    originalSeqData.setVisible(data != null);
+  }
+
+  public AlignViewportI getAlignViewport()
+  {
+    return av;
+  }
+
+  public PCAModel getPcaModel()
+  {
+    return pcaModel;
+  }
+
+  public void setPcaModel(PCAModel pcaModel)
+  {
+    this.pcaModel = pcaModel;
+  }
+
+  public RotatableCanvas getRotatableCanvas()
+  {
+    return rc;
+  }
+
+  public void setRotatableCanvas(RotatableCanvas rc)
+  {
+    this.rc = rc;
+  }
+
+  public int getTop()
+  {
+    return top;
+  }
+
+  public void setTop(int top)
+  {
+    this.top = top;
+  }
+
+  /**
+   * set the associated view for this PCA.
+   * 
+   * @param panel
+   */
+  public void selectAssociatedView(AlignmentPanel panel)
+  {
+    getRotatableCanvas().setApplyToAllViews(false);
+
+    ap = panel;
+    av = panel.av;
+
+    getRotatableCanvas().av = panel.av;
+    getRotatableCanvas().ap = panel;
+    PaintRefresher.Register(PCAPanel.this, panel.av.getSequenceSetId());
+  }
 }
index 02368df..dc0cdb4 100755 (executable)
 package jalview.gui;
 
 import jalview.api.RotatableCanvasI;
+import jalview.datamodel.Point;
 import jalview.datamodel.SequenceGroup;
 import jalview.datamodel.SequenceI;
 import jalview.datamodel.SequencePoint;
 import jalview.math.RotatableMatrix;
+import jalview.math.RotatableMatrix.Axis;
+import jalview.util.ColorUtils;
 import jalview.util.MessageManager;
 import jalview.viewmodel.AlignmentViewport;
 
@@ -43,328 +46,192 @@ import java.awt.event.MouseListener;
 import java.awt.event.MouseMotionListener;
 import java.awt.event.MouseWheelEvent;
 import java.awt.event.MouseWheelListener;
-import java.util.Vector;
+import java.util.Arrays;
+import java.util.Iterator;
+import java.util.List;
 
 import javax.swing.JPanel;
 import javax.swing.ToolTipManager;
 
 /**
- * DOCUMENT ME!
- * 
- * @author $author$
- * @version $Revision$
+ * Models a Panel on which a set of points, and optionally x/y/z axes, can be
+ * drawn, and rotated or zoomed with the mouse
  */
 public class RotatableCanvas extends JPanel implements MouseListener,
-        MouseMotionListener, KeyListener, RotatableCanvasI
+        MouseMotionListener, KeyListener, RotatableCanvasI,
+        MouseWheelListener
 {
-  RotatableMatrix idmat = new RotatableMatrix(3, 3);
+  private static final float ZOOM_OUT = 0.9f;
 
-  RotatableMatrix objmat = new RotatableMatrix(3, 3);
+  private static final float ZOOM_IN = 1.1f;
 
-  RotatableMatrix rotmat = new RotatableMatrix(3, 3);
+  /*
+   * pixels distance within which tooltip shows sequence name
+   */
+  private static final int NEARBY = 3;
 
-  // RubberbandRectangle rubberband;
-  boolean drawAxes = true;
+  private static final List<String> AXES = Arrays.asList("x", "y", "z");
 
-  int omx = 0;
+  private static final Color AXIS_COLOUR = Color.yellow;
 
-  int mx = 0;
+  private static final int DIMS = 3;
 
-  int omy = 0;
+  boolean drawAxes = true;
+
+  int mouseX;
 
-  int my = 0;
+  int mouseY;
 
   Image img;
 
   Graphics ig;
 
-  Dimension prefsize;
-
-  float[] centre = new float[3];
+  Dimension prefSize;
 
-  float[] width = new float[3];
-
-  float[] max = new float[3];
-
-  float[] min = new float[3];
+  /*
+   * the min-max [x, y, z] values of sequence points when the points
+   * were set on the object, or when the view is reset; 
+   * x and y ranges are not recomputed as points are rotated, as this
+   * would make scaling (zoom) unstable, but z ranges are (for correct
+   * graduated colour brightness based on z-coordinate)
+   */
+  float[] seqMin;
 
-  float maxwidth;
+  float[] seqMax;
 
-  float scale;
+  /*
+   * a scale factor used in drawing; when equal to 1, the points span
+   * half the available width or height (whichever is less); increase this
+   * factor to zoom in, decrease it to zoom out
+   */
+  private float scaleFactor;
 
   int npoint;
 
-  Vector points;
-
-  float[][] orig;
-
-  float[][] axes;
-
-  int startx;
-
-  int starty;
-
-  int lastx;
-
-  int lasty;
-
-  int rectx1;
-
-  int recty1;
-
-  int rectx2;
+  /*
+   * sequences and their (x, y, z) PCA dimension values
+   */
+  List<SequencePoint> sequencePoints;
 
-  int recty2;
+  /*
+   * x, y, z axis end points (PCA dimension values)
+   */
+  private Point[] axisEndPoints;
 
-  float scalefactor = 1;
+  // fields for 'select rectangle' (JAL-1124)
+  // int rectx1;
+  // int recty1;
+  // int rectx2;
+  // int recty2;
 
   AlignmentViewport av;
 
   AlignmentPanel ap;
 
-  boolean showLabels = false;
+  private boolean showLabels;
 
-  Color bgColour = Color.black;
+  private Color bgColour;
 
-  boolean applyToAllViews = false;
+  private boolean applyToAllViews;
 
-  public RotatableCanvas(AlignmentPanel ap)
+  /**
+   * Constructor
+   * 
+   * @param panel
+   */
+  public RotatableCanvas(AlignmentPanel panel)
   {
-    this.av = ap.av;
-    this.ap = ap;
-
-    addMouseWheelListener(new MouseWheelListener()
-    {
-      @Override
-      public void mouseWheelMoved(MouseWheelEvent e)
-      {
-        double wheelRotation = e.getPreciseWheelRotation();
-        if (wheelRotation > 0)
-        {
-          /*
-           * zoom in
-           */
-          scale = (float) (scale * 1.1);
-          repaint();
-        }
-        else if (wheelRotation < 0)
-        {
-          /*
-           * zoom out
-           */
-          scale = (float) (scale * 0.9);
-          repaint();
-        }
-      }
-    });
-
+    this.av = panel.av;
+    this.ap = panel;
+    setAxisEndPoints(new Point[DIMS]);
+    setShowLabels(false);
+    setApplyToAllViews(false);
+    setBgColour(Color.BLACK);
+    resetAxes();
+
+    ToolTipManager.sharedInstance().registerComponent(this);
+
+    addMouseListener(this);
+    addMouseMotionListener(this);
+    addMouseWheelListener(this);
   }
 
-  public void showLabels(boolean b)
+  /**
+   * Refreshes the display with labels shown (or not)
+   * 
+   * @param show
+   */
+  public void showLabels(boolean show)
   {
-    showLabels = b;
+    setShowLabels(show);
     repaint();
   }
 
-  boolean first = true;
-
   @Override
-  public void setPoints(Vector points, int npoint)
+  public void setPoints(List<SequencePoint> points, int np)
   {
-    this.points = points;
-    this.npoint = npoint;
-    if (first)
-    {
-      ToolTipManager.sharedInstance().registerComponent(this);
-      ToolTipManager.sharedInstance().setInitialDelay(0);
-      ToolTipManager.sharedInstance().setDismissDelay(10000);
-    }
-    prefsize = getPreferredSize();
-    orig = new float[npoint][3];
+    this.sequencePoints = points;
+    this.npoint = np;
+    prefSize = getPreferredSize();
 
-    for (int i = 0; i < npoint; i++)
-    {
-      SequencePoint sp = (SequencePoint) points.elementAt(i);
+    findWidths();
 
-      for (int j = 0; j < 3; j++)
-      {
-        orig[i][j] = sp.coord[j];
-      }
-    }
-
-    // Initialize the matrices to identity
-    for (int i = 0; i < 3; i++)
-    {
-      for (int j = 0; j < 3; j++)
-      {
-        if (i != j)
-        {
-          idmat.addElement(i, j, 0);
-          objmat.addElement(i, j, 0);
-          rotmat.addElement(i, j, 0);
-        }
-        else
-        {
-          idmat.addElement(i, j, 0);
-          objmat.addElement(i, j, 0);
-          rotmat.addElement(i, j, 0);
-        }
-      }
-    }
-
-    axes = new float[3][3];
-    initAxes();
-
-    findCentre();
-    findWidth();
-
-    scale = findScale();
-    if (first)
-    {
-
-      addMouseListener(this);
-
-      addMouseMotionListener(this);
-    }
-    first = false;
-  }
-
-  public void initAxes()
-  {
-    for (int i = 0; i < 3; i++)
-    {
-      for (int j = 0; j < 3; j++)
-      {
-        if (i != j)
-        {
-          axes[i][j] = 0;
-        }
-        else
-        {
-          axes[i][j] = 1;
-        }
-      }
-    }
+    setScaleFactor(1f);
   }
 
   /**
-   * DOCUMENT ME!
+   * Resets axes to the initial state: x-axis to the right, y-axis up, z-axis to
+   * back (so obscured in a 2-D display)
    */
-  public void findWidth()
+  protected void resetAxes()
   {
-    max = new float[3];
-    min = new float[3];
-
-    max[0] = (float) -1e30;
-    max[1] = (float) -1e30;
-    max[2] = (float) -1e30;
-
-    min[0] = (float) 1e30;
-    min[1] = (float) 1e30;
-    min[2] = (float) 1e30;
-
-    for (int i = 0; i < 3; i++)
-    {
-      for (int j = 0; j < npoint; j++)
-      {
-        SequencePoint sp = (SequencePoint) points.elementAt(j);
-
-        if (sp.coord[i] >= max[i])
-        {
-          max[i] = sp.coord[i];
-        }
-
-        if (sp.coord[i] <= min[i])
-        {
-          min[i] = sp.coord[i];
-        }
-      }
-    }
-
-    // System.out.println("xmax " + max[0] + " min " + min[0]);
-    // System.out.println("ymax " + max[1] + " min " + min[1]);
-    // System.out.println("zmax " + max[2] + " min " + min[2]);
-    width[0] = Math.abs(max[0] - min[0]);
-    width[1] = Math.abs(max[1] - min[1]);
-    width[2] = Math.abs(max[2] - min[2]);
-
-    maxwidth = width[0];
-
-    if (width[1] > width[0])
-    {
-      maxwidth = width[1];
-    }
-
-    if (width[2] > width[1])
-    {
-      maxwidth = width[2];
-    }
-
-    // System.out.println("Maxwidth = " + maxwidth);
-  }
-
-  /**
-   * DOCUMENT ME!
-   * 
-   * @return DOCUMENT ME!
-   */
-  public float findScale()
-  {
-    int dim;
-    int width;
-    int height;
-
-    if (getWidth() != 0)
-    {
-      width = getWidth();
-      height = getHeight();
-    }
-    else
-    {
-      width = prefsize.width;
-      height = prefsize.height;
-    }
-
-    if (width < height)
-    {
-      dim = width;
-    }
-    else
-    {
-      dim = height;
-    }
-
-    return (dim * scalefactor) / (2 * maxwidth);
+    getAxisEndPoints()[0] = new Point(1f, 0f, 0f);
+    getAxisEndPoints()[1] = new Point(0f, 1f, 0f);
+    getAxisEndPoints()[2] = new Point(0f, 0f, 1f);
   }
 
   /**
-   * DOCUMENT ME!
+   * Computes and saves the min-max ranges of x/y/z positions of the sequence
+   * points
    */
-  public void findCentre()
+  protected void findWidths()
   {
-    // Find centre coordinate
-    findWidth();
-
-    centre[0] = (max[0] + min[0]) / 2;
-    centre[1] = (max[1] + min[1]) / 2;
-    centre[2] = (max[2] + min[2]) / 2;
-
-    // System.out.println("Centre x " + centre[0]);
-    // System.out.println("Centre y " + centre[1]);
-    // System.out.println("Centre z " + centre[2]);
+    float[] max = new float[DIMS];
+    float[] min = new float[DIMS];
+    
+    max[0] = -Float.MAX_VALUE;
+    max[1] = -Float.MAX_VALUE;
+    max[2] = -Float.MAX_VALUE;
+    
+    min[0] = Float.MAX_VALUE;
+    min[1] = Float.MAX_VALUE;
+    min[2] = Float.MAX_VALUE;
+    
+    for (SequencePoint sp : sequencePoints)
+    {
+      max[0] = Math.max(max[0], sp.coord.x);
+      max[1] = Math.max(max[1], sp.coord.y);
+      max[2] = Math.max(max[2], sp.coord.z);
+      min[0] = Math.min(min[0], sp.coord.x);
+      min[1] = Math.min(min[1], sp.coord.y);
+      min[2] = Math.min(min[2], sp.coord.z);
+    }
+    
+    seqMin = min;
+    seqMax = max;
   }
 
   /**
-   * DOCUMENT ME!
+   * Answers the preferred size if it has been set, else 400 x 400
    * 
-   * @return DOCUMENT ME!
+   * @return
    */
   @Override
   public Dimension getPreferredSize()
   {
-    if (prefsize != null)
+    if (prefSize != null)
     {
-      return prefsize;
+      return prefSize;
     }
     else
     {
@@ -373,9 +240,10 @@ public class RotatableCanvas extends JPanel implements MouseListener,
   }
 
   /**
-   * DOCUMENT ME!
+   * Answers the preferred size
    * 
-   * @return DOCUMENT ME!
+   * @return
+   * @see RotatableCanvas#getPreferredSize()
    */
   @Override
   public Dimension getMinimumSize()
@@ -384,10 +252,9 @@ public class RotatableCanvas extends JPanel implements MouseListener,
   }
 
   /**
-   * DOCUMENT ME!
+   * Repaints the panel
    * 
    * @param g
-   *          DOCUMENT ME!
    */
   @Override
   public void paintComponent(Graphics g1)
@@ -397,7 +264,7 @@ public class RotatableCanvas extends JPanel implements MouseListener,
 
     g.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
             RenderingHints.VALUE_ANTIALIAS_ON);
-    if (points == null)
+    if (sequencePoints == null)
     {
       g.setFont(new Font("Verdana", Font.PLAIN, 18));
       g.drawString(
@@ -406,24 +273,24 @@ public class RotatableCanvas extends JPanel implements MouseListener,
     }
     else
     {
-      // Only create the image at the beginning -
-      if ((img == null) || (prefsize.width != getWidth())
-              || (prefsize.height != getHeight()))
+      /*
+       * create the image at the beginning or after a resize
+       */
+      boolean resized = prefSize.width != getWidth()
+              || prefSize.height != getHeight();
+      if (img == null || resized)
       {
-        prefsize.width = getWidth();
-        prefsize.height = getHeight();
+        prefSize.width = getWidth();
+        prefSize.height = getHeight();
 
-        scale = findScale();
-
-        // System.out.println("New scale = " + scale);
         img = createImage(getWidth(), getHeight());
         ig = img.getGraphics();
       }
 
-      drawBackground(ig, bgColour);
+      drawBackground(ig);
       drawScene(ig);
 
-      if (drawAxes == true)
+      if (drawAxes)
       {
         drawAxes(ig);
       }
@@ -433,96 +300,110 @@ public class RotatableCanvas extends JPanel implements MouseListener,
   }
 
   /**
-   * DOCUMENT ME!
+   * Resets the rotation and choice of axes to the initial state (without change
+   * of scale factor)
+   */
+  public void resetView()
+  {
+    img = null;
+    findWidths();
+    resetAxes();
+    repaint();
+  }
+
+  /**
+   * Draws lines for the x, y, z axes
    * 
    * @param g
-   *          DOCUMENT ME!
    */
   public void drawAxes(Graphics g)
   {
+    g.setColor(AXIS_COLOUR);
 
-    g.setColor(Color.yellow);
+    int midX = getWidth() / 2;
+    int midY = getHeight() / 2;
+    float maxWidth = Math.max(Math.abs(seqMax[0] - seqMin[0]),
+            Math.abs(seqMax[1] - seqMin[1]));
+    int pix = Math.min(getWidth(), getHeight());
+    float scaleBy = pix * getScaleFactor() / (2f * maxWidth);
 
-    for (int i = 0; i < 3; i++)
+    for (int i = 0; i < DIMS; i++)
     {
-      g.drawLine(getWidth() / 2, getHeight() / 2,
-              (int) ((axes[i][0] * scale * max[0]) + (getWidth() / 2)),
-              (int) ((axes[i][1] * scale * max[1]) + (getHeight() / 2)));
+      g.drawLine(midX, midY,
+              midX + (int) (getAxisEndPoints()[i].x * scaleBy * seqMax[0]),
+              midY + (int) (getAxisEndPoints()[i].y * scaleBy * seqMax[1]));
     }
   }
 
   /**
-   * DOCUMENT ME!
+   * Fills the background with the currently configured background colour
    * 
    * @param g
-   *          DOCUMENT ME!
-   * @param col
-   *          DOCUMENT ME!
    */
-  public void drawBackground(Graphics g, Color col)
+  public void drawBackground(Graphics g)
   {
-    g.setColor(col);
-    g.fillRect(0, 0, prefsize.width, prefsize.height);
+    g.setColor(getBgColour());
+    g.fillRect(0, 0, prefSize.width, prefSize.height);
   }
 
   /**
-   * DOCUMENT ME!
+   * Draws points (6x6 squares) for the sequences of the PCA, and labels
+   * (sequence names) if configured to do so. The sequence points colours are
+   * taken from the sequence ids in the alignment (converting black to white).
+   * Sequences 'at the back' (z-coordinate is negative) are shaded slightly
+   * darker to help give a 3-D sensation.
    * 
    * @param g
-   *          DOCUMENT ME!
    */
   public void drawScene(Graphics g1)
   {
-
     Graphics2D g = (Graphics2D) g1;
 
     g.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
             RenderingHints.VALUE_ANTIALIAS_ON);
+    int pix = Math.min(getWidth(), getHeight());
+    float xWidth = Math.abs(seqMax[0] - seqMin[0]);
+    float yWidth = Math.abs(seqMax[1] - seqMin[1]);
+    float maxWidth = Math.max(xWidth, yWidth);
+    float scaleBy = pix * getScaleFactor() / (2f * maxWidth);
 
-    int halfwidth = getWidth() / 2;
-    int halfheight = getHeight() / 2;
+    float[] centre = getCentre();
 
     for (int i = 0; i < npoint; i++)
     {
-      SequencePoint sp = (SequencePoint) points.elementAt(i);
-      int x = (int) ((sp.coord[0] - centre[0]) * scale) + halfwidth;
-      int y = (int) ((sp.coord[1] - centre[1]) * scale)
-              + halfheight;
-      float z = sp.coord[1] - centre[2];
-
-      if (av.getSequenceColour(sp.sequence) == Color.black)
-      {
-        g.setColor(Color.white);
-      }
-      else
-      {
-        g.setColor(av.getSequenceColour(sp.sequence));
-      }
-
-      if (av.getSelectionGroup() != null)
-      {
-        if (av.getSelectionGroup().getSequences(null)
-                .contains(((SequencePoint) points.elementAt(i)).sequence))
-        {
-          g.setColor(Color.gray);
-        }
-      }
+      /*
+       * sequence point colour as sequence id, but
+       * gray if sequence is currently selected
+       */
+      SequencePoint sp = sequencePoints.get(i);
+      Color sequenceColour = getSequencePointColour(sp);
+      g.setColor(sequenceColour);
+
+      int halfwidth = getWidth() / 2;
+      int halfheight = getHeight() / 2;
+      int x = (int) ((sp.coord.x - centre[0]) * scaleBy) + halfwidth;
+      int y = (int) ((sp.coord.y - centre[1]) * scaleBy) + halfheight;
+      g.fillRect(x - 3, y - 3, 6, 6);
 
-      if (z < 0)
+      if (isShowLabels())
       {
-        g.setColor(g.getColor().darker());
+        g.setColor(Color.red);
+        g.drawString(sp.getSequence().getName(), x - 3, y - 4);
       }
-
-      g.fillRect(x - 3, y - 3, 6, 6);
-      if (showLabels)
+    }
+    if (isShowLabels())
+    {
+      g.setColor(AXIS_COLOUR);
+      int midX = getWidth() / 2;
+      int midY = getHeight() / 2;
+      Iterator<String> axes = AXES.iterator();
+      for (Point p : getAxisEndPoints())
       {
-        g.setColor(Color.red);
-        g.drawString(
-                ((SequencePoint) points.elementAt(i)).sequence.getName(),
-                x - 3, y - 4);
+        int x = midX + (int) (p.x * scaleBy * seqMax[0]);
+        int y = midY + (int) (p.y * scaleBy * seqMax[1]);
+        g.drawString(axes.next(), x - 3, y - 4);
       }
     }
-
     // //Now the rectangle
     // if (rectx2 != -1 && recty2 != -1) {
     // g.setColor(Color.white);
@@ -532,128 +413,147 @@ public class RotatableCanvas extends JPanel implements MouseListener,
   }
 
   /**
-   * DOCUMENT ME!
+   * Determines the colour to use when drawing a sequence point. The colour is
+   * taken from the sequence id, with black converted to white, and then
+   * graduated from darker (at the back) to brighter (at the front) based on the
+   * z-axis coordinate of the point.
    * 
-   * @return DOCUMENT ME!
+   * @param sp
+   * @return
    */
-  public Dimension minimumsize()
+  protected Color getSequencePointColour(SequencePoint sp)
   {
-    return prefsize;
-  }
+    SequenceI sequence = sp.getSequence();
+    Color sequenceColour = av.getSequenceColour(sequence);
+    if (sequenceColour == Color.black)
+    {
+      sequenceColour = Color.white;
+    }
+    if (av.getSelectionGroup() != null)
+    {
+      if (av.getSelectionGroup().getSequences(null).contains(sequence))
+      {
+        sequenceColour = Color.gray;
+      }
+    }
 
-  /**
-   * DOCUMENT ME!
-   * 
-   * @return DOCUMENT ME!
-   */
-  public Dimension preferredsize()
-  {
-    return prefsize;
+    /*
+     * graduate brighter for point in front of centre, darker if behind centre
+     */
+    float zCentre = (seqMin[2] + seqMax[2]) / 2f;
+    if (sp.coord.z > zCentre)
+    {
+      sequenceColour = ColorUtils.getGraduatedColour(sp.coord.z, 0,
+              sequenceColour, seqMax[2], sequenceColour.brighter());
+    }
+    else if (sp.coord.z < zCentre)
+    {
+      sequenceColour = ColorUtils.getGraduatedColour(sp.coord.z, seqMin[2],
+              sequenceColour.darker(), 0, sequenceColour);
+    }
+
+    return sequenceColour;
   }
 
-  /**
-   * DOCUMENT ME!
-   * 
-   * @param evt
-   *          DOCUMENT ME!
-   */
   @Override
   public void keyTyped(KeyEvent evt)
   {
   }
 
-  /**
-   * DOCUMENT ME!
-   * 
-   * @param evt
-   *          DOCUMENT ME!
-   */
   @Override
   public void keyReleased(KeyEvent evt)
   {
   }
 
   /**
-   * DOCUMENT ME!
+   * Responds to up or down arrow key by zooming in or out, respectively
    * 
    * @param evt
-   *          DOCUMENT ME!
    */
   @Override
   public void keyPressed(KeyEvent evt)
   {
-    if (evt.getKeyCode() == KeyEvent.VK_UP)
+    int keyCode = evt.getKeyCode();
+    boolean shiftDown = evt.isShiftDown();
+
+    if (keyCode == KeyEvent.VK_UP)
+    {
+      if (shiftDown)
+      {
+        rotate(0f, -1f);
+      }
+      else
+      {
+        zoom(ZOOM_IN);
+      }
+    }
+    else if (keyCode == KeyEvent.VK_DOWN)
+    {
+      if (shiftDown)
+      {
+        rotate(0f, 1f);
+      }
+      else
+      {
+        zoom(ZOOM_OUT);
+      }
+    }
+    else if (shiftDown && keyCode == KeyEvent.VK_LEFT)
     {
-      scalefactor = (float) (scalefactor * 1.1);
-      scale = findScale();
+      rotate(1f, 0f);
     }
-    else if (evt.getKeyCode() == KeyEvent.VK_DOWN)
+    else if (shiftDown && keyCode == KeyEvent.VK_RIGHT)
     {
-      scalefactor = (float) (scalefactor * 0.9);
-      scale = findScale();
+      rotate(-1f, 0f);
     }
     else if (evt.getKeyChar() == 's')
     {
-      System.err.println("DEBUG: Rectangle selection"); // log.debug
-
-      if ((rectx2 != -1) && (recty2 != -1))
-      {
-        rectSelect(rectx1, recty1, rectx2, recty2);
-      }
+      // Cache.log.warn("DEBUG: Rectangle selection");
+      // todo not yet enabled as rectx2, recty2 are always -1
+      // need to set them in mouseDragged; JAL-1124
+      // if ((rectx2 != -1) && (recty2 != -1))
+      // {
+      // rectSelect(rectx1, recty1, rectx2, recty2);
+      // }
     }
 
     repaint();
   }
 
-  /**
-   * DOCUMENT ME!
-   * 
-   * @param evt
-   *          DOCUMENT ME!
-   */
+  @Override
+  public void zoom(float factor)
+  {
+    if (factor > 0f)
+    {
+      setScaleFactor(getScaleFactor() * factor);
+    }
+  }
+
   @Override
   public void mouseClicked(MouseEvent evt)
   {
   }
 
-  /**
-   * DOCUMENT ME!
-   * 
-   * @param evt
-   *          DOCUMENT ME!
-   */
   @Override
   public void mouseEntered(MouseEvent evt)
   {
   }
 
-  /**
-   * DOCUMENT ME!
-   * 
-   * @param evt
-   *          DOCUMENT ME!
-   */
   @Override
   public void mouseExited(MouseEvent evt)
   {
   }
 
-  /**
-   * DOCUMENT ME!
-   * 
-   * @param evt
-   *          DOCUMENT ME!
-   */
   @Override
   public void mouseReleased(MouseEvent evt)
   {
   }
 
   /**
-   * DOCUMENT ME!
-   * 
-   * @param evt
-   *          DOCUMENT ME!
+   * If the mouse press is at (within 2 pixels of) a sequence point, toggles
+   * (adds or removes) the corresponding sequence as a member of the viewport
+   * selection group. This supports configuring a group in the alignment by
+   * clicking on points in the PCA display.
    */
   @Override
   public void mousePressed(MouseEvent evt)
@@ -661,22 +561,15 @@ public class RotatableCanvas extends JPanel implements MouseListener,
     int x = evt.getX();
     int y = evt.getY();
 
-    mx = x;
-    my = y;
-
-    omx = mx;
-    omy = my;
-
-    startx = x;
-    starty = y;
+    mouseX = x;
+    mouseY = y;
 
-    rectx1 = x;
-    recty1 = y;
+    // rectx1 = x;
+    // recty1 = y;
+    // rectx2 = -1;
+    // recty2 = -1;
 
-    rectx2 = -1;
-    recty2 = -1;
-
-    SequenceI found = findPoint(x, y);
+    SequenceI found = findSequenceAtPoint(x, y);
 
     if (found != null)
     {
@@ -704,36 +597,37 @@ public class RotatableCanvas extends JPanel implements MouseListener,
     repaint();
   }
 
-  // private void fireSequenceSelectionEvent(Selection sel) {
-  // controller.handleSequenceSelectionEvent(new
-  // SequenceSelectionEvent(this,sel));
-  // }
+  /**
+   * Sets the tooltip to the name of the sequence within 2 pixels of the mouse
+   * position, or clears the tooltip if none found
+   */
   @Override
   public void mouseMoved(MouseEvent evt)
   {
-    SequenceI found = findPoint(evt.getX(), evt.getY());
+    SequenceI found = findSequenceAtPoint(evt.getX(), evt.getY());
 
-    if (found != null)
-    {
-      this.setToolTipText(found.getName());
-    }
-    else
-    {
-      this.setToolTipText(null);
-    }
+    this.setToolTipText(found == null ? null : found.getName());
   }
 
   /**
-   * DOCUMENT ME!
+   * Action handler for a mouse drag. Rotates the display around the X axis (for
+   * up/down mouse movement) and/or the Y axis (for left/right mouse movement).
    * 
    * @param evt
-   *          DOCUMENT ME!
    */
   @Override
   public void mouseDragged(MouseEvent evt)
   {
-    mx = evt.getX();
-    my = evt.getY();
+    int xPos = evt.getX();
+    int yPos = evt.getY();
+
+    if (xPos == mouseX && yPos == mouseY)
+    {
+      return;
+    }
+
+    int xDelta = xPos - mouseX;
+    int yDelta = yPos - mouseY;
 
     // Check if this is a rectangle drawing drag
     if ((evt.getModifiers() & InputEvent.BUTTON2_MASK) != 0)
@@ -743,113 +637,178 @@ public class RotatableCanvas extends JPanel implements MouseListener,
     }
     else
     {
-      rotmat.setIdentity();
+      rotate(xDelta, yDelta);
 
-      rotmat.rotate(my - omy, 'x');
-      rotmat.rotate(mx - omx, 'y');
+      mouseX = xPos;
+      mouseY = yPos;
 
-      for (int i = 0; i < npoint; i++)
-      {
-        SequencePoint sp = (SequencePoint) points.elementAt(i);
-        sp.coord[0] -= centre[0];
-        sp.coord[1] -= centre[1];
-        sp.coord[2] -= centre[2];
-
-        // Now apply the rotation matrix
-        sp.coord = rotmat.vectorMultiply(sp.coord);
-
-        // Now translate back again
-        sp.coord[0] += centre[0];
-        sp.coord[1] += centre[1];
-        sp.coord[2] += centre[2];
-      }
+      // findWidths();
 
-      for (int i = 0; i < 3; i++)
-      {
-        axes[i] = rotmat.vectorMultiply(axes[i]);
-      }
+      repaint();
+    }
+  }
+
+  @Override
+  public void rotate(float x, float y)
+  {
+    if (x == 0f && y == 0f)
+    {
+      return;
+    }
+
+    /*
+     * get the identity transformation...
+     */
+    RotatableMatrix rotmat = new RotatableMatrix();
+
+    /*
+     * rotate around the X axis for change in Y
+     * (mouse movement up/down); note we are equating a
+     * number of pixels with degrees of rotation here!
+     */
+    if (y != 0)
+    {
+      rotmat.rotate(y, Axis.X);
+    }
+
+    /*
+     * rotate around the Y axis for change in X
+     * (mouse movement left/right)
+     */
+    if (x != 0)
+    {
+      rotmat.rotate(x, Axis.Y);
+    }
+
+    /*
+     * apply the composite transformation to sequence points;
+     * update z min-max range (affects colour graduation), but not
+     * x or y min-max (as this would affect axis scaling)
+     */
+    float[] centre = getCentre();
+    float zMin = Float.MAX_VALUE;
+    float zMax = -Float.MAX_VALUE;
+
+    for (int i = 0; i < npoint; i++)
+    {
+      SequencePoint sp = sequencePoints.get(i);
+      sp.translate(-centre[0], -centre[1], -centre[2]);
+
+      // Now apply the rotation matrix
+      sp.coord = rotmat.vectorMultiply(sp.coord);
+
+      // Now translate back again
+      sp.translate(centre[0], centre[1], centre[2]);
+      
+      zMin = Math.min(zMin, sp.coord.z);
+      zMax = Math.max(zMax, sp.coord.z);
+    }
 
-      omx = mx;
-      omy = my;
+    seqMin[2] = zMin;
+    seqMax[2] = zMax;
 
-      paint(this.getGraphics());
+    /*
+     * rotate the x/y/z axis positions
+     */
+    for (int i = 0; i < DIMS; i++)
+    {
+      getAxisEndPoints()[i] = rotmat.vectorMultiply(getAxisEndPoints()[i]);
     }
   }
 
   /**
-   * DOCUMENT ME!
+   * Answers the x/y/z coordinates that are midway between the maximum and
+   * minimum sequence point values
+   * 
+   * @return
+   */
+  private float[] getCentre()
+  {
+    float xCentre = (seqMin[0] + seqMax[0]) / 2f;
+    float yCentre = (seqMin[1] + seqMax[1]) / 2f;
+    float zCentre = (seqMin[2] + seqMax[2]) / 2f;
+
+    return new float[] { xCentre, yCentre, zCentre };
+  }
+
+  /**
+   * Adds any sequences whose displayed points are within the given rectangle to
+   * the viewport's current selection. Intended for key 's' after dragging to
+   * select a region of the PCA.
    * 
    * @param x1
-   *          DOCUMENT ME!
    * @param y1
-   *          DOCUMENT ME!
    * @param x2
-   *          DOCUMENT ME!
    * @param y2
-   *          DOCUMENT ME!
    */
-  public void rectSelect(int x1, int y1, int x2, int y2)
+  protected void rectSelect(int x1, int y1, int x2, int y2)
   {
+    float[] centre = getCentre();
+
     for (int i = 0; i < npoint; i++)
     {
-      SequencePoint sp = (SequencePoint) points.elementAt(i);
-      int tmp1 = (int) (((sp.coord[0] - centre[0]) * scale)
+      SequencePoint sp = sequencePoints.get(i);
+      int tmp1 = (int) (((sp.coord.x - centre[0]) * getScaleFactor())
               + (getWidth() / 2.0));
-      int tmp2 = (int) (((sp.coord[1] - centre[1]) * scale)
+      int tmp2 = (int) (((sp.coord.y - centre[1]) * getScaleFactor())
               + (getHeight() / 2.0));
 
       if ((tmp1 > x1) && (tmp1 < x2) && (tmp2 > y1) && (tmp2 < y2))
       {
         if (av != null)
         {
+          SequenceI sequence = sp.getSequence();
           if (!av.getSelectionGroup().getSequences(null)
-                  .contains(sp.sequence))
+                  .contains(sequence))
           {
-            av.getSelectionGroup().addSequence(sp.sequence, true);
+            av.getSelectionGroup().addSequence(sequence, true);
           }
         }
       }
     }
-
-    // if (changedSel) {
-    // fireSequenceSelectionEvent(av.getSelection());
-    // }
   }
 
   /**
-   * DOCUMENT ME!
+   * Answers the first sequence found whose point on the display is within 2
+   * pixels of the given coordinates, or null if none is found
    * 
    * @param x
-   *          DOCUMENT ME!
    * @param y
-   *          DOCUMENT ME!
    * 
-   * @return DOCUMENT ME!
+   * @return
    */
-  public SequenceI findPoint(int x, int y)
+  protected SequenceI findSequenceAtPoint(int x, int y)
   {
     int halfwidth = getWidth() / 2;
     int halfheight = getHeight() / 2;
 
     int found = -1;
+    int pix = Math.min(getWidth(), getHeight());
+    float xWidth = Math.abs(seqMax[0] - seqMin[0]);
+    float yWidth = Math.abs(seqMax[1] - seqMin[1]);
+    float maxWidth = Math.max(xWidth, yWidth);
+    float scaleBy = pix * getScaleFactor() / (2f * maxWidth);
+
+    float[] centre = getCentre();
 
     for (int i = 0; i < npoint; i++)
     {
-      SequencePoint sp = (SequencePoint) points.elementAt(i);
-      int px = (int) ((sp.coord[0] - centre[0]) * scale)
+      SequencePoint sp = sequencePoints.get(i);
+      int px = (int) ((sp.coord.x - centre[0]) * scaleBy)
               + halfwidth;
-      int py = (int) ((sp.coord[1] - centre[1]) * scale)
+      int py = (int) ((sp.coord.y - centre[1]) * scaleBy)
               + halfheight;
 
-      if ((Math.abs(px - x) < 3) && (Math.abs(py - y) < 3))
+      if ((Math.abs(px - x) < NEARBY) && (Math.abs(py - y) < NEARBY))
       {
         found = i;
+        break;
       }
     }
 
     if (found != -1)
     {
-      return ((SequencePoint) points.elementAt(found)).sequence;
+      return sequencePoints.get(found).getSequence();
     }
     else
     {
@@ -857,9 +816,15 @@ public class RotatableCanvas extends JPanel implements MouseListener,
     }
   }
 
+  /**
+   * Answers the panel the PCA is associated with (all panels for this alignment
+   * if 'associate with all panels' is selected).
+   * 
+   * @return
+   */
   AlignmentPanel[] getAssociatedPanels()
   {
-    if (applyToAllViews)
+    if (isApplyToAllViews())
     {
       return PaintRefresher.getAssociatedPanels(av.getSequenceSetId());
     }
@@ -869,19 +834,114 @@ public class RotatableCanvas extends JPanel implements MouseListener,
     }
   }
 
+  public Color getBackgroundColour()
+  {
+    return getBgColour();
+  }
+
+  /**
+   * Zooms in or out in response to mouse wheel movement
+   */
+  @Override
+  public void mouseWheelMoved(MouseWheelEvent e)
+  {
+    double wheelRotation = e.getPreciseWheelRotation();
+    if (wheelRotation > 0)
+    {
+      zoom(ZOOM_IN);
+      repaint();
+    }
+    else if (wheelRotation < 0)
+    {
+      zoom(ZOOM_OUT);
+      repaint();
+    }
+  }
+
+  /**
+   * Answers the sequence point minimum [x, y, z] values. Note these are derived
+   * when sequence points are set, but x and y values are not updated on
+   * rotation (because this would result in changes to scaling).
+   * 
+   * @return
+   */
+  public float[] getSeqMin()
+  {
+    return seqMin;
+  }
+
+  /**
+   * Answers the sequence point maximum [x, y, z] values. Note these are derived
+   * when sequence points are set, but x and y values are not updated on
+   * rotation (because this would result in changes to scaling).
+   * 
+   * @return
+   */
+  public float[] getSeqMax()
+  {
+    return seqMax;
+  }
+
   /**
+   * Sets the minimum and maximum [x, y, z] positions for sequence points. For
+   * use when restoring a saved PCA from state data.
    * 
-   * @return x,y,z positions of point s (index into points) under current
-   *         transform.
+   * @param min
+   * @param max
    */
-  public double[] getPointPosition(int s)
+  public void setSeqMinMax(float[] min, float[] max)
+  {
+    seqMin = min;
+    seqMax = max;
+  }
+
+  public float getScaleFactor()
+  {
+    return scaleFactor;
+  }
+
+  public void setScaleFactor(float scaleFactor)
+  {
+    this.scaleFactor = scaleFactor;
+  }
+
+  public boolean isShowLabels()
   {
-    double pts[] = new double[3];
-    float[] p = ((SequencePoint) points.elementAt(s)).coord;
-    pts[0] = p[0];
-    pts[1] = p[1];
-    pts[2] = p[2];
-    return pts;
+    return showLabels;
   }
 
+  public void setShowLabels(boolean showLabels)
+  {
+    this.showLabels = showLabels;
+  }
+
+  public boolean isApplyToAllViews()
+  {
+    return applyToAllViews;
+  }
+
+  public void setApplyToAllViews(boolean applyToAllViews)
+  {
+    this.applyToAllViews = applyToAllViews;
+  }
+
+  public Point[] getAxisEndPoints()
+  {
+    return axisEndPoints;
+  }
+
+  public void setAxisEndPoints(Point[] axisEndPoints)
+  {
+    this.axisEndPoints = axisEndPoints;
+  }
+
+  public Color getBgColour()
+  {
+    return bgColour;
+  }
+
+  public void setBgColour(Color bgColour)
+  {
+    this.bgColour = bgColour;
+  }
 }
index e6bba02..6abee08 100755 (executable)
@@ -276,7 +276,9 @@ public class ScalePanel extends JPanel
   {
     mouseDragging = false;
 
-    int res = (evt.getX() / av.getCharWidth())
+    int xCords = Math.max(0, evt.getX()); // prevent negative X coordinates
+
+    int res = (xCords / av.getCharWidth())
             + av.getRanges().getStartRes();
 
     if (av.hasHiddenColumns())
index 45def89..c195c80 100755 (executable)
@@ -1160,4 +1160,14 @@ public class TreeCanvas extends JPanel implements MouseListener, Runnable,
   {
     this.threshold = threshold;
   }
+
+  public boolean isApplyToAllViews()
+  {
+    return this.applyToAllViews;
+  }
+
+  public void setApplyToAllViews(boolean applyToAllViews)
+  {
+    this.applyToAllViews = applyToAllViews;
+  }
 }
index 084f461..ca4f84e 100755 (executable)
@@ -879,7 +879,7 @@ public class TreePanel extends GTreePanel
     /*
      * put them together as <method> Using <model>
      */
-    final String ttl = MessageManager.formatMessage("label.treecalc_title",
+    final String ttl = MessageManager.formatMessage("label.calc_title",
             treecalcnm, smn);
     return ttl;
   }
index a183794..122ad0f 100755 (executable)
@@ -46,13 +46,11 @@ public class GPCAPanel extends JInternalFrame
 {
   private static final Font VERDANA_12 = new Font("Verdana", 0, 12);
 
-  protected JComboBox<String> xCombobox = new JComboBox<String>();
+  protected JComboBox<String> xCombobox = new JComboBox<>();
 
-  protected JComboBox<String> yCombobox = new JComboBox<String>();
+  protected JComboBox<String> yCombobox = new JComboBox<>();
 
-  protected JComboBox<String> zCombobox = new JComboBox<String>();
-
-  protected JMenu scoreModelMenu = new JMenu();
+  protected JComboBox<String> zCombobox = new JComboBox<>();
 
   protected JMenu viewMenu = new JMenu();
 
@@ -60,16 +58,15 @@ public class GPCAPanel extends JInternalFrame
 
   protected JMenu associateViewsMenu = new JMenu();
 
-  protected JMenu calcSettings = new JMenu();
-
-  protected JCheckBoxMenuItem nuclSetting = new JCheckBoxMenuItem();
-
-  protected JCheckBoxMenuItem protSetting = new JCheckBoxMenuItem();
-
   protected JLabel statusBar = new JLabel();
 
   protected JPanel statusPanel = new JPanel();
 
+  protected JMenuItem originalSeqData;
+
+  /**
+   * Constructor
+   */
   public GPCAPanel()
   {
     try
@@ -110,7 +107,7 @@ public class GPCAPanel extends JInternalFrame
       @Override
       public void actionPerformed(ActionEvent e)
       {
-        zCombobox_actionPerformed(e);
+        doDimensionChange();
       }
     });
     yCombobox.setFont(VERDANA_12);
@@ -119,7 +116,7 @@ public class GPCAPanel extends JInternalFrame
       @Override
       public void actionPerformed(ActionEvent e)
       {
-        yCombobox_actionPerformed(e);
+        doDimensionChange();
       }
     });
     xCombobox.setFont(VERDANA_12);
@@ -128,7 +125,7 @@ public class GPCAPanel extends JInternalFrame
       @Override
       public void actionPerformed(ActionEvent e)
       {
-        xCombobox_actionPerformed(e);
+        doDimensionChange();
       }
     });
     JButton resetButton = new JButton();
@@ -139,7 +136,7 @@ public class GPCAPanel extends JInternalFrame
       @Override
       public void actionPerformed(ActionEvent e)
       {
-        resetButton_actionPerformed(e);
+        resetButton_actionPerformed();
       }
     });
     JMenu fileMenu = new JMenu();
@@ -152,7 +149,7 @@ public class GPCAPanel extends JInternalFrame
       @Override
       public void actionPerformed(ActionEvent e)
       {
-        eps_actionPerformed(e);
+        eps_actionPerformed();
       }
     });
     JMenuItem png = new JMenuItem("PNG");
@@ -161,7 +158,7 @@ public class GPCAPanel extends JInternalFrame
       @Override
       public void actionPerformed(ActionEvent e)
       {
-        png_actionPerformed(e);
+        png_actionPerformed();
       }
     });
     JMenuItem outputValues = new JMenuItem();
@@ -171,7 +168,7 @@ public class GPCAPanel extends JInternalFrame
       @Override
       public void actionPerformed(ActionEvent e)
       {
-        outputValues_actionPerformed(e);
+        outputValues_actionPerformed();
       }
     });
     JMenuItem outputPoints = new JMenuItem();
@@ -181,7 +178,7 @@ public class GPCAPanel extends JInternalFrame
       @Override
       public void actionPerformed(ActionEvent e)
       {
-        outputPoints_actionPerformed(e);
+        outputPoints_actionPerformed();
       }
     });
     JMenuItem outputProjPoints = new JMenuItem();
@@ -192,7 +189,7 @@ public class GPCAPanel extends JInternalFrame
       @Override
       public void actionPerformed(ActionEvent e)
       {
-        outputProjPoints_actionPerformed(e);
+        outputProjPoints_actionPerformed();
       }
     });
     JMenuItem print = new JMenuItem();
@@ -202,7 +199,7 @@ public class GPCAPanel extends JInternalFrame
       @Override
       public void actionPerformed(ActionEvent e)
       {
-        print_actionPerformed(e);
+        print_actionPerformed();
       }
     });
     viewMenu.setText(MessageManager.getString("action.view"));
@@ -224,33 +221,13 @@ public class GPCAPanel extends JInternalFrame
       {
       }
     });
-    scoreModelMenu
-            .setText(MessageManager.getString("label.select_score_model"));
-    scoreModelMenu.addMenuListener(new MenuListener()
-    {
-      @Override
-      public void menuSelected(MenuEvent e)
-      {
-        scoreModel_menuSelected();
-      }
-
-      @Override
-      public void menuDeselected(MenuEvent e)
-      {
-      }
-
-      @Override
-      public void menuCanceled(MenuEvent e)
-      {
-      }
-    });
     showLabels.setText(MessageManager.getString("label.show_labels"));
     showLabels.addActionListener(new ActionListener()
     {
       @Override
       public void actionPerformed(ActionEvent e)
       {
-        showLabels_actionPerformed(e);
+        showLabels_actionPerformed();
       }
     });
     JMenuItem bgcolour = new JMenuItem();
@@ -260,47 +237,22 @@ public class GPCAPanel extends JInternalFrame
       @Override
       public void actionPerformed(ActionEvent e)
       {
-        bgcolour_actionPerformed(e);
+        bgcolour_actionPerformed();
       }
     });
-    JMenuItem originalSeqData = new JMenuItem();
+    originalSeqData = new JMenuItem();
     originalSeqData.setText(MessageManager.getString("label.input_data"));
     originalSeqData.addActionListener(new ActionListener()
     {
       @Override
       public void actionPerformed(ActionEvent e)
       {
-        originalSeqData_actionPerformed(e);
+        originalSeqData_actionPerformed();
       }
     });
     associateViewsMenu.setText(
             MessageManager.getString("label.associate_nodes_with"));
-    calcSettings.setText(MessageManager.getString("action.change_params"));
-    nuclSetting
-            .setText(MessageManager.getString("label.nucleotide_matrix"));
-    protSetting.setText(MessageManager.getString("label.protein_matrix"));
-    nuclSetting.addActionListener(new ActionListener()
-    {
-
-      @Override
-      public void actionPerformed(ActionEvent arg0)
-      {
-        nuclSetting_actionPerfomed(arg0);
-      }
-    });
-    protSetting.addActionListener(new ActionListener()
-    {
-
-      @Override
-      public void actionPerformed(ActionEvent arg0)
-      {
-        protSetting_actionPerfomed(arg0);
-      }
-    });
 
-    calcSettings.add(nuclSetting);
-    calcSettings.add(protSetting);
-    calcSettings.add(scoreModelMenu);
     statusPanel.setLayout(new GridLayout());
     statusBar.setFont(VERDANA_12);
     // statusPanel.setBackground(Color.lightGray);
@@ -321,7 +273,6 @@ public class GPCAPanel extends JInternalFrame
     JMenuBar jMenuBar1 = new JMenuBar();
     jMenuBar1.add(fileMenu);
     jMenuBar1.add(viewMenu);
-    jMenuBar1.add(calcSettings);
     setJMenuBar(jMenuBar1);
     fileMenu.add(saveMenu);
     fileMenu.add(outputValues);
@@ -336,91 +287,51 @@ public class GPCAPanel extends JInternalFrame
     viewMenu.add(associateViewsMenu);
   }
 
-  protected void scoreModel_menuSelected()
-  {
-    // TODO Auto-generated method stub
-
-  }
-
-  protected void resetButton_actionPerformed(ActionEvent e)
+  protected void resetButton_actionPerformed()
   {
-    // TODO Auto-generated method stub
-
   }
 
-  protected void protSetting_actionPerfomed(ActionEvent arg0)
+  protected void outputPoints_actionPerformed()
   {
-    // TODO Auto-generated method stub
-
   }
 
-  protected void nuclSetting_actionPerfomed(ActionEvent arg0)
+  protected void outputProjPoints_actionPerformed()
   {
-    // TODO Auto-generated method stub
-
   }
 
-  protected void outputPoints_actionPerformed(ActionEvent e)
+  protected void eps_actionPerformed()
   {
-    // TODO Auto-generated method stub
-
   }
 
-  protected void outputProjPoints_actionPerformed(ActionEvent e)
+  protected void png_actionPerformed()
   {
-    // TODO Auto-generated method stub
-
   }
 
-  protected void xCombobox_actionPerformed(ActionEvent e)
+  protected void outputValues_actionPerformed()
   {
   }
 
-  protected void yCombobox_actionPerformed(ActionEvent e)
+  protected void print_actionPerformed()
   {
   }
 
-  protected void zCombobox_actionPerformed(ActionEvent e)
+  protected void showLabels_actionPerformed()
   {
   }
 
-  public void eps_actionPerformed(ActionEvent e)
+  protected void bgcolour_actionPerformed()
   {
-
   }
 
-  public void png_actionPerformed(ActionEvent e)
+  protected void originalSeqData_actionPerformed()
   {
-
   }
 
-  public void outputValues_actionPerformed(ActionEvent e)
+  protected void viewMenu_menuSelected()
   {
-
   }
 
-  public void print_actionPerformed(ActionEvent e)
+  protected void doDimensionChange()
   {
-
-  }
-
-  public void showLabels_actionPerformed(ActionEvent e)
-  {
-
-  }
-
-  public void bgcolour_actionPerformed(ActionEvent e)
-  {
-
-  }
-
-  public void originalSeqData_actionPerformed(ActionEvent e)
-  {
-
-  }
-
-  public void viewMenu_menuSelected()
-  {
-
   }
 }
index 8910c67..77862c8 100755 (executable)
@@ -24,6 +24,7 @@ import jalview.util.Format;
 import jalview.util.MessageManager;
 
 import java.io.PrintStream;
+import java.util.Arrays;
 
 /**
  * A class to model rectangular matrices of double values and operations on them
@@ -31,37 +32,40 @@ import java.io.PrintStream;
 public class Matrix implements MatrixI
 {
   /*
-   * the cell values in row-major order
+   * maximum number of iterations for tqli
    */
-  private double[][] value;
+  private static final int MAX_ITER = 45;
+  // fudge - add 15 iterations, just in case
 
   /*
    * the number of rows
    */
-  protected int rows;
+  final protected int rows;
 
   /*
    * the number of columns
    */
-  protected int cols;
+  final protected int cols;
+
+  /*
+   * the cell values in row-major order
+   */
+  private double[][] value;
 
   protected double[] d; // Diagonal
 
   protected double[] e; // off diagonal
 
   /**
-   * maximum number of iterations for tqli
+   * Constructor given number of rows and columns
    * 
+   * @param colCount
+   * @param rowCount
    */
-  private static final int maxIter = 45; // fudge - add 15 iterations, just in
-                                         // case
-
-  /**
-   * Default constructor
-   */
-  public Matrix()
+  protected Matrix(int rowCount, int colCount)
   {
-
+    rows = rowCount;
+    cols = colCount;
   }
 
   /**
@@ -103,11 +107,6 @@ public class Matrix implements MatrixI
     }
   }
 
-  /**
-   * Returns a new matrix which is the transpose of this one
-   * 
-   * @return
-   */
   @Override
   public MatrixI transpose()
   {
@@ -145,18 +144,6 @@ public class Matrix implements MatrixI
     }
   }
 
-  /**
-   * Returns a new matrix which is the result of premultiplying this matrix by
-   * the supplied argument. If this of size AxB (A rows and B columns), and the
-   * argument is CxA (C rows and A columns), the result is of size CxB.
-   * 
-   * @param in
-   * 
-   * @return
-   * @throws IllegalArgumentException
-   *           if the number of columns in the pre-multiplier is not equal to
-   *           the number of rows in the multiplicand (this)
-   */
   @Override
   public MatrixI preMultiply(MatrixI in)
   {
@@ -208,21 +195,6 @@ public class Matrix implements MatrixI
     return out;
   }
 
-  /**
-   * Returns a new matrix which is the result of postmultiplying this matrix by
-   * the supplied argument. If this of size AxB (A rows and B columns), and the
-   * argument is BxC (B rows and C columns), the result is of size AxC.
-   * <p>
-   * This method simply returns the result of in.preMultiply(this)
-   * 
-   * @param in
-   * 
-   * @return
-   * @throws IllegalArgumentException
-   *           if the number of rows in the post-multiplier is not equal to the
-   *           number of columns in the multiplicand (this)
-   * @see #preMultiply(Matrix)
-   */
   @Override
   public MatrixI postMultiply(MatrixI in)
   {
@@ -234,11 +206,6 @@ public class Matrix implements MatrixI
     return in.preMultiply(this);
   }
 
-  /**
-   * Answers a new matrix with a copy of the values in this one
-   * 
-   * @return
-   */
   @Override
   public MatrixI copy()
   {
@@ -249,7 +216,17 @@ public class Matrix implements MatrixI
       System.arraycopy(value[i], 0, newmat[i], 0, value[i].length);
     }
 
-    return new Matrix(newmat);
+    Matrix m = new Matrix(newmat);
+    if (this.d != null)
+    {
+      m.d = Arrays.copyOf(this.d, this.d.length);
+    }
+    if (this.e != null)
+    {
+      m.e = Arrays.copyOf(this.e, this.e.length);
+    }
+
+    return m;
   }
 
   /**
@@ -479,11 +456,11 @@ public class Matrix implements MatrixI
         {
           iter++;
 
-          if (iter == maxIter)
+          if (iter == MAX_ITER)
           {
             throw new Exception(MessageManager.formatMessage(
                     "exception.matrix_too_many_iteration", new String[]
-                    { "tqli", Integer.valueOf(maxIter).toString() }));
+                    { "tqli", Integer.valueOf(MAX_ITER).toString() }));
           }
           else
           {
@@ -743,11 +720,11 @@ public class Matrix implements MatrixI
         {
           iter++;
 
-          if (iter == maxIter)
+          if (iter == MAX_ITER)
           {
             throw new Exception(MessageManager.formatMessage(
                     "exception.matrix_too_many_iteration", new String[]
-                    { "tqli2", Integer.valueOf(maxIter).toString() }));
+                    { "tqli2", Integer.valueOf(MAX_ITER).toString() }));
           }
           else
           {
@@ -995,4 +972,16 @@ public class Matrix implements MatrixI
       }
     }
   }
+
+  @Override
+  public void setD(double[] v)
+  {
+    d = v;
+  }
+
+  @Override
+  public void setE(double[] v)
+  {
+    e = v;
+  }
 }
index 5b93c76..d72890a 100644 (file)
@@ -22,6 +22,10 @@ package jalview.math;
 
 import java.io.PrintStream;
 
+/**
+ * An interface that describes a rectangular matrix of double values and
+ * operations on it
+ */
 public interface MatrixI
 {
   /**
@@ -63,18 +67,59 @@ public interface MatrixI
    */
   double[] getRow(int i);
 
+  /**
+   * Answers a new matrix with a copy of the values in this one
+   * 
+   * @return
+   */
   MatrixI copy();
 
+  /**
+   * Returns a new matrix which is the transpose of this one
+   * 
+   * @return
+   */
   MatrixI transpose();
 
+  /**
+   * Returns a new matrix which is the result of premultiplying this matrix by
+   * the supplied argument. If this of size AxB (A rows and B columns), and the
+   * argument is CxA (C rows and A columns), the result is of size CxB.
+   * 
+   * @param in
+   * 
+   * @return
+   * @throws IllegalArgumentException
+   *           if the number of columns in the pre-multiplier is not equal to
+   *           the number of rows in the multiplicand (this)
+   */
   MatrixI preMultiply(MatrixI m);
 
+  /**
+   * Returns a new matrix which is the result of postmultiplying this matrix by
+   * the supplied argument. If this of size AxB (A rows and B columns), and the
+   * argument is BxC (B rows and C columns), the result is of size AxC.
+   * <p>
+   * This method simply returns the result of in.preMultiply(this)
+   * 
+   * @param in
+   * 
+   * @return
+   * @throws IllegalArgumentException
+   *           if the number of rows in the post-multiplier is not equal to the
+   *           number of columns in the multiplicand (this)
+   * @see #preMultiply(Matrix)
+   */
   MatrixI postMultiply(MatrixI m);
 
   double[] getD();
 
   double[] getE();
 
+  void setD(double[] v);
+
+  void setE(double[] v);
+
   void print(PrintStream ps, String format);
 
   void printD(PrintStream ps, String format);
index 5971227..602c5e4 100755 (executable)
  */
 package jalview.math;
 
+import jalview.datamodel.Point;
+
+import java.util.HashMap;
+import java.util.Map;
+
 /**
- * DOCUMENT ME!
- * 
- * @author $author$
- * @version $Revision$
+ * Model for a 3x3 matrix which provides methods for rotation in 3-D space
  */
 public class RotatableMatrix
 {
-  float[][] matrix;
+  private static final int DIMS = 3;
 
-  float[] temp;
+  /*
+   * cache the most used rotations: +/- 1, 2, 3, 4 degrees around x or y axis
+   */
+  private static Map<Axis, Map<Float, float[][]>> cachedRotations;
 
-  float[][] rot;
+  static
+  {
+    cachedRotations = new HashMap<>();
+    for (Axis axis : Axis.values())
+    {
+      HashMap<Float, float[][]> map = new HashMap<>();
+      cachedRotations.put(axis, map);
+      for (int deg = 1; deg < 5; deg++)
+      {
+        float[][] rotation = getRotation(deg, axis);
+        map.put(Float.valueOf(deg), rotation);
+        rotation = getRotation(-deg, axis);
+        map.put(Float.valueOf(-deg), rotation);
+      }
+    }
+  }
 
-  /**
-   * Creates a new RotatableMatrix object.
-   * 
-   * @param rows
-   *          DOCUMENT ME!
-   * @param cols
-   *          DOCUMENT ME!
-   */
-  public RotatableMatrix(int rows, int cols)
+  public enum Axis
   {
-    matrix = new float[rows][cols];
+    X, Y, Z
+  };
 
-    temp = new float[3];
+  float[][] matrix;
 
-    rot = new float[3][3];
+  /**
+   * Constructor creates a new identity matrix (all values zero except for 1 on
+   * the diagonal)
+   */
+  public RotatableMatrix()
+  {
+    matrix = new float[DIMS][DIMS];
+    for (int j = 0; j < DIMS; j++)
+    {
+      matrix[j][j] = 1f;
+    }
   }
 
   /**
-   * DOCUMENT ME!
+   * Sets the value at position (i, j) of the matrix
    * 
    * @param i
-   *          DOCUMENT ME!
    * @param j
-   *          DOCUMENT ME!
    * @param value
-   *          DOCUMENT ME!
    */
-  public void addElement(int i, int j, float value)
+  public void setValue(int i, int j, float value)
   {
     matrix[i][j] = value;
   }
 
   /**
-   * DOCUMENT ME!
+   * Answers the value at position (i, j) of the matrix
+   * 
+   * @param i
+   * @param j
+   * @return
+   */
+  public float getValue(int i, int j)
+  {
+    return matrix[i][j];
+  }
+
+  /**
+   * Prints the matrix in rows of space-delimited values
    */
   public void print()
   {
@@ -82,174 +114,137 @@ public class RotatableMatrix
   }
 
   /**
-   * DOCUMENT ME!
+   * Rotates the matrix through the specified number of degrees around the
+   * specified axis
    * 
    * @param degrees
-   *          DOCUMENT ME!
    * @param axis
-   *          DOCUMENT ME!
    */
-  public void rotate(float degrees, char axis)
+  public void rotate(float degrees, Axis axis)
   {
-    float costheta = (float) Math.cos((degrees * Math.PI) / (float) 180.0);
+    float[][] rot = getRotation(degrees, axis);
 
-    float sintheta = (float) Math.sin((degrees * Math.PI) / (float) 180.0);
+    preMultiply(rot);
+  }
 
-    if (axis == 'z')
+  /**
+   * Answers a matrix which, when it pre-multiplies another matrix, applies a
+   * rotation of the specified number of degrees around the specified axis
+   * 
+   * @param degrees
+   * @param axis
+   * @return
+   * @see https://en.wikipedia.org/wiki/Rotation_matrix#Basic_rotations
+   */
+  protected static float[][] getRotation(float degrees, Axis axis)
+  {
+    Float floatValue = Float.valueOf(degrees);
+    if (cachedRotations.get(axis).containsKey(floatValue))
     {
-      rot[0][0] = (float) costheta;
-
-      rot[0][1] = (float) -sintheta;
-
-      rot[0][2] = (float) 0.0;
-
-      rot[1][0] = (float) sintheta;
-
-      rot[1][1] = (float) costheta;
-
-      rot[1][2] = (float) 0.0;
-
-      rot[2][0] = (float) 0.0;
-
-      rot[2][1] = (float) 0.0;
-
-      rot[2][2] = (float) 1.0;
-
-      preMultiply(rot);
+      // System.out.println("getRotation from cache: " + (int) degrees);
+      return cachedRotations.get(axis).get(floatValue);
     }
 
-    if (axis == 'x')
-    {
-      rot[0][0] = (float) 1.0;
-
-      rot[0][1] = (float) 0.0;
-
-      rot[0][2] = (float) 0.0;
-
-      rot[1][0] = (float) 0.0;
+    float costheta = (float) Math.cos(degrees * Math.PI / 180f);
 
-      rot[1][1] = (float) costheta;
+    float sintheta = (float) Math.sin(degrees * Math.PI / 180f);
 
-      rot[1][2] = (float) sintheta;
+    float[][] rot = new float[DIMS][DIMS];
 
-      rot[2][0] = (float) 0.0;
-
-      rot[2][1] = (float) -sintheta;
-
-      rot[2][2] = (float) costheta;
-
-      preMultiply(rot);
-    }
-
-    if (axis == 'y')
+    switch (axis)
     {
-      rot[0][0] = (float) costheta;
-
-      rot[0][1] = (float) 0.0;
-
-      rot[0][2] = (float) -sintheta;
-
-      rot[1][0] = (float) 0.0;
-
-      rot[1][1] = (float) 1.0;
-
-      rot[1][2] = (float) 0.0;
-
-      rot[2][0] = (float) sintheta;
-
-      rot[2][1] = (float) 0.0;
-
-      rot[2][2] = (float) costheta;
-
-      preMultiply(rot);
+    case X:
+      rot[0][0] = 1f;
+      rot[1][1] = costheta;
+      rot[1][2] = sintheta;
+      rot[2][1] = -sintheta;
+      rot[2][2] = costheta;
+      break;
+    case Y:
+      rot[0][0] = costheta;
+      rot[0][2] = -sintheta;
+      rot[1][1] = 1f;
+      rot[2][0] = sintheta;
+      rot[2][2] = costheta;
+      break;
+    case Z:
+      rot[0][0] = costheta;
+      rot[0][1] = -sintheta;
+      rot[1][0] = sintheta;
+      rot[1][1] = costheta;
+      rot[2][2] = 1f;
+      break;
     }
+    return rot;
   }
 
   /**
-   * DOCUMENT ME!
+   * Answers a new array of float values which is the result of pre-multiplying
+   * this matrix by the given vector. Each value of the result is the dot
+   * product of the vector with one column of this matrix. The matrix and input
+   * vector are not modified.
    * 
    * @param vect
-   *          DOCUMENT ME!
    * 
-   * @return DOCUMENT ME!
+   * @return
    */
   public float[] vectorMultiply(float[] vect)
   {
-    temp[0] = vect[0];
-
-    temp[1] = vect[1];
-
-    temp[2] = vect[2];
+    float[] result = new float[DIMS];
 
-    for (int i = 0; i < 3; i++)
+    for (int i = 0; i < DIMS; i++)
     {
-      temp[i] = (matrix[i][0] * vect[0]) + (matrix[i][1] * vect[1])
+      result[i] = (matrix[i][0] * vect[0]) + (matrix[i][1] * vect[1])
               + (matrix[i][2] * vect[2]);
     }
 
-    vect[0] = temp[0];
-
-    vect[1] = temp[1];
-
-    vect[2] = temp[2];
-
-    return vect;
+    return result;
   }
 
   /**
-   * DOCUMENT ME!
+   * Performs pre-multiplication of this matrix by the given one. Value (i, j)
+   * of the result is the dot product of the i'th row of <code>mat</code> with
+   * the j'th column of this matrix.
    * 
    * @param mat
-   *          DOCUMENT ME!
    */
   public void preMultiply(float[][] mat)
   {
-    float[][] tmp = new float[3][3];
+    float[][] tmp = new float[DIMS][DIMS];
 
-    for (int i = 0; i < 3; i++)
+    for (int i = 0; i < DIMS; i++)
     {
-      for (int j = 0; j < 3; j++)
+      for (int j = 0; j < DIMS; j++)
       {
         tmp[i][j] = (mat[i][0] * matrix[0][j]) + (mat[i][1] * matrix[1][j])
                 + (mat[i][2] * matrix[2][j]);
       }
     }
 
-    for (int i = 0; i < 3; i++)
-    {
-      for (int j = 0; j < 3; j++)
-      {
-        matrix[i][j] = tmp[i][j];
-      }
-    }
+    matrix = tmp;
   }
 
   /**
-   * DOCUMENT ME!
+   * Performs post-multiplication of this matrix by the given one. Value (i, j)
+   * of the result is the dot product of the i'th row of this matrix with the
+   * j'th column of <code>mat</code>.
    * 
    * @param mat
-   *          DOCUMENT ME!
    */
   public void postMultiply(float[][] mat)
   {
-    float[][] tmp = new float[3][3];
+    float[][] tmp = new float[DIMS][DIMS];
 
-    for (int i = 0; i < 3; i++)
+    for (int i = 0; i < DIMS; i++)
     {
-      for (int j = 0; j < 3; j++)
+      for (int j = 0; j < DIMS; j++)
       {
         tmp[i][j] = (matrix[i][0] * mat[0][j]) + (matrix[i][1] * mat[1][j])
                 + (matrix[i][2] * mat[2][j]);
       }
     }
 
-    for (int i = 0; i < 3; i++)
-    {
-      for (int j = 0; j < 3; j++)
-      {
-        matrix[i][j] = tmp[i][j];
-      }
-    }
+    matrix = tmp;
   }
 
   /**
@@ -260,47 +255,47 @@ public class RotatableMatrix
    */
   public static void main(String[] args)
   {
-    RotatableMatrix m = new RotatableMatrix(3, 3);
+    RotatableMatrix m = new RotatableMatrix();
 
-    m.addElement(0, 0, 1);
+    m.setValue(0, 0, 1);
 
-    m.addElement(0, 1, 0);
+    m.setValue(0, 1, 0);
 
-    m.addElement(0, 2, 0);
+    m.setValue(0, 2, 0);
 
-    m.addElement(1, 0, 0);
+    m.setValue(1, 0, 0);
 
-    m.addElement(1, 1, 2);
+    m.setValue(1, 1, 2);
 
-    m.addElement(1, 2, 0);
+    m.setValue(1, 2, 0);
 
-    m.addElement(2, 0, 0);
+    m.setValue(2, 0, 0);
 
-    m.addElement(2, 1, 0);
+    m.setValue(2, 1, 0);
 
-    m.addElement(2, 2, 1);
+    m.setValue(2, 2, 1);
 
     m.print();
 
-    RotatableMatrix n = new RotatableMatrix(3, 3);
+    RotatableMatrix n = new RotatableMatrix();
 
-    n.addElement(0, 0, 2);
+    n.setValue(0, 0, 2);
 
-    n.addElement(0, 1, 1);
+    n.setValue(0, 1, 1);
 
-    n.addElement(0, 2, 1);
+    n.setValue(0, 2, 1);
 
-    n.addElement(1, 0, 2);
+    n.setValue(1, 0, 2);
 
-    n.addElement(1, 1, 1);
+    n.setValue(1, 1, 1);
 
-    n.addElement(1, 2, 1);
+    n.setValue(1, 2, 1);
 
-    n.addElement(2, 0, 2);
+    n.setValue(2, 0, 2);
 
-    n.addElement(2, 1, 1);
+    n.setValue(2, 1, 1);
 
-    n.addElement(2, 2, 1);
+    n.setValue(2, 2, 1);
 
     n.print();
 
@@ -321,26 +316,15 @@ public class RotatableMatrix
   }
 
   /**
-   * DOCUMENT ME!
+   * Performs a vector multiplication whose result is the Point representing the
+   * input point's value vector post-multiplied by this matrix.
+   * 
+   * @param coord
+   * @return
    */
-  public void setIdentity()
+  public Point vectorMultiply(Point coord)
   {
-    matrix[0][0] = (float) 1.0;
-
-    matrix[1][1] = (float) 1.0;
-
-    matrix[2][2] = (float) 1.0;
-
-    matrix[0][1] = (float) 0.0;
-
-    matrix[0][2] = (float) 0.0;
-
-    matrix[1][0] = (float) 0.0;
-
-    matrix[1][2] = (float) 0.0;
-
-    matrix[2][0] = (float) 0.0;
-
-    matrix[2][1] = (float) 0.0;
+    float[] v = vectorMultiply(new float[] { coord.x, coord.y, coord.z });
+    return new Point(v[0], v[1], v[2]);
   }
 }
index 86592a0..e24cda5 100644 (file)
@@ -45,11 +45,8 @@ public class SparseMatrix extends Matrix
    */
   public SparseMatrix(double[][] v)
   {
-    rows = v.length;
-    if (rows > 0)
-    {
-      cols = v[0].length;
-    }
+    super(v.length, v.length > 0 ? v[0].length : 0);
+
     sparseColumns = new SparseDoubleArray[cols];
 
     /*
index b153d9f..4a4c0c2 100644 (file)
  */
 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;
@@ -31,6 +40,7 @@ import jalview.datamodel.AlignmentAnnotation;
 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;
@@ -51,6 +61,7 @@ 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;
@@ -60,6 +71,8 @@ import jalview.gui.TreePanel;
 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.schemes.AnnotationColourGradient;
 import jalview.schemes.ColourSchemeI;
@@ -76,6 +89,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;
@@ -91,6 +105,8 @@ 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;
@@ -105,6 +121,11 @@ 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;
@@ -117,6 +138,7 @@ 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;
@@ -191,6 +213,12 @@ public class Jalview2XML
 
   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;
 
@@ -1208,6 +1236,9 @@ public class Jalview2XML
               tree.setXpos(tp.getX());
               tree.setYpos(tp.getY());
               tree.setId(makeHashCode(tp, null));
+              tree.setLinkToAllViews(
+                      tp.getTreeCanvas().isApplyToAllViews());
+
               // jms.addTree(tree);
               object.getTree().add(tree);
             }
@@ -1216,6 +1247,24 @@ public class Jalview2XML
       }
     }
 
+    /*
+     * 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
@@ -1623,6 +1672,196 @@ public class Jalview2XML
   }
 
   /**
+   * 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>
@@ -3020,6 +3259,28 @@ public class Jalview2XML
             : 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;
@@ -3140,7 +3401,7 @@ public class Jalview2XML
 
       // 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)
@@ -3680,13 +3941,6 @@ public class Jalview2XML
     // ///////////////////////////////
     // 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.
@@ -3768,6 +4022,7 @@ public class Jalview2XML
     if (loadTreesAndStructures)
     {
       loadTrees(jalviewModel, view, af, av, ap);
+      loadPCAViewers(jalviewModel, ap);
       loadPDBStructures(jprovider, jseqs, af, ap);
       loadRnaViewers(jprovider, jseqs, ap);
     }
@@ -3916,6 +4171,8 @@ public class Jalview2XML
           // 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)
@@ -5185,13 +5442,51 @@ public class Jalview2XML
   }
 
   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();
     }
@@ -5214,10 +5509,58 @@ public class Jalview2XML
     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
@@ -5553,6 +5896,10 @@ public class Jalview2XML
     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.getViewport().get(0).setId(null);
@@ -5814,6 +6161,128 @@ public class Jalview2XML
   }
 
   /**
+   * 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
diff --git a/src/jalview/schemabinding/version2/Axis.java b/src/jalview/schemabinding/version2/Axis.java
new file mode 100644 (file)
index 0000000..9fe9660
--- /dev/null
@@ -0,0 +1,276 @@
+/*
+ * This class was automatically generated with 
+ * <a href="http://www.castor.org">Castor 1.1</a>, using an XML
+ * Schema.
+ * $Id$
+ */
+
+package jalview.schemabinding.version2;
+
+//---------------------------------/
+//- Imported classes and packages -/
+//---------------------------------/
+
+import org.exolab.castor.xml.Marshaller;
+import org.exolab.castor.xml.Unmarshaller;
+
+/**
+ * endpoints of X, Y and Z axes in that order
+ * 
+ * 
+ * @version $Revision$ $Date$
+ */
+public class Axis implements java.io.Serializable
+{
+
+  // --------------------------/
+  // - Class/Member Variables -/
+  // --------------------------/
+
+  /**
+   * Field _xPos.
+   */
+  private float _xPos;
+
+  /**
+   * keeps track of state for field: _xPos
+   */
+  private boolean _has_xPos;
+
+  /**
+   * Field _yPos.
+   */
+  private float _yPos;
+
+  /**
+   * keeps track of state for field: _yPos
+   */
+  private boolean _has_yPos;
+
+  /**
+   * Field _zPos.
+   */
+  private float _zPos;
+
+  /**
+   * keeps track of state for field: _zPos
+   */
+  private boolean _has_zPos;
+
+  // ----------------/
+  // - Constructors -/
+  // ----------------/
+
+  public Axis()
+  {
+    super();
+  }
+
+  // -----------/
+  // - Methods -/
+  // -----------/
+
+  /**
+   */
+  public void deleteXPos()
+  {
+    this._has_xPos = false;
+  }
+
+  /**
+   */
+  public void deleteYPos()
+  {
+    this._has_yPos = false;
+  }
+
+  /**
+   */
+  public void deleteZPos()
+  {
+    this._has_zPos = false;
+  }
+
+  /**
+   * Returns the value of field 'xPos'.
+   * 
+   * @return the value of field 'XPos'.
+   */
+  public float getXPos()
+  {
+    return this._xPos;
+  }
+
+  /**
+   * Returns the value of field 'yPos'.
+   * 
+   * @return the value of field 'YPos'.
+   */
+  public float getYPos()
+  {
+    return this._yPos;
+  }
+
+  /**
+   * Returns the value of field 'zPos'.
+   * 
+   * @return the value of field 'ZPos'.
+   */
+  public float getZPos()
+  {
+    return this._zPos;
+  }
+
+  /**
+   * Method hasXPos.
+   * 
+   * @return true if at least one XPos has been added
+   */
+  public boolean hasXPos()
+  {
+    return this._has_xPos;
+  }
+
+  /**
+   * Method hasYPos.
+   * 
+   * @return true if at least one YPos has been added
+   */
+  public boolean hasYPos()
+  {
+    return this._has_yPos;
+  }
+
+  /**
+   * Method hasZPos.
+   * 
+   * @return true if at least one ZPos has been added
+   */
+  public boolean hasZPos()
+  {
+    return this._has_zPos;
+  }
+
+  /**
+   * Method isValid.
+   * 
+   * @return true if this object is valid according to the schema
+   */
+  public boolean isValid()
+  {
+    try
+    {
+      validate();
+    } catch (org.exolab.castor.xml.ValidationException vex)
+    {
+      return false;
+    }
+    return true;
+  }
+
+  /**
+   * 
+   * 
+   * @param out
+   * @throws org.exolab.castor.xml.MarshalException
+   *           if object is null or if any SAXException is thrown during
+   *           marshaling
+   * @throws org.exolab.castor.xml.ValidationException
+   *           if this object is an invalid instance according to the schema
+   */
+  public void marshal(final java.io.Writer out)
+          throws org.exolab.castor.xml.MarshalException,
+          org.exolab.castor.xml.ValidationException
+  {
+    Marshaller.marshal(this, out);
+  }
+
+  /**
+   * 
+   * 
+   * @param handler
+   * @throws java.io.IOException
+   *           if an IOException occurs during marshaling
+   * @throws org.exolab.castor.xml.ValidationException
+   *           if this object is an invalid instance according to the schema
+   * @throws org.exolab.castor.xml.MarshalException
+   *           if object is null or if any SAXException is thrown during
+   *           marshaling
+   */
+  public void marshal(final org.xml.sax.ContentHandler handler)
+          throws java.io.IOException,
+          org.exolab.castor.xml.MarshalException,
+          org.exolab.castor.xml.ValidationException
+  {
+    Marshaller.marshal(this, handler);
+  }
+
+  /**
+   * Sets the value of field 'xPos'.
+   * 
+   * @param xPos
+   *          the value of field 'xPos'.
+   */
+  public void setXPos(final float xPos)
+  {
+    this._xPos = xPos;
+    this._has_xPos = true;
+  }
+
+  /**
+   * Sets the value of field 'yPos'.
+   * 
+   * @param yPos
+   *          the value of field 'yPos'.
+   */
+  public void setYPos(final float yPos)
+  {
+    this._yPos = yPos;
+    this._has_yPos = true;
+  }
+
+  /**
+   * Sets the value of field 'zPos'.
+   * 
+   * @param zPos
+   *          the value of field 'zPos'.
+   */
+  public void setZPos(final float zPos)
+  {
+    this._zPos = zPos;
+    this._has_zPos = true;
+  }
+
+  /**
+   * Method unmarshal.
+   * 
+   * @param reader
+   * @throws org.exolab.castor.xml.MarshalException
+   *           if object is null or if any SAXException is thrown during
+   *           marshaling
+   * @throws org.exolab.castor.xml.ValidationException
+   *           if this object is an invalid instance according to the schema
+   * @return the unmarshaled jalview.schemabinding.version2.Axis
+   */
+  public static jalview.schemabinding.version2.Axis unmarshal(
+          final java.io.Reader reader)
+          throws org.exolab.castor.xml.MarshalException,
+          org.exolab.castor.xml.ValidationException
+  {
+    return (jalview.schemabinding.version2.Axis) Unmarshaller
+            .unmarshal(jalview.schemabinding.version2.Axis.class, reader);
+  }
+
+  /**
+   * 
+   * 
+   * @throws org.exolab.castor.xml.ValidationException
+   *           if this object is an invalid instance according to the schema
+   */
+  public void validate() throws org.exolab.castor.xml.ValidationException
+  {
+    org.exolab.castor.xml.Validator validator = new org.exolab.castor.xml.Validator();
+    validator.validate(this);
+  }
+
+}
diff --git a/src/jalview/schemabinding/version2/D.java b/src/jalview/schemabinding/version2/D.java
new file mode 100644 (file)
index 0000000..9ea09d9
--- /dev/null
@@ -0,0 +1,124 @@
+/*
+ * This class was automatically generated with 
+ * <a href="http://www.castor.org">Castor 1.1</a>, using an XML
+ * Schema.
+ * $Id$
+ */
+
+package jalview.schemabinding.version2;
+
+//---------------------------------/
+//- Imported classes and packages -/
+//---------------------------------/
+
+import org.exolab.castor.xml.Marshaller;
+import org.exolab.castor.xml.Unmarshaller;
+
+/**
+ * Class D.
+ * 
+ * @version $Revision$ $Date$
+ */
+public class D extends DoubleVector implements java.io.Serializable
+{
+
+  // ----------------/
+  // - Constructors -/
+  // ----------------/
+
+  public D()
+  {
+    super();
+  }
+
+  // -----------/
+  // - Methods -/
+  // -----------/
+
+  /**
+   * Method isValid.
+   * 
+   * @return true if this object is valid according to the schema
+   */
+  public boolean isValid()
+  {
+    try
+    {
+      validate();
+    } catch (org.exolab.castor.xml.ValidationException vex)
+    {
+      return false;
+    }
+    return true;
+  }
+
+  /**
+   * 
+   * 
+   * @param out
+   * @throws org.exolab.castor.xml.MarshalException
+   *           if object is null or if any SAXException is thrown during
+   *           marshaling
+   * @throws org.exolab.castor.xml.ValidationException
+   *           if this object is an invalid instance according to the schema
+   */
+  public void marshal(final java.io.Writer out)
+          throws org.exolab.castor.xml.MarshalException,
+          org.exolab.castor.xml.ValidationException
+  {
+    Marshaller.marshal(this, out);
+  }
+
+  /**
+   * 
+   * 
+   * @param handler
+   * @throws java.io.IOException
+   *           if an IOException occurs during marshaling
+   * @throws org.exolab.castor.xml.ValidationException
+   *           if this object is an invalid instance according to the schema
+   * @throws org.exolab.castor.xml.MarshalException
+   *           if object is null or if any SAXException is thrown during
+   *           marshaling
+   */
+  public void marshal(final org.xml.sax.ContentHandler handler)
+          throws java.io.IOException,
+          org.exolab.castor.xml.MarshalException,
+          org.exolab.castor.xml.ValidationException
+  {
+    Marshaller.marshal(this, handler);
+  }
+
+  /**
+   * Method unmarshal.
+   * 
+   * @param reader
+   * @throws org.exolab.castor.xml.MarshalException
+   *           if object is null or if any SAXException is thrown during
+   *           marshaling
+   * @throws org.exolab.castor.xml.ValidationException
+   *           if this object is an invalid instance according to the schema
+   * @return the unmarshaled jalview.schemabinding.version2.DoubleVector
+   */
+  public static jalview.schemabinding.version2.DoubleVector unmarshal(
+          final java.io.Reader reader)
+          throws org.exolab.castor.xml.MarshalException,
+          org.exolab.castor.xml.ValidationException
+  {
+    return (jalview.schemabinding.version2.DoubleVector) Unmarshaller
+            .unmarshal(jalview.schemabinding.version2.D.class, reader);
+  }
+
+  /**
+   * 
+   * 
+   * @throws org.exolab.castor.xml.ValidationException
+   *           if this object is an invalid instance according to the schema
+   */
+  public void validate() throws org.exolab.castor.xml.ValidationException
+  {
+    org.exolab.castor.xml.Validator validator = new org.exolab.castor.xml.Validator();
+    validator.validate(this);
+  }
+
+}
diff --git a/src/jalview/schemabinding/version2/DoubleMatrix.java b/src/jalview/schemabinding/version2/DoubleMatrix.java
new file mode 100644 (file)
index 0000000..04aed99
--- /dev/null
@@ -0,0 +1,440 @@
+/*
+ * This class was automatically generated with 
+ * <a href="http://www.castor.org">Castor 1.1</a>, using an XML
+ * Schema.
+ * $Id$
+ */
+
+package jalview.schemabinding.version2;
+
+//---------------------------------/
+//- Imported classes and packages -/
+//---------------------------------/
+
+import org.exolab.castor.xml.Marshaller;
+import org.exolab.castor.xml.Unmarshaller;
+
+/**
+ * Class DoubleMatrix.
+ * 
+ * @version $Revision$ $Date$
+ */
+public class DoubleMatrix implements java.io.Serializable
+{
+
+  // --------------------------/
+  // - Class/Member Variables -/
+  // --------------------------/
+
+  /**
+   * Field _rows.
+   */
+  private int _rows;
+
+  /**
+   * keeps track of state for field: _rows
+   */
+  private boolean _has_rows;
+
+  /**
+   * Field _columns.
+   */
+  private int _columns;
+
+  /**
+   * keeps track of state for field: _columns
+   */
+  private boolean _has_columns;
+
+  /**
+   * Field _rowList.
+   */
+  private java.util.Vector _rowList;
+
+  /**
+   * Field _d.
+   */
+  private jalview.schemabinding.version2.D _d;
+
+  /**
+   * Field _e.
+   */
+  private jalview.schemabinding.version2.E _e;
+
+  // ----------------/
+  // - Constructors -/
+  // ----------------/
+
+  public DoubleMatrix()
+  {
+    super();
+    this._rowList = new java.util.Vector();
+  }
+
+  // -----------/
+  // - Methods -/
+  // -----------/
+
+  /**
+   * 
+   * 
+   * @param vRow
+   * @throws java.lang.IndexOutOfBoundsException
+   *           if the index given is outside the bounds of the collection
+   */
+  public void addRow(final jalview.schemabinding.version2.Row vRow)
+          throws java.lang.IndexOutOfBoundsException
+  {
+    this._rowList.addElement(vRow);
+  }
+
+  /**
+   * 
+   * 
+   * @param index
+   * @param vRow
+   * @throws java.lang.IndexOutOfBoundsException
+   *           if the index given is outside the bounds of the collection
+   */
+  public void addRow(final int index,
+          final jalview.schemabinding.version2.Row vRow)
+          throws java.lang.IndexOutOfBoundsException
+  {
+    this._rowList.add(index, vRow);
+  }
+
+  /**
+   */
+  public void deleteColumns()
+  {
+    this._has_columns = false;
+  }
+
+  /**
+   */
+  public void deleteRows()
+  {
+    this._has_rows = false;
+  }
+
+  /**
+   * Method enumerateRow.
+   * 
+   * @return an Enumeration over all jalview.schemabinding.version2.Row elements
+   */
+  public java.util.Enumeration enumerateRow()
+  {
+    return this._rowList.elements();
+  }
+
+  /**
+   * Returns the value of field 'columns'.
+   * 
+   * @return the value of field 'Columns'.
+   */
+  public int getColumns()
+  {
+    return this._columns;
+  }
+
+  /**
+   * Returns the value of field 'd'.
+   * 
+   * @return the value of field 'D'.
+   */
+  public jalview.schemabinding.version2.D getD()
+  {
+    return this._d;
+  }
+
+  /**
+   * Returns the value of field 'e'.
+   * 
+   * @return the value of field 'E'.
+   */
+  public jalview.schemabinding.version2.E getE()
+  {
+    return this._e;
+  }
+
+  /**
+   * Method getRow.
+   * 
+   * @param index
+   * @throws java.lang.IndexOutOfBoundsException
+   *           if the index given is outside the bounds of the collection
+   * @return the value of the jalview.schemabinding.version2.Row at the given
+   *         index
+   */
+  public jalview.schemabinding.version2.Row getRow(final int index)
+          throws java.lang.IndexOutOfBoundsException
+  {
+    // check bounds for index
+    if (index < 0 || index >= this._rowList.size())
+    {
+      throw new IndexOutOfBoundsException("getRow: Index value '" + index
+              + "' not in range [0.." + (this._rowList.size() - 1) + "]");
+    }
+
+    return (jalview.schemabinding.version2.Row) _rowList.get(index);
+  }
+
+  /**
+   * Method getRow.Returns the contents of the collection in an Array.
+   * <p>
+   * Note: Just in case the collection contents are changing in another thread,
+   * we pass a 0-length Array of the correct type into the API call. This way we
+   * <i>know</i> that the Array returned is of exactly the correct length.
+   * 
+   * @return this collection as an Array
+   */
+  public jalview.schemabinding.version2.Row[] getRow()
+  {
+    jalview.schemabinding.version2.Row[] array = new jalview.schemabinding.version2.Row[0];
+    return (jalview.schemabinding.version2.Row[]) this._rowList
+            .toArray(array);
+  }
+
+  /**
+   * Method getRowCount.
+   * 
+   * @return the size of this collection
+   */
+  public int getRowCount()
+  {
+    return this._rowList.size();
+  }
+
+  /**
+   * Returns the value of field 'rows'.
+   * 
+   * @return the value of field 'Rows'.
+   */
+  public int getRows()
+  {
+    return this._rows;
+  }
+
+  /**
+   * Method hasColumns.
+   * 
+   * @return true if at least one Columns has been added
+   */
+  public boolean hasColumns()
+  {
+    return this._has_columns;
+  }
+
+  /**
+   * Method hasRows.
+   * 
+   * @return true if at least one Rows has been added
+   */
+  public boolean hasRows()
+  {
+    return this._has_rows;
+  }
+
+  /**
+   * Method isValid.
+   * 
+   * @return true if this object is valid according to the schema
+   */
+  public boolean isValid()
+  {
+    try
+    {
+      validate();
+    } catch (org.exolab.castor.xml.ValidationException vex)
+    {
+      return false;
+    }
+    return true;
+  }
+
+  /**
+   * 
+   * 
+   * @param out
+   * @throws org.exolab.castor.xml.MarshalException
+   *           if object is null or if any SAXException is thrown during
+   *           marshaling
+   * @throws org.exolab.castor.xml.ValidationException
+   *           if this object is an invalid instance according to the schema
+   */
+  public void marshal(final java.io.Writer out)
+          throws org.exolab.castor.xml.MarshalException,
+          org.exolab.castor.xml.ValidationException
+  {
+    Marshaller.marshal(this, out);
+  }
+
+  /**
+   * 
+   * 
+   * @param handler
+   * @throws java.io.IOException
+   *           if an IOException occurs during marshaling
+   * @throws org.exolab.castor.xml.ValidationException
+   *           if this object is an invalid instance according to the schema
+   * @throws org.exolab.castor.xml.MarshalException
+   *           if object is null or if any SAXException is thrown during
+   *           marshaling
+   */
+  public void marshal(final org.xml.sax.ContentHandler handler)
+          throws java.io.IOException,
+          org.exolab.castor.xml.MarshalException,
+          org.exolab.castor.xml.ValidationException
+  {
+    Marshaller.marshal(this, handler);
+  }
+
+  /**
+   */
+  public void removeAllRow()
+  {
+    this._rowList.clear();
+  }
+
+  /**
+   * Method removeRow.
+   * 
+   * @param vRow
+   * @return true if the object was removed from the collection.
+   */
+  public boolean removeRow(final jalview.schemabinding.version2.Row vRow)
+  {
+    boolean removed = _rowList.remove(vRow);
+    return removed;
+  }
+
+  /**
+   * Method removeRowAt.
+   * 
+   * @param index
+   * @return the element removed from the collection
+   */
+  public jalview.schemabinding.version2.Row removeRowAt(final int index)
+  {
+    java.lang.Object obj = this._rowList.remove(index);
+    return (jalview.schemabinding.version2.Row) obj;
+  }
+
+  /**
+   * Sets the value of field 'columns'.
+   * 
+   * @param columns
+   *          the value of field 'columns'.
+   */
+  public void setColumns(final int columns)
+  {
+    this._columns = columns;
+    this._has_columns = true;
+  }
+
+  /**
+   * Sets the value of field 'd'.
+   * 
+   * @param d
+   *          the value of field 'd'.
+   */
+  public void setD(final jalview.schemabinding.version2.D d)
+  {
+    this._d = d;
+  }
+
+  /**
+   * Sets the value of field 'e'.
+   * 
+   * @param e
+   *          the value of field 'e'.
+   */
+  public void setE(final jalview.schemabinding.version2.E e)
+  {
+    this._e = e;
+  }
+
+  /**
+   * 
+   * 
+   * @param index
+   * @param vRow
+   * @throws java.lang.IndexOutOfBoundsException
+   *           if the index given is outside the bounds of the collection
+   */
+  public void setRow(final int index,
+          final jalview.schemabinding.version2.Row vRow)
+          throws java.lang.IndexOutOfBoundsException
+  {
+    // check bounds for index
+    if (index < 0 || index >= this._rowList.size())
+    {
+      throw new IndexOutOfBoundsException("setRow: Index value '" + index
+              + "' not in range [0.." + (this._rowList.size() - 1) + "]");
+    }
+
+    this._rowList.set(index, vRow);
+  }
+
+  /**
+   * 
+   * 
+   * @param vRowArray
+   */
+  public void setRow(final jalview.schemabinding.version2.Row[] vRowArray)
+  {
+    // -- copy array
+    _rowList.clear();
+
+    for (int i = 0; i < vRowArray.length; i++)
+    {
+      this._rowList.add(vRowArray[i]);
+    }
+  }
+
+  /**
+   * Sets the value of field 'rows'.
+   * 
+   * @param rows
+   *          the value of field 'rows'.
+   */
+  public void setRows(final int rows)
+  {
+    this._rows = rows;
+    this._has_rows = true;
+  }
+
+  /**
+   * Method unmarshal.
+   * 
+   * @param reader
+   * @throws org.exolab.castor.xml.MarshalException
+   *           if object is null or if any SAXException is thrown during
+   *           marshaling
+   * @throws org.exolab.castor.xml.ValidationException
+   *           if this object is an invalid instance according to the schema
+   * @return the unmarshaled jalview.schemabinding.version2.DoubleMatrix
+   */
+  public static jalview.schemabinding.version2.DoubleMatrix unmarshal(
+          final java.io.Reader reader)
+          throws org.exolab.castor.xml.MarshalException,
+          org.exolab.castor.xml.ValidationException
+  {
+    return (jalview.schemabinding.version2.DoubleMatrix) Unmarshaller
+            .unmarshal(jalview.schemabinding.version2.DoubleMatrix.class,
+                    reader);
+  }
+
+  /**
+   * 
+   * 
+   * @throws org.exolab.castor.xml.ValidationException
+   *           if this object is an invalid instance according to the schema
+   */
+  public void validate() throws org.exolab.castor.xml.ValidationException
+  {
+    org.exolab.castor.xml.Validator validator = new org.exolab.castor.xml.Validator();
+    validator.validate(this);
+  }
+
+}
diff --git a/src/jalview/schemabinding/version2/DoubleVector.java b/src/jalview/schemabinding/version2/DoubleVector.java
new file mode 100644 (file)
index 0000000..c4d8ff5
--- /dev/null
@@ -0,0 +1,288 @@
+/*
+ * This class was automatically generated with 
+ * <a href="http://www.castor.org">Castor 1.1</a>, using an XML
+ * Schema.
+ * $Id$
+ */
+
+package jalview.schemabinding.version2;
+
+//---------------------------------/
+//- Imported classes and packages -/
+//---------------------------------/
+
+import org.exolab.castor.xml.Marshaller;
+import org.exolab.castor.xml.Unmarshaller;
+
+/**
+ * Class DoubleVector.
+ * 
+ * @version $Revision$ $Date$
+ */
+public class DoubleVector implements java.io.Serializable
+{
+
+  // --------------------------/
+  // - Class/Member Variables -/
+  // --------------------------/
+
+  /**
+   * Field _vList.
+   */
+  private java.util.Vector _vList;
+
+  // ----------------/
+  // - Constructors -/
+  // ----------------/
+
+  public DoubleVector()
+  {
+    super();
+    this._vList = new java.util.Vector();
+  }
+
+  // -----------/
+  // - Methods -/
+  // -----------/
+
+  /**
+   * 
+   * 
+   * @param vV
+   * @throws java.lang.IndexOutOfBoundsException
+   *           if the index given is outside the bounds of the collection
+   */
+  public void addV(final double vV)
+          throws java.lang.IndexOutOfBoundsException
+  {
+    this._vList.addElement(new java.lang.Double(vV));
+  }
+
+  /**
+   * 
+   * 
+   * @param index
+   * @param vV
+   * @throws java.lang.IndexOutOfBoundsException
+   *           if the index given is outside the bounds of the collection
+   */
+  public void addV(final int index, final double vV)
+          throws java.lang.IndexOutOfBoundsException
+  {
+    this._vList.add(index, new java.lang.Double(vV));
+  }
+
+  /**
+   * Method enumerateV.
+   * 
+   * @return an Enumeration over all double elements
+   */
+  public java.util.Enumeration enumerateV()
+  {
+    return this._vList.elements();
+  }
+
+  /**
+   * Method getV.
+   * 
+   * @param index
+   * @throws java.lang.IndexOutOfBoundsException
+   *           if the index given is outside the bounds of the collection
+   * @return the value of the double at the given index
+   */
+  public double getV(final int index)
+          throws java.lang.IndexOutOfBoundsException
+  {
+    // check bounds for index
+    if (index < 0 || index >= this._vList.size())
+    {
+      throw new IndexOutOfBoundsException("getV: Index value '" + index
+              + "' not in range [0.." + (this._vList.size() - 1) + "]");
+    }
+
+    return ((java.lang.Double) _vList.get(index)).doubleValue();
+  }
+
+  /**
+   * Method getV.Returns the contents of the collection in an Array.
+   * 
+   * @return this collection as an Array
+   */
+  public double[] getV()
+  {
+    int size = this._vList.size();
+    double[] array = new double[size];
+    java.util.Iterator iter = _vList.iterator();
+    for (int index = 0; index < size; index++)
+    {
+      array[index] = ((java.lang.Double) iter.next()).doubleValue();
+    }
+    return array;
+  }
+
+  /**
+   * Method getVCount.
+   * 
+   * @return the size of this collection
+   */
+  public int getVCount()
+  {
+    return this._vList.size();
+  }
+
+  /**
+   * Method isValid.
+   * 
+   * @return true if this object is valid according to the schema
+   */
+  public boolean isValid()
+  {
+    try
+    {
+      validate();
+    } catch (org.exolab.castor.xml.ValidationException vex)
+    {
+      return false;
+    }
+    return true;
+  }
+
+  /**
+   * 
+   * 
+   * @param out
+   * @throws org.exolab.castor.xml.MarshalException
+   *           if object is null or if any SAXException is thrown during
+   *           marshaling
+   * @throws org.exolab.castor.xml.ValidationException
+   *           if this object is an invalid instance according to the schema
+   */
+  public void marshal(final java.io.Writer out)
+          throws org.exolab.castor.xml.MarshalException,
+          org.exolab.castor.xml.ValidationException
+  {
+    Marshaller.marshal(this, out);
+  }
+
+  /**
+   * 
+   * 
+   * @param handler
+   * @throws java.io.IOException
+   *           if an IOException occurs during marshaling
+   * @throws org.exolab.castor.xml.ValidationException
+   *           if this object is an invalid instance according to the schema
+   * @throws org.exolab.castor.xml.MarshalException
+   *           if object is null or if any SAXException is thrown during
+   *           marshaling
+   */
+  public void marshal(final org.xml.sax.ContentHandler handler)
+          throws java.io.IOException,
+          org.exolab.castor.xml.MarshalException,
+          org.exolab.castor.xml.ValidationException
+  {
+    Marshaller.marshal(this, handler);
+  }
+
+  /**
+   */
+  public void removeAllV()
+  {
+    this._vList.clear();
+  }
+
+  /**
+   * Method removeV.
+   * 
+   * @param vV
+   * @return true if the object was removed from the collection.
+   */
+  public boolean removeV(final double vV)
+  {
+    boolean removed = _vList.remove(new java.lang.Double(vV));
+    return removed;
+  }
+
+  /**
+   * Method removeVAt.
+   * 
+   * @param index
+   * @return the element removed from the collection
+   */
+  public double removeVAt(final int index)
+  {
+    java.lang.Object obj = this._vList.remove(index);
+    return ((java.lang.Double) obj).doubleValue();
+  }
+
+  /**
+   * 
+   * 
+   * @param index
+   * @param vV
+   * @throws java.lang.IndexOutOfBoundsException
+   *           if the index given is outside the bounds of the collection
+   */
+  public void setV(final int index, final double vV)
+          throws java.lang.IndexOutOfBoundsException
+  {
+    // check bounds for index
+    if (index < 0 || index >= this._vList.size())
+    {
+      throw new IndexOutOfBoundsException("setV: Index value '" + index
+              + "' not in range [0.." + (this._vList.size() - 1) + "]");
+    }
+
+    this._vList.set(index, new java.lang.Double(vV));
+  }
+
+  /**
+   * 
+   * 
+   * @param vVArray
+   */
+  public void setV(final double[] vVArray)
+  {
+    // -- copy array
+    _vList.clear();
+
+    for (int i = 0; i < vVArray.length; i++)
+    {
+      this._vList.add(new java.lang.Double(vVArray[i]));
+    }
+  }
+
+  /**
+   * Method unmarshal.
+   * 
+   * @param reader
+   * @throws org.exolab.castor.xml.MarshalException
+   *           if object is null or if any SAXException is thrown during
+   *           marshaling
+   * @throws org.exolab.castor.xml.ValidationException
+   *           if this object is an invalid instance according to the schema
+   * @return the unmarshaled jalview.schemabinding.version2.DoubleVector
+   */
+  public static jalview.schemabinding.version2.DoubleVector unmarshal(
+          final java.io.Reader reader)
+          throws org.exolab.castor.xml.MarshalException,
+          org.exolab.castor.xml.ValidationException
+  {
+    return (jalview.schemabinding.version2.DoubleVector) Unmarshaller
+            .unmarshal(jalview.schemabinding.version2.DoubleVector.class,
+                    reader);
+  }
+
+  /**
+   * 
+   * 
+   * @throws org.exolab.castor.xml.ValidationException
+   *           if this object is an invalid instance according to the schema
+   */
+  public void validate() throws org.exolab.castor.xml.ValidationException
+  {
+    org.exolab.castor.xml.Validator validator = new org.exolab.castor.xml.Validator();
+    validator.validate(this);
+  }
+
+}
diff --git a/src/jalview/schemabinding/version2/E.java b/src/jalview/schemabinding/version2/E.java
new file mode 100644 (file)
index 0000000..5daa4dd
--- /dev/null
@@ -0,0 +1,124 @@
+/*
+ * This class was automatically generated with 
+ * <a href="http://www.castor.org">Castor 1.1</a>, using an XML
+ * Schema.
+ * $Id$
+ */
+
+package jalview.schemabinding.version2;
+
+//---------------------------------/
+//- Imported classes and packages -/
+//---------------------------------/
+
+import org.exolab.castor.xml.Marshaller;
+import org.exolab.castor.xml.Unmarshaller;
+
+/**
+ * Class E.
+ * 
+ * @version $Revision$ $Date$
+ */
+public class E extends DoubleVector implements java.io.Serializable
+{
+
+  // ----------------/
+  // - Constructors -/
+  // ----------------/
+
+  public E()
+  {
+    super();
+  }
+
+  // -----------/
+  // - Methods -/
+  // -----------/
+
+  /**
+   * Method isValid.
+   * 
+   * @return true if this object is valid according to the schema
+   */
+  public boolean isValid()
+  {
+    try
+    {
+      validate();
+    } catch (org.exolab.castor.xml.ValidationException vex)
+    {
+      return false;
+    }
+    return true;
+  }
+
+  /**
+   * 
+   * 
+   * @param out
+   * @throws org.exolab.castor.xml.MarshalException
+   *           if object is null or if any SAXException is thrown during
+   *           marshaling
+   * @throws org.exolab.castor.xml.ValidationException
+   *           if this object is an invalid instance according to the schema
+   */
+  public void marshal(final java.io.Writer out)
+          throws org.exolab.castor.xml.MarshalException,
+          org.exolab.castor.xml.ValidationException
+  {
+    Marshaller.marshal(this, out);
+  }
+
+  /**
+   * 
+   * 
+   * @param handler
+   * @throws java.io.IOException
+   *           if an IOException occurs during marshaling
+   * @throws org.exolab.castor.xml.ValidationException
+   *           if this object is an invalid instance according to the schema
+   * @throws org.exolab.castor.xml.MarshalException
+   *           if object is null or if any SAXException is thrown during
+   *           marshaling
+   */
+  public void marshal(final org.xml.sax.ContentHandler handler)
+          throws java.io.IOException,
+          org.exolab.castor.xml.MarshalException,
+          org.exolab.castor.xml.ValidationException
+  {
+    Marshaller.marshal(this, handler);
+  }
+
+  /**
+   * Method unmarshal.
+   * 
+   * @param reader
+   * @throws org.exolab.castor.xml.MarshalException
+   *           if object is null or if any SAXException is thrown during
+   *           marshaling
+   * @throws org.exolab.castor.xml.ValidationException
+   *           if this object is an invalid instance according to the schema
+   * @return the unmarshaled jalview.schemabinding.version2.DoubleVector
+   */
+  public static jalview.schemabinding.version2.DoubleVector unmarshal(
+          final java.io.Reader reader)
+          throws org.exolab.castor.xml.MarshalException,
+          org.exolab.castor.xml.ValidationException
+  {
+    return (jalview.schemabinding.version2.DoubleVector) Unmarshaller
+            .unmarshal(jalview.schemabinding.version2.E.class, reader);
+  }
+
+  /**
+   * 
+   * 
+   * @throws org.exolab.castor.xml.ValidationException
+   *           if this object is an invalid instance according to the schema
+   */
+  public void validate() throws org.exolab.castor.xml.ValidationException
+  {
+    org.exolab.castor.xml.Validator validator = new org.exolab.castor.xml.Validator();
+    validator.validate(this);
+  }
+
+}
diff --git a/src/jalview/schemabinding/version2/EigenMatrix.java b/src/jalview/schemabinding/version2/EigenMatrix.java
new file mode 100644 (file)
index 0000000..b04a50c
--- /dev/null
@@ -0,0 +1,126 @@
+/*
+ * This class was automatically generated with 
+ * <a href="http://www.castor.org">Castor 1.1</a>, using an XML
+ * Schema.
+ * $Id$
+ */
+
+package jalview.schemabinding.version2;
+
+//---------------------------------/
+//- Imported classes and packages -/
+//---------------------------------/
+
+import org.exolab.castor.xml.Marshaller;
+import org.exolab.castor.xml.Unmarshaller;
+
+/**
+ * Class EigenMatrix.
+ * 
+ * @version $Revision$ $Date$
+ */
+public class EigenMatrix extends DoubleMatrix
+        implements java.io.Serializable
+{
+
+  // ----------------/
+  // - Constructors -/
+  // ----------------/
+
+  public EigenMatrix()
+  {
+    super();
+  }
+
+  // -----------/
+  // - Methods -/
+  // -----------/
+
+  /**
+   * Method isValid.
+   * 
+   * @return true if this object is valid according to the schema
+   */
+  public boolean isValid()
+  {
+    try
+    {
+      validate();
+    } catch (org.exolab.castor.xml.ValidationException vex)
+    {
+      return false;
+    }
+    return true;
+  }
+
+  /**
+   * 
+   * 
+   * @param out
+   * @throws org.exolab.castor.xml.MarshalException
+   *           if object is null or if any SAXException is thrown during
+   *           marshaling
+   * @throws org.exolab.castor.xml.ValidationException
+   *           if this object is an invalid instance according to the schema
+   */
+  public void marshal(final java.io.Writer out)
+          throws org.exolab.castor.xml.MarshalException,
+          org.exolab.castor.xml.ValidationException
+  {
+    Marshaller.marshal(this, out);
+  }
+
+  /**
+   * 
+   * 
+   * @param handler
+   * @throws java.io.IOException
+   *           if an IOException occurs during marshaling
+   * @throws org.exolab.castor.xml.ValidationException
+   *           if this object is an invalid instance according to the schema
+   * @throws org.exolab.castor.xml.MarshalException
+   *           if object is null or if any SAXException is thrown during
+   *           marshaling
+   */
+  public void marshal(final org.xml.sax.ContentHandler handler)
+          throws java.io.IOException,
+          org.exolab.castor.xml.MarshalException,
+          org.exolab.castor.xml.ValidationException
+  {
+    Marshaller.marshal(this, handler);
+  }
+
+  /**
+   * Method unmarshal.
+   * 
+   * @param reader
+   * @throws org.exolab.castor.xml.MarshalException
+   *           if object is null or if any SAXException is thrown during
+   *           marshaling
+   * @throws org.exolab.castor.xml.ValidationException
+   *           if this object is an invalid instance according to the schema
+   * @return the unmarshaled jalview.schemabinding.version2.DoubleMatrix
+   */
+  public static jalview.schemabinding.version2.DoubleMatrix unmarshal(
+          final java.io.Reader reader)
+          throws org.exolab.castor.xml.MarshalException,
+          org.exolab.castor.xml.ValidationException
+  {
+    return (jalview.schemabinding.version2.DoubleMatrix) Unmarshaller
+            .unmarshal(jalview.schemabinding.version2.EigenMatrix.class,
+                    reader);
+  }
+
+  /**
+   * 
+   * 
+   * @throws org.exolab.castor.xml.ValidationException
+   *           if this object is an invalid instance according to the schema
+   */
+  public void validate() throws org.exolab.castor.xml.ValidationException
+  {
+    org.exolab.castor.xml.Validator validator = new org.exolab.castor.xml.Validator();
+    validator.validate(this);
+  }
+
+}
diff --git a/src/jalview/schemabinding/version2/PairwiseMatrix.java b/src/jalview/schemabinding/version2/PairwiseMatrix.java
new file mode 100644 (file)
index 0000000..3906111
--- /dev/null
@@ -0,0 +1,126 @@
+/*
+ * This class was automatically generated with 
+ * <a href="http://www.castor.org">Castor 1.1</a>, using an XML
+ * Schema.
+ * $Id$
+ */
+
+package jalview.schemabinding.version2;
+
+//---------------------------------/
+//- Imported classes and packages -/
+//---------------------------------/
+
+import org.exolab.castor.xml.Marshaller;
+import org.exolab.castor.xml.Unmarshaller;
+
+/**
+ * Class PairwiseMatrix.
+ * 
+ * @version $Revision$ $Date$
+ */
+public class PairwiseMatrix extends DoubleMatrix
+        implements java.io.Serializable
+{
+
+  // ----------------/
+  // - Constructors -/
+  // ----------------/
+
+  public PairwiseMatrix()
+  {
+    super();
+  }
+
+  // -----------/
+  // - Methods -/
+  // -----------/
+
+  /**
+   * Method isValid.
+   * 
+   * @return true if this object is valid according to the schema
+   */
+  public boolean isValid()
+  {
+    try
+    {
+      validate();
+    } catch (org.exolab.castor.xml.ValidationException vex)
+    {
+      return false;
+    }
+    return true;
+  }
+
+  /**
+   * 
+   * 
+   * @param out
+   * @throws org.exolab.castor.xml.MarshalException
+   *           if object is null or if any SAXException is thrown during
+   *           marshaling
+   * @throws org.exolab.castor.xml.ValidationException
+   *           if this object is an invalid instance according to the schema
+   */
+  public void marshal(final java.io.Writer out)
+          throws org.exolab.castor.xml.MarshalException,
+          org.exolab.castor.xml.ValidationException
+  {
+    Marshaller.marshal(this, out);
+  }
+
+  /**
+   * 
+   * 
+   * @param handler
+   * @throws java.io.IOException
+   *           if an IOException occurs during marshaling
+   * @throws org.exolab.castor.xml.ValidationException
+   *           if this object is an invalid instance according to the schema
+   * @throws org.exolab.castor.xml.MarshalException
+   *           if object is null or if any SAXException is thrown during
+   *           marshaling
+   */
+  public void marshal(final org.xml.sax.ContentHandler handler)
+          throws java.io.IOException,
+          org.exolab.castor.xml.MarshalException,
+          org.exolab.castor.xml.ValidationException
+  {
+    Marshaller.marshal(this, handler);
+  }
+
+  /**
+   * Method unmarshal.
+   * 
+   * @param reader
+   * @throws org.exolab.castor.xml.MarshalException
+   *           if object is null or if any SAXException is thrown during
+   *           marshaling
+   * @throws org.exolab.castor.xml.ValidationException
+   *           if this object is an invalid instance according to the schema
+   * @return the unmarshaled jalview.schemabinding.version2.DoubleMatrix
+   */
+  public static jalview.schemabinding.version2.DoubleMatrix unmarshal(
+          final java.io.Reader reader)
+          throws org.exolab.castor.xml.MarshalException,
+          org.exolab.castor.xml.ValidationException
+  {
+    return (jalview.schemabinding.version2.DoubleMatrix) Unmarshaller
+            .unmarshal(jalview.schemabinding.version2.PairwiseMatrix.class,
+                    reader);
+  }
+
+  /**
+   * 
+   * 
+   * @throws org.exolab.castor.xml.ValidationException
+   *           if this object is an invalid instance according to the schema
+   */
+  public void validate() throws org.exolab.castor.xml.ValidationException
+  {
+    org.exolab.castor.xml.Validator validator = new org.exolab.castor.xml.Validator();
+    validator.validate(this);
+  }
+
+}
diff --git a/src/jalview/schemabinding/version2/PcaData.java b/src/jalview/schemabinding/version2/PcaData.java
new file mode 100644 (file)
index 0000000..dfce269
--- /dev/null
@@ -0,0 +1,125 @@
+/*
+ * This class was automatically generated with 
+ * <a href="http://www.castor.org">Castor 1.1</a>, using an XML
+ * Schema.
+ * $Id$
+ */
+
+package jalview.schemabinding.version2;
+
+//---------------------------------/
+//- Imported classes and packages -/
+//---------------------------------/
+
+import org.exolab.castor.xml.Marshaller;
+import org.exolab.castor.xml.Unmarshaller;
+
+/**
+ * Class PcaData.
+ * 
+ * @version $Revision$ $Date$
+ */
+public class PcaData extends PcaDataType implements java.io.Serializable
+{
+
+  // ----------------/
+  // - Constructors -/
+  // ----------------/
+
+  public PcaData()
+  {
+    super();
+  }
+
+  // -----------/
+  // - Methods -/
+  // -----------/
+
+  /**
+   * Method isValid.
+   * 
+   * @return true if this object is valid according to the schema
+   */
+  public boolean isValid()
+  {
+    try
+    {
+      validate();
+    } catch (org.exolab.castor.xml.ValidationException vex)
+    {
+      return false;
+    }
+    return true;
+  }
+
+  /**
+   * 
+   * 
+   * @param out
+   * @throws org.exolab.castor.xml.MarshalException
+   *           if object is null or if any SAXException is thrown during
+   *           marshaling
+   * @throws org.exolab.castor.xml.ValidationException
+   *           if this object is an invalid instance according to the schema
+   */
+  public void marshal(final java.io.Writer out)
+          throws org.exolab.castor.xml.MarshalException,
+          org.exolab.castor.xml.ValidationException
+  {
+    Marshaller.marshal(this, out);
+  }
+
+  /**
+   * 
+   * 
+   * @param handler
+   * @throws java.io.IOException
+   *           if an IOException occurs during marshaling
+   * @throws org.exolab.castor.xml.ValidationException
+   *           if this object is an invalid instance according to the schema
+   * @throws org.exolab.castor.xml.MarshalException
+   *           if object is null or if any SAXException is thrown during
+   *           marshaling
+   */
+  public void marshal(final org.xml.sax.ContentHandler handler)
+          throws java.io.IOException,
+          org.exolab.castor.xml.MarshalException,
+          org.exolab.castor.xml.ValidationException
+  {
+    Marshaller.marshal(this, handler);
+  }
+
+  /**
+   * Method unmarshal.
+   * 
+   * @param reader
+   * @throws org.exolab.castor.xml.MarshalException
+   *           if object is null or if any SAXException is thrown during
+   *           marshaling
+   * @throws org.exolab.castor.xml.ValidationException
+   *           if this object is an invalid instance according to the schema
+   * @return the unmarshaled jalview.schemabinding.version2.PcaDataType
+   */
+  public static jalview.schemabinding.version2.PcaDataType unmarshal(
+          final java.io.Reader reader)
+          throws org.exolab.castor.xml.MarshalException,
+          org.exolab.castor.xml.ValidationException
+  {
+    return (jalview.schemabinding.version2.PcaDataType) Unmarshaller
+            .unmarshal(jalview.schemabinding.version2.PcaData.class,
+                    reader);
+  }
+
+  /**
+   * 
+   * 
+   * @throws org.exolab.castor.xml.ValidationException
+   *           if this object is an invalid instance according to the schema
+   */
+  public void validate() throws org.exolab.castor.xml.ValidationException
+  {
+    org.exolab.castor.xml.Validator validator = new org.exolab.castor.xml.Validator();
+    validator.validate(this);
+  }
+
+}
diff --git a/src/jalview/schemabinding/version2/PcaDataType.java b/src/jalview/schemabinding/version2/PcaDataType.java
new file mode 100644 (file)
index 0000000..42f1723
--- /dev/null
@@ -0,0 +1,211 @@
+/*
+ * This class was automatically generated with 
+ * <a href="http://www.castor.org">Castor 1.1</a>, using an XML
+ * Schema.
+ * $Id$
+ */
+
+package jalview.schemabinding.version2;
+
+//---------------------------------/
+//- Imported classes and packages -/
+//---------------------------------/
+
+import org.exolab.castor.xml.Marshaller;
+import org.exolab.castor.xml.Unmarshaller;
+
+/**
+ * The results of a PCA calculation
+ * 
+ * 
+ * @version $Revision$ $Date$
+ */
+public class PcaDataType implements java.io.Serializable
+{
+
+  // --------------------------/
+  // - Class/Member Variables -/
+  // --------------------------/
+
+  /**
+   * Field _pairwiseMatrix.
+   */
+  private jalview.schemabinding.version2.PairwiseMatrix _pairwiseMatrix;
+
+  /**
+   * Field _tridiagonalMatrix.
+   */
+  private jalview.schemabinding.version2.TridiagonalMatrix _tridiagonalMatrix;
+
+  /**
+   * Field _eigenMatrix.
+   */
+  private jalview.schemabinding.version2.EigenMatrix _eigenMatrix;
+
+  // ----------------/
+  // - Constructors -/
+  // ----------------/
+
+  public PcaDataType()
+  {
+    super();
+  }
+
+  // -----------/
+  // - Methods -/
+  // -----------/
+
+  /**
+   * Returns the value of field 'eigenMatrix'.
+   * 
+   * @return the value of field 'EigenMatrix'.
+   */
+  public jalview.schemabinding.version2.EigenMatrix getEigenMatrix()
+  {
+    return this._eigenMatrix;
+  }
+
+  /**
+   * Returns the value of field 'pairwiseMatrix'.
+   * 
+   * @return the value of field 'PairwiseMatrix'.
+   */
+  public jalview.schemabinding.version2.PairwiseMatrix getPairwiseMatrix()
+  {
+    return this._pairwiseMatrix;
+  }
+
+  /**
+   * Returns the value of field 'tridiagonalMatrix'.
+   * 
+   * @return the value of field 'TridiagonalMatrix'.
+   */
+  public jalview.schemabinding.version2.TridiagonalMatrix getTridiagonalMatrix()
+  {
+    return this._tridiagonalMatrix;
+  }
+
+  /**
+   * Method isValid.
+   * 
+   * @return true if this object is valid according to the schema
+   */
+  public boolean isValid()
+  {
+    try
+    {
+      validate();
+    } catch (org.exolab.castor.xml.ValidationException vex)
+    {
+      return false;
+    }
+    return true;
+  }
+
+  /**
+   * 
+   * 
+   * @param out
+   * @throws org.exolab.castor.xml.MarshalException
+   *           if object is null or if any SAXException is thrown during
+   *           marshaling
+   * @throws org.exolab.castor.xml.ValidationException
+   *           if this object is an invalid instance according to the schema
+   */
+  public void marshal(final java.io.Writer out)
+          throws org.exolab.castor.xml.MarshalException,
+          org.exolab.castor.xml.ValidationException
+  {
+    Marshaller.marshal(this, out);
+  }
+
+  /**
+   * 
+   * 
+   * @param handler
+   * @throws java.io.IOException
+   *           if an IOException occurs during marshaling
+   * @throws org.exolab.castor.xml.ValidationException
+   *           if this object is an invalid instance according to the schema
+   * @throws org.exolab.castor.xml.MarshalException
+   *           if object is null or if any SAXException is thrown during
+   *           marshaling
+   */
+  public void marshal(final org.xml.sax.ContentHandler handler)
+          throws java.io.IOException,
+          org.exolab.castor.xml.MarshalException,
+          org.exolab.castor.xml.ValidationException
+  {
+    Marshaller.marshal(this, handler);
+  }
+
+  /**
+   * Sets the value of field 'eigenMatrix'.
+   * 
+   * @param eigenMatrix
+   *          the value of field 'eigenMatrix'.
+   */
+  public void setEigenMatrix(
+          final jalview.schemabinding.version2.EigenMatrix eigenMatrix)
+  {
+    this._eigenMatrix = eigenMatrix;
+  }
+
+  /**
+   * Sets the value of field 'pairwiseMatrix'.
+   * 
+   * @param pairwiseMatrix
+   *          the value of field 'pairwiseMatrix'.
+   */
+  public void setPairwiseMatrix(
+          final jalview.schemabinding.version2.PairwiseMatrix pairwiseMatrix)
+  {
+    this._pairwiseMatrix = pairwiseMatrix;
+  }
+
+  /**
+   * Sets the value of field 'tridiagonalMatrix'.
+   * 
+   * @param tridiagonalMatrix
+   *          the value of field 'tridiagonalMatrix'.
+   */
+  public void setTridiagonalMatrix(
+          final jalview.schemabinding.version2.TridiagonalMatrix tridiagonalMatrix)
+  {
+    this._tridiagonalMatrix = tridiagonalMatrix;
+  }
+
+  /**
+   * Method unmarshal.
+   * 
+   * @param reader
+   * @throws org.exolab.castor.xml.MarshalException
+   *           if object is null or if any SAXException is thrown during
+   *           marshaling
+   * @throws org.exolab.castor.xml.ValidationException
+   *           if this object is an invalid instance according to the schema
+   * @return the unmarshaled jalview.schemabinding.version2.PcaDataType
+   */
+  public static jalview.schemabinding.version2.PcaDataType unmarshal(
+          final java.io.Reader reader)
+          throws org.exolab.castor.xml.MarshalException,
+          org.exolab.castor.xml.ValidationException
+  {
+    return (jalview.schemabinding.version2.PcaDataType) Unmarshaller
+            .unmarshal(jalview.schemabinding.version2.PcaDataType.class,
+                    reader);
+  }
+
+  /**
+   * 
+   * 
+   * @throws org.exolab.castor.xml.ValidationException
+   *           if this object is an invalid instance according to the schema
+   */
+  public void validate() throws org.exolab.castor.xml.ValidationException
+  {
+    org.exolab.castor.xml.Validator validator = new org.exolab.castor.xml.Validator();
+    validator.validate(this);
+  }
+
+}
diff --git a/src/jalview/schemabinding/version2/PcaViewer.java b/src/jalview/schemabinding/version2/PcaViewer.java
new file mode 100644 (file)
index 0000000..3fce2d5
--- /dev/null
@@ -0,0 +1,1403 @@
+/*
+ * This class was automatically generated with 
+ * <a href="http://www.castor.org">Castor 1.1</a>, using an XML
+ * Schema.
+ * $Id$
+ */
+
+package jalview.schemabinding.version2;
+
+//---------------------------------/
+//- Imported classes and packages -/
+//---------------------------------/
+
+import org.exolab.castor.xml.Marshaller;
+import org.exolab.castor.xml.Unmarshaller;
+
+/**
+ * Class PcaViewer.
+ * 
+ * @version $Revision$ $Date$
+ */
+public class PcaViewer implements java.io.Serializable
+{
+
+  // --------------------------/
+  // - Class/Member Variables -/
+  // --------------------------/
+
+  /**
+   * Field _title.
+   */
+  private java.lang.String _title;
+
+  /**
+   * Field _scoreModelName.
+   */
+  private java.lang.String _scoreModelName;
+
+  /**
+   * Field _xDim.
+   */
+  private int _xDim;
+
+  /**
+   * keeps track of state for field: _xDim
+   */
+  private boolean _has_xDim;
+
+  /**
+   * Field _yDim.
+   */
+  private int _yDim;
+
+  /**
+   * keeps track of state for field: _yDim
+   */
+  private boolean _has_yDim;
+
+  /**
+   * Field _zDim.
+   */
+  private int _zDim;
+
+  /**
+   * keeps track of state for field: _zDim
+   */
+  private boolean _has_zDim;
+
+  /**
+   * Field _bgColour.
+   */
+  private int _bgColour;
+
+  /**
+   * keeps track of state for field: _bgColour
+   */
+  private boolean _has_bgColour;
+
+  /**
+   * Field _scaleFactor.
+   */
+  private float _scaleFactor;
+
+  /**
+   * keeps track of state for field: _scaleFactor
+   */
+  private boolean _has_scaleFactor;
+
+  /**
+   * Field _showLabels.
+   */
+  private boolean _showLabels;
+
+  /**
+   * keeps track of state for field: _showLabels
+   */
+  private boolean _has_showLabels;
+
+  /**
+   * Field _linkToAllViews.
+   */
+  private boolean _linkToAllViews;
+
+  /**
+   * keeps track of state for field: _linkToAllViews
+   */
+  private boolean _has_linkToAllViews;
+
+  /**
+   * Field _includeGaps.
+   */
+  private boolean _includeGaps;
+
+  /**
+   * keeps track of state for field: _includeGaps
+   */
+  private boolean _has_includeGaps;
+
+  /**
+   * Field _matchGaps.
+   */
+  private boolean _matchGaps;
+
+  /**
+   * keeps track of state for field: _matchGaps
+   */
+  private boolean _has_matchGaps;
+
+  /**
+   * Field _includeGappedColumns.
+   */
+  private boolean _includeGappedColumns;
+
+  /**
+   * keeps track of state for field: _includeGappedColumns
+   */
+  private boolean _has_includeGappedColumns;
+
+  /**
+   * Field _denominateByShortestLength.
+   */
+  private boolean _denominateByShortestLength;
+
+  /**
+   * keeps track of state for field: _denominateByShortestLength
+   */
+  private boolean _has_denominateByShortestLength;
+
+  /**
+   * Field _width.
+   */
+  private int _width;
+
+  /**
+   * keeps track of state for field: _width
+   */
+  private boolean _has_width;
+
+  /**
+   * Field _height.
+   */
+  private int _height;
+
+  /**
+   * keeps track of state for field: _height
+   */
+  private boolean _has_height;
+
+  /**
+   * Field _xpos.
+   */
+  private int _xpos;
+
+  /**
+   * keeps track of state for field: _xpos
+   */
+  private boolean _has_xpos;
+
+  /**
+   * Field _ypos.
+   */
+  private int _ypos;
+
+  /**
+   * keeps track of state for field: _ypos
+   */
+  private boolean _has_ypos;
+
+  /**
+   * Field _sequencePointList.
+   */
+  private java.util.Vector _sequencePointList;
+
+  /**
+   * endpoints of X, Y and Z axes in that order
+   * 
+   */
+  private java.util.Vector _axisList;
+
+  /**
+   * Field _seqPointMin.
+   */
+  private jalview.schemabinding.version2.SeqPointMin _seqPointMin;
+
+  /**
+   * Field _seqPointMax.
+   */
+  private jalview.schemabinding.version2.SeqPointMax _seqPointMax;
+
+  /**
+   * Field _pcaData.
+   */
+  private jalview.schemabinding.version2.PcaData _pcaData;
+
+  // ----------------/
+  // - Constructors -/
+  // ----------------/
+
+  public PcaViewer()
+  {
+    super();
+    this._sequencePointList = new java.util.Vector();
+    this._axisList = new java.util.Vector();
+  }
+
+  // -----------/
+  // - Methods -/
+  // -----------/
+
+  /**
+   * 
+   * 
+   * @param vAxis
+   * @throws java.lang.IndexOutOfBoundsException
+   *           if the index given is outside the bounds of the collection
+   */
+  public void addAxis(final jalview.schemabinding.version2.Axis vAxis)
+          throws java.lang.IndexOutOfBoundsException
+  {
+    // check for the maximum size
+    if (this._axisList.size() >= 3)
+    {
+      throw new IndexOutOfBoundsException("addAxis has a maximum of 3");
+    }
+
+    this._axisList.addElement(vAxis);
+  }
+
+  /**
+   * 
+   * 
+   * @param index
+   * @param vAxis
+   * @throws java.lang.IndexOutOfBoundsException
+   *           if the index given is outside the bounds of the collection
+   */
+  public void addAxis(final int index,
+          final jalview.schemabinding.version2.Axis vAxis)
+          throws java.lang.IndexOutOfBoundsException
+  {
+    // check for the maximum size
+    if (this._axisList.size() >= 3)
+    {
+      throw new IndexOutOfBoundsException("addAxis has a maximum of 3");
+    }
+
+    this._axisList.add(index, vAxis);
+  }
+
+  /**
+   * 
+   * 
+   * @param vSequencePoint
+   * @throws java.lang.IndexOutOfBoundsException
+   *           if the index given is outside the bounds of the collection
+   */
+  public void addSequencePoint(
+          final jalview.schemabinding.version2.SequencePoint vSequencePoint)
+          throws java.lang.IndexOutOfBoundsException
+  {
+    this._sequencePointList.addElement(vSequencePoint);
+  }
+
+  /**
+   * 
+   * 
+   * @param index
+   * @param vSequencePoint
+   * @throws java.lang.IndexOutOfBoundsException
+   *           if the index given is outside the bounds of the collection
+   */
+  public void addSequencePoint(final int index,
+          final jalview.schemabinding.version2.SequencePoint vSequencePoint)
+          throws java.lang.IndexOutOfBoundsException
+  {
+    this._sequencePointList.add(index, vSequencePoint);
+  }
+
+  /**
+   */
+  public void deleteBgColour()
+  {
+    this._has_bgColour = false;
+  }
+
+  /**
+   */
+  public void deleteDenominateByShortestLength()
+  {
+    this._has_denominateByShortestLength = false;
+  }
+
+  /**
+   */
+  public void deleteHeight()
+  {
+    this._has_height = false;
+  }
+
+  /**
+   */
+  public void deleteIncludeGappedColumns()
+  {
+    this._has_includeGappedColumns = false;
+  }
+
+  /**
+   */
+  public void deleteIncludeGaps()
+  {
+    this._has_includeGaps = false;
+  }
+
+  /**
+   */
+  public void deleteLinkToAllViews()
+  {
+    this._has_linkToAllViews = false;
+  }
+
+  /**
+   */
+  public void deleteMatchGaps()
+  {
+    this._has_matchGaps = false;
+  }
+
+  /**
+   */
+  public void deleteScaleFactor()
+  {
+    this._has_scaleFactor = false;
+  }
+
+  /**
+   */
+  public void deleteShowLabels()
+  {
+    this._has_showLabels = false;
+  }
+
+  /**
+   */
+  public void deleteWidth()
+  {
+    this._has_width = false;
+  }
+
+  /**
+   */
+  public void deleteXDim()
+  {
+    this._has_xDim = false;
+  }
+
+  /**
+   */
+  public void deleteXpos()
+  {
+    this._has_xpos = false;
+  }
+
+  /**
+   */
+  public void deleteYDim()
+  {
+    this._has_yDim = false;
+  }
+
+  /**
+   */
+  public void deleteYpos()
+  {
+    this._has_ypos = false;
+  }
+
+  /**
+   */
+  public void deleteZDim()
+  {
+    this._has_zDim = false;
+  }
+
+  /**
+   * Method enumerateAxis.
+   * 
+   * @return an Enumeration over all jalview.schemabinding.version2.Axis
+   *         elements
+   */
+  public java.util.Enumeration enumerateAxis()
+  {
+    return this._axisList.elements();
+  }
+
+  /**
+   * Method enumerateSequencePoint.
+   * 
+   * @return an Enumeration over all
+   *         jalview.schemabinding.version2.SequencePoint elements
+   */
+  public java.util.Enumeration enumerateSequencePoint()
+  {
+    return this._sequencePointList.elements();
+  }
+
+  /**
+   * Method getAxis.
+   * 
+   * @param index
+   * @throws java.lang.IndexOutOfBoundsException
+   *           if the index given is outside the bounds of the collection
+   * @return the value of the jalview.schemabinding.version2.Axis at the given
+   *         index
+   */
+  public jalview.schemabinding.version2.Axis getAxis(final int index)
+          throws java.lang.IndexOutOfBoundsException
+  {
+    // check bounds for index
+    if (index < 0 || index >= this._axisList.size())
+    {
+      throw new IndexOutOfBoundsException("getAxis: Index value '" + index
+              + "' not in range [0.." + (this._axisList.size() - 1) + "]");
+    }
+
+    return (jalview.schemabinding.version2.Axis) _axisList.get(index);
+  }
+
+  /**
+   * Method getAxis.Returns the contents of the collection in an Array.
+   * <p>
+   * Note: Just in case the collection contents are changing in another thread,
+   * we pass a 0-length Array of the correct type into the API call. This way we
+   * <i>know</i> that the Array returned is of exactly the correct length.
+   * 
+   * @return this collection as an Array
+   */
+  public jalview.schemabinding.version2.Axis[] getAxis()
+  {
+    jalview.schemabinding.version2.Axis[] array = new jalview.schemabinding.version2.Axis[0];
+    return (jalview.schemabinding.version2.Axis[]) this._axisList
+            .toArray(array);
+  }
+
+  /**
+   * Method getAxisCount.
+   * 
+   * @return the size of this collection
+   */
+  public int getAxisCount()
+  {
+    return this._axisList.size();
+  }
+
+  /**
+   * Returns the value of field 'bgColour'.
+   * 
+   * @return the value of field 'BgColour'.
+   */
+  public int getBgColour()
+  {
+    return this._bgColour;
+  }
+
+  /**
+   * Returns the value of field 'denominateByShortestLength'.
+   * 
+   * @return the value of field 'DenominateByShortestLength'.
+   */
+  public boolean getDenominateByShortestLength()
+  {
+    return this._denominateByShortestLength;
+  }
+
+  /**
+   * Returns the value of field 'height'.
+   * 
+   * @return the value of field 'Height'.
+   */
+  public int getHeight()
+  {
+    return this._height;
+  }
+
+  /**
+   * Returns the value of field 'includeGappedColumns'.
+   * 
+   * @return the value of field 'IncludeGappedColumns'.
+   */
+  public boolean getIncludeGappedColumns()
+  {
+    return this._includeGappedColumns;
+  }
+
+  /**
+   * Returns the value of field 'includeGaps'.
+   * 
+   * @return the value of field 'IncludeGaps'.
+   */
+  public boolean getIncludeGaps()
+  {
+    return this._includeGaps;
+  }
+
+  /**
+   * Returns the value of field 'linkToAllViews'.
+   * 
+   * @return the value of field 'LinkToAllViews'.
+   */
+  public boolean getLinkToAllViews()
+  {
+    return this._linkToAllViews;
+  }
+
+  /**
+   * Returns the value of field 'matchGaps'.
+   * 
+   * @return the value of field 'MatchGaps'.
+   */
+  public boolean getMatchGaps()
+  {
+    return this._matchGaps;
+  }
+
+  /**
+   * Returns the value of field 'pcaData'.
+   * 
+   * @return the value of field 'PcaData'.
+   */
+  public jalview.schemabinding.version2.PcaData getPcaData()
+  {
+    return this._pcaData;
+  }
+
+  /**
+   * Returns the value of field 'scaleFactor'.
+   * 
+   * @return the value of field 'ScaleFactor'.
+   */
+  public float getScaleFactor()
+  {
+    return this._scaleFactor;
+  }
+
+  /**
+   * Returns the value of field 'scoreModelName'.
+   * 
+   * @return the value of field 'ScoreModelName'.
+   */
+  public java.lang.String getScoreModelName()
+  {
+    return this._scoreModelName;
+  }
+
+  /**
+   * Returns the value of field 'seqPointMax'.
+   * 
+   * @return the value of field 'SeqPointMax'.
+   */
+  public jalview.schemabinding.version2.SeqPointMax getSeqPointMax()
+  {
+    return this._seqPointMax;
+  }
+
+  /**
+   * Returns the value of field 'seqPointMin'.
+   * 
+   * @return the value of field 'SeqPointMin'.
+   */
+  public jalview.schemabinding.version2.SeqPointMin getSeqPointMin()
+  {
+    return this._seqPointMin;
+  }
+
+  /**
+   * Method getSequencePoint.
+   * 
+   * @param index
+   * @throws java.lang.IndexOutOfBoundsException
+   *           if the index given is outside the bounds of the collection
+   * @return the value of the jalview.schemabinding.version2.SequencePoint at
+   *         the given index
+   */
+  public jalview.schemabinding.version2.SequencePoint getSequencePoint(
+          final int index) throws java.lang.IndexOutOfBoundsException
+  {
+    // check bounds for index
+    if (index < 0 || index >= this._sequencePointList.size())
+    {
+      throw new IndexOutOfBoundsException("getSequencePoint: Index value '"
+              + index + "' not in range [0.."
+              + (this._sequencePointList.size() - 1) + "]");
+    }
+
+    return (jalview.schemabinding.version2.SequencePoint) _sequencePointList
+            .get(index);
+  }
+
+  /**
+   * Method getSequencePoint.Returns the contents of the collection in an Array.
+   * <p>
+   * Note: Just in case the collection contents are changing in another thread,
+   * we pass a 0-length Array of the correct type into the API call. This way we
+   * <i>know</i> that the Array returned is of exactly the correct length.
+   * 
+   * @return this collection as an Array
+   */
+  public jalview.schemabinding.version2.SequencePoint[] getSequencePoint()
+  {
+    jalview.schemabinding.version2.SequencePoint[] array = new jalview.schemabinding.version2.SequencePoint[0];
+    return (jalview.schemabinding.version2.SequencePoint[]) this._sequencePointList
+            .toArray(array);
+  }
+
+  /**
+   * Method getSequencePointCount.
+   * 
+   * @return the size of this collection
+   */
+  public int getSequencePointCount()
+  {
+    return this._sequencePointList.size();
+  }
+
+  /**
+   * Returns the value of field 'showLabels'.
+   * 
+   * @return the value of field 'ShowLabels'.
+   */
+  public boolean getShowLabels()
+  {
+    return this._showLabels;
+  }
+
+  /**
+   * Returns the value of field 'title'.
+   * 
+   * @return the value of field 'Title'.
+   */
+  public java.lang.String getTitle()
+  {
+    return this._title;
+  }
+
+  /**
+   * Returns the value of field 'width'.
+   * 
+   * @return the value of field 'Width'.
+   */
+  public int getWidth()
+  {
+    return this._width;
+  }
+
+  /**
+   * Returns the value of field 'xDim'.
+   * 
+   * @return the value of field 'XDim'.
+   */
+  public int getXDim()
+  {
+    return this._xDim;
+  }
+
+  /**
+   * Returns the value of field 'xpos'.
+   * 
+   * @return the value of field 'Xpos'.
+   */
+  public int getXpos()
+  {
+    return this._xpos;
+  }
+
+  /**
+   * Returns the value of field 'yDim'.
+   * 
+   * @return the value of field 'YDim'.
+   */
+  public int getYDim()
+  {
+    return this._yDim;
+  }
+
+  /**
+   * Returns the value of field 'ypos'.
+   * 
+   * @return the value of field 'Ypos'.
+   */
+  public int getYpos()
+  {
+    return this._ypos;
+  }
+
+  /**
+   * Returns the value of field 'zDim'.
+   * 
+   * @return the value of field 'ZDim'.
+   */
+  public int getZDim()
+  {
+    return this._zDim;
+  }
+
+  /**
+   * Method hasBgColour.
+   * 
+   * @return true if at least one BgColour has been added
+   */
+  public boolean hasBgColour()
+  {
+    return this._has_bgColour;
+  }
+
+  /**
+   * Method hasDenominateByShortestLength.
+   * 
+   * @return true if at least one DenominateByShortestLength has been added
+   */
+  public boolean hasDenominateByShortestLength()
+  {
+    return this._has_denominateByShortestLength;
+  }
+
+  /**
+   * Method hasHeight.
+   * 
+   * @return true if at least one Height has been added
+   */
+  public boolean hasHeight()
+  {
+    return this._has_height;
+  }
+
+  /**
+   * Method hasIncludeGappedColumns.
+   * 
+   * @return true if at least one IncludeGappedColumns has been added
+   */
+  public boolean hasIncludeGappedColumns()
+  {
+    return this._has_includeGappedColumns;
+  }
+
+  /**
+   * Method hasIncludeGaps.
+   * 
+   * @return true if at least one IncludeGaps has been added
+   */
+  public boolean hasIncludeGaps()
+  {
+    return this._has_includeGaps;
+  }
+
+  /**
+   * Method hasLinkToAllViews.
+   * 
+   * @return true if at least one LinkToAllViews has been added
+   */
+  public boolean hasLinkToAllViews()
+  {
+    return this._has_linkToAllViews;
+  }
+
+  /**
+   * Method hasMatchGaps.
+   * 
+   * @return true if at least one MatchGaps has been added
+   */
+  public boolean hasMatchGaps()
+  {
+    return this._has_matchGaps;
+  }
+
+  /**
+   * Method hasScaleFactor.
+   * 
+   * @return true if at least one ScaleFactor has been added
+   */
+  public boolean hasScaleFactor()
+  {
+    return this._has_scaleFactor;
+  }
+
+  /**
+   * Method hasShowLabels.
+   * 
+   * @return true if at least one ShowLabels has been added
+   */
+  public boolean hasShowLabels()
+  {
+    return this._has_showLabels;
+  }
+
+  /**
+   * Method hasWidth.
+   * 
+   * @return true if at least one Width has been added
+   */
+  public boolean hasWidth()
+  {
+    return this._has_width;
+  }
+
+  /**
+   * Method hasXDim.
+   * 
+   * @return true if at least one XDim has been added
+   */
+  public boolean hasXDim()
+  {
+    return this._has_xDim;
+  }
+
+  /**
+   * Method hasXpos.
+   * 
+   * @return true if at least one Xpos has been added
+   */
+  public boolean hasXpos()
+  {
+    return this._has_xpos;
+  }
+
+  /**
+   * Method hasYDim.
+   * 
+   * @return true if at least one YDim has been added
+   */
+  public boolean hasYDim()
+  {
+    return this._has_yDim;
+  }
+
+  /**
+   * Method hasYpos.
+   * 
+   * @return true if at least one Ypos has been added
+   */
+  public boolean hasYpos()
+  {
+    return this._has_ypos;
+  }
+
+  /**
+   * Method hasZDim.
+   * 
+   * @return true if at least one ZDim has been added
+   */
+  public boolean hasZDim()
+  {
+    return this._has_zDim;
+  }
+
+  /**
+   * Returns the value of field 'denominateByShortestLength'.
+   * 
+   * @return the value of field 'DenominateByShortestLength'.
+   */
+  public boolean isDenominateByShortestLength()
+  {
+    return this._denominateByShortestLength;
+  }
+
+  /**
+   * Returns the value of field 'includeGappedColumns'.
+   * 
+   * @return the value of field 'IncludeGappedColumns'.
+   */
+  public boolean isIncludeGappedColumns()
+  {
+    return this._includeGappedColumns;
+  }
+
+  /**
+   * Returns the value of field 'includeGaps'.
+   * 
+   * @return the value of field 'IncludeGaps'.
+   */
+  public boolean isIncludeGaps()
+  {
+    return this._includeGaps;
+  }
+
+  /**
+   * Returns the value of field 'linkToAllViews'.
+   * 
+   * @return the value of field 'LinkToAllViews'.
+   */
+  public boolean isLinkToAllViews()
+  {
+    return this._linkToAllViews;
+  }
+
+  /**
+   * Returns the value of field 'matchGaps'.
+   * 
+   * @return the value of field 'MatchGaps'.
+   */
+  public boolean isMatchGaps()
+  {
+    return this._matchGaps;
+  }
+
+  /**
+   * Returns the value of field 'showLabels'.
+   * 
+   * @return the value of field 'ShowLabels'.
+   */
+  public boolean isShowLabels()
+  {
+    return this._showLabels;
+  }
+
+  /**
+   * Method isValid.
+   * 
+   * @return true if this object is valid according to the schema
+   */
+  public boolean isValid()
+  {
+    try
+    {
+      validate();
+    } catch (org.exolab.castor.xml.ValidationException vex)
+    {
+      return false;
+    }
+    return true;
+  }
+
+  /**
+   * 
+   * 
+   * @param out
+   * @throws org.exolab.castor.xml.MarshalException
+   *           if object is null or if any SAXException is thrown during
+   *           marshaling
+   * @throws org.exolab.castor.xml.ValidationException
+   *           if this object is an invalid instance according to the schema
+   */
+  public void marshal(final java.io.Writer out)
+          throws org.exolab.castor.xml.MarshalException,
+          org.exolab.castor.xml.ValidationException
+  {
+    Marshaller.marshal(this, out);
+  }
+
+  /**
+   * 
+   * 
+   * @param handler
+   * @throws java.io.IOException
+   *           if an IOException occurs during marshaling
+   * @throws org.exolab.castor.xml.ValidationException
+   *           if this object is an invalid instance according to the schema
+   * @throws org.exolab.castor.xml.MarshalException
+   *           if object is null or if any SAXException is thrown during
+   *           marshaling
+   */
+  public void marshal(final org.xml.sax.ContentHandler handler)
+          throws java.io.IOException,
+          org.exolab.castor.xml.MarshalException,
+          org.exolab.castor.xml.ValidationException
+  {
+    Marshaller.marshal(this, handler);
+  }
+
+  /**
+   */
+  public void removeAllAxis()
+  {
+    this._axisList.clear();
+  }
+
+  /**
+   */
+  public void removeAllSequencePoint()
+  {
+    this._sequencePointList.clear();
+  }
+
+  /**
+   * Method removeAxis.
+   * 
+   * @param vAxis
+   * @return true if the object was removed from the collection.
+   */
+  public boolean removeAxis(final jalview.schemabinding.version2.Axis vAxis)
+  {
+    boolean removed = _axisList.remove(vAxis);
+    return removed;
+  }
+
+  /**
+   * Method removeAxisAt.
+   * 
+   * @param index
+   * @return the element removed from the collection
+   */
+  public jalview.schemabinding.version2.Axis removeAxisAt(final int index)
+  {
+    java.lang.Object obj = this._axisList.remove(index);
+    return (jalview.schemabinding.version2.Axis) obj;
+  }
+
+  /**
+   * Method removeSequencePoint.
+   * 
+   * @param vSequencePoint
+   * @return true if the object was removed from the collection.
+   */
+  public boolean removeSequencePoint(
+          final jalview.schemabinding.version2.SequencePoint vSequencePoint)
+  {
+    boolean removed = _sequencePointList.remove(vSequencePoint);
+    return removed;
+  }
+
+  /**
+   * Method removeSequencePointAt.
+   * 
+   * @param index
+   * @return the element removed from the collection
+   */
+  public jalview.schemabinding.version2.SequencePoint removeSequencePointAt(
+          final int index)
+  {
+    java.lang.Object obj = this._sequencePointList.remove(index);
+    return (jalview.schemabinding.version2.SequencePoint) obj;
+  }
+
+  /**
+   * 
+   * 
+   * @param index
+   * @param vAxis
+   * @throws java.lang.IndexOutOfBoundsException
+   *           if the index given is outside the bounds of the collection
+   */
+  public void setAxis(final int index,
+          final jalview.schemabinding.version2.Axis vAxis)
+          throws java.lang.IndexOutOfBoundsException
+  {
+    // check bounds for index
+    if (index < 0 || index >= this._axisList.size())
+    {
+      throw new IndexOutOfBoundsException("setAxis: Index value '" + index
+              + "' not in range [0.." + (this._axisList.size() - 1) + "]");
+    }
+
+    this._axisList.set(index, vAxis);
+  }
+
+  /**
+   * 
+   * 
+   * @param vAxisArray
+   */
+  public void setAxis(
+          final jalview.schemabinding.version2.Axis[] vAxisArray)
+  {
+    // -- copy array
+    _axisList.clear();
+
+    for (int i = 0; i < vAxisArray.length; i++)
+    {
+      this._axisList.add(vAxisArray[i]);
+    }
+  }
+
+  /**
+   * Sets the value of field 'bgColour'.
+   * 
+   * @param bgColour
+   *          the value of field 'bgColour'.
+   */
+  public void setBgColour(final int bgColour)
+  {
+    this._bgColour = bgColour;
+    this._has_bgColour = true;
+  }
+
+  /**
+   * Sets the value of field 'denominateByShortestLength'.
+   * 
+   * @param denominateByShortestLength
+   *          the value of field 'denominateByShortestLength'.
+   */
+  public void setDenominateByShortestLength(
+          final boolean denominateByShortestLength)
+  {
+    this._denominateByShortestLength = denominateByShortestLength;
+    this._has_denominateByShortestLength = true;
+  }
+
+  /**
+   * Sets the value of field 'height'.
+   * 
+   * @param height
+   *          the value of field 'height'.
+   */
+  public void setHeight(final int height)
+  {
+    this._height = height;
+    this._has_height = true;
+  }
+
+  /**
+   * Sets the value of field 'includeGappedColumns'.
+   * 
+   * @param includeGappedColumns
+   *          the value of field 'includeGappedColumns'.
+   */
+  public void setIncludeGappedColumns(final boolean includeGappedColumns)
+  {
+    this._includeGappedColumns = includeGappedColumns;
+    this._has_includeGappedColumns = true;
+  }
+
+  /**
+   * Sets the value of field 'includeGaps'.
+   * 
+   * @param includeGaps
+   *          the value of field 'includeGaps'.
+   */
+  public void setIncludeGaps(final boolean includeGaps)
+  {
+    this._includeGaps = includeGaps;
+    this._has_includeGaps = true;
+  }
+
+  /**
+   * Sets the value of field 'linkToAllViews'.
+   * 
+   * @param linkToAllViews
+   *          the value of field 'linkToAllViews'.
+   */
+  public void setLinkToAllViews(final boolean linkToAllViews)
+  {
+    this._linkToAllViews = linkToAllViews;
+    this._has_linkToAllViews = true;
+  }
+
+  /**
+   * Sets the value of field 'matchGaps'.
+   * 
+   * @param matchGaps
+   *          the value of field 'matchGaps'.
+   */
+  public void setMatchGaps(final boolean matchGaps)
+  {
+    this._matchGaps = matchGaps;
+    this._has_matchGaps = true;
+  }
+
+  /**
+   * Sets the value of field 'pcaData'.
+   * 
+   * @param pcaData
+   *          the value of field 'pcaData'.
+   */
+  public void setPcaData(
+          final jalview.schemabinding.version2.PcaData pcaData)
+  {
+    this._pcaData = pcaData;
+  }
+
+  /**
+   * Sets the value of field 'scaleFactor'.
+   * 
+   * @param scaleFactor
+   *          the value of field 'scaleFactor'.
+   */
+  public void setScaleFactor(final float scaleFactor)
+  {
+    this._scaleFactor = scaleFactor;
+    this._has_scaleFactor = true;
+  }
+
+  /**
+   * Sets the value of field 'scoreModelName'.
+   * 
+   * @param scoreModelName
+   *          the value of field 'scoreModelName'.
+   */
+  public void setScoreModelName(final java.lang.String scoreModelName)
+  {
+    this._scoreModelName = scoreModelName;
+  }
+
+  /**
+   * Sets the value of field 'seqPointMax'.
+   * 
+   * @param seqPointMax
+   *          the value of field 'seqPointMax'.
+   */
+  public void setSeqPointMax(
+          final jalview.schemabinding.version2.SeqPointMax seqPointMax)
+  {
+    this._seqPointMax = seqPointMax;
+  }
+
+  /**
+   * Sets the value of field 'seqPointMin'.
+   * 
+   * @param seqPointMin
+   *          the value of field 'seqPointMin'.
+   */
+  public void setSeqPointMin(
+          final jalview.schemabinding.version2.SeqPointMin seqPointMin)
+  {
+    this._seqPointMin = seqPointMin;
+  }
+
+  /**
+   * 
+   * 
+   * @param index
+   * @param vSequencePoint
+   * @throws java.lang.IndexOutOfBoundsException
+   *           if the index given is outside the bounds of the collection
+   */
+  public void setSequencePoint(final int index,
+          final jalview.schemabinding.version2.SequencePoint vSequencePoint)
+          throws java.lang.IndexOutOfBoundsException
+  {
+    // check bounds for index
+    if (index < 0 || index >= this._sequencePointList.size())
+    {
+      throw new IndexOutOfBoundsException("setSequencePoint: Index value '"
+              + index + "' not in range [0.."
+              + (this._sequencePointList.size() - 1) + "]");
+    }
+
+    this._sequencePointList.set(index, vSequencePoint);
+  }
+
+  /**
+   * 
+   * 
+   * @param vSequencePointArray
+   */
+  public void setSequencePoint(
+          final jalview.schemabinding.version2.SequencePoint[] vSequencePointArray)
+  {
+    // -- copy array
+    _sequencePointList.clear();
+
+    for (int i = 0; i < vSequencePointArray.length; i++)
+    {
+      this._sequencePointList.add(vSequencePointArray[i]);
+    }
+  }
+
+  /**
+   * Sets the value of field 'showLabels'.
+   * 
+   * @param showLabels
+   *          the value of field 'showLabels'.
+   */
+  public void setShowLabels(final boolean showLabels)
+  {
+    this._showLabels = showLabels;
+    this._has_showLabels = true;
+  }
+
+  /**
+   * Sets the value of field 'title'.
+   * 
+   * @param title
+   *          the value of field 'title'.
+   */
+  public void setTitle(final java.lang.String title)
+  {
+    this._title = title;
+  }
+
+  /**
+   * Sets the value of field 'width'.
+   * 
+   * @param width
+   *          the value of field 'width'.
+   */
+  public void setWidth(final int width)
+  {
+    this._width = width;
+    this._has_width = true;
+  }
+
+  /**
+   * Sets the value of field 'xDim'.
+   * 
+   * @param xDim
+   *          the value of field 'xDim'.
+   */
+  public void setXDim(final int xDim)
+  {
+    this._xDim = xDim;
+    this._has_xDim = true;
+  }
+
+  /**
+   * Sets the value of field 'xpos'.
+   * 
+   * @param xpos
+   *          the value of field 'xpos'.
+   */
+  public void setXpos(final int xpos)
+  {
+    this._xpos = xpos;
+    this._has_xpos = true;
+  }
+
+  /**
+   * Sets the value of field 'yDim'.
+   * 
+   * @param yDim
+   *          the value of field 'yDim'.
+   */
+  public void setYDim(final int yDim)
+  {
+    this._yDim = yDim;
+    this._has_yDim = true;
+  }
+
+  /**
+   * Sets the value of field 'ypos'.
+   * 
+   * @param ypos
+   *          the value of field 'ypos'.
+   */
+  public void setYpos(final int ypos)
+  {
+    this._ypos = ypos;
+    this._has_ypos = true;
+  }
+
+  /**
+   * Sets the value of field 'zDim'.
+   * 
+   * @param zDim
+   *          the value of field 'zDim'.
+   */
+  public void setZDim(final int zDim)
+  {
+    this._zDim = zDim;
+    this._has_zDim = true;
+  }
+
+  /**
+   * Method unmarshal.
+   * 
+   * @param reader
+   * @throws org.exolab.castor.xml.MarshalException
+   *           if object is null or if any SAXException is thrown during
+   *           marshaling
+   * @throws org.exolab.castor.xml.ValidationException
+   *           if this object is an invalid instance according to the schema
+   * @return the unmarshaled jalview.schemabinding.version2.PcaViewer
+   */
+  public static jalview.schemabinding.version2.PcaViewer unmarshal(
+          final java.io.Reader reader)
+          throws org.exolab.castor.xml.MarshalException,
+          org.exolab.castor.xml.ValidationException
+  {
+    return (jalview.schemabinding.version2.PcaViewer) Unmarshaller
+            .unmarshal(jalview.schemabinding.version2.PcaViewer.class,
+                    reader);
+  }
+
+  /**
+   * 
+   * 
+   * @throws org.exolab.castor.xml.ValidationException
+   *           if this object is an invalid instance according to the schema
+   */
+  public void validate() throws org.exolab.castor.xml.ValidationException
+  {
+    org.exolab.castor.xml.Validator validator = new org.exolab.castor.xml.Validator();
+    validator.validate(this);
+  }
+
+}
diff --git a/src/jalview/schemabinding/version2/Row.java b/src/jalview/schemabinding/version2/Row.java
new file mode 100644 (file)
index 0000000..d351d1d
--- /dev/null
@@ -0,0 +1,124 @@
+/*
+ * This class was automatically generated with 
+ * <a href="http://www.castor.org">Castor 1.1</a>, using an XML
+ * Schema.
+ * $Id$
+ */
+
+package jalview.schemabinding.version2;
+
+//---------------------------------/
+//- Imported classes and packages -/
+//---------------------------------/
+
+import org.exolab.castor.xml.Marshaller;
+import org.exolab.castor.xml.Unmarshaller;
+
+/**
+ * Class Row.
+ * 
+ * @version $Revision$ $Date$
+ */
+public class Row extends DoubleVector implements java.io.Serializable
+{
+
+  // ----------------/
+  // - Constructors -/
+  // ----------------/
+
+  public Row()
+  {
+    super();
+  }
+
+  // -----------/
+  // - Methods -/
+  // -----------/
+
+  /**
+   * Method isValid.
+   * 
+   * @return true if this object is valid according to the schema
+   */
+  public boolean isValid()
+  {
+    try
+    {
+      validate();
+    } catch (org.exolab.castor.xml.ValidationException vex)
+    {
+      return false;
+    }
+    return true;
+  }
+
+  /**
+   * 
+   * 
+   * @param out
+   * @throws org.exolab.castor.xml.MarshalException
+   *           if object is null or if any SAXException is thrown during
+   *           marshaling
+   * @throws org.exolab.castor.xml.ValidationException
+   *           if this object is an invalid instance according to the schema
+   */
+  public void marshal(final java.io.Writer out)
+          throws org.exolab.castor.xml.MarshalException,
+          org.exolab.castor.xml.ValidationException
+  {
+    Marshaller.marshal(this, out);
+  }
+
+  /**
+   * 
+   * 
+   * @param handler
+   * @throws java.io.IOException
+   *           if an IOException occurs during marshaling
+   * @throws org.exolab.castor.xml.ValidationException
+   *           if this object is an invalid instance according to the schema
+   * @throws org.exolab.castor.xml.MarshalException
+   *           if object is null or if any SAXException is thrown during
+   *           marshaling
+   */
+  public void marshal(final org.xml.sax.ContentHandler handler)
+          throws java.io.IOException,
+          org.exolab.castor.xml.MarshalException,
+          org.exolab.castor.xml.ValidationException
+  {
+    Marshaller.marshal(this, handler);
+  }
+
+  /**
+   * Method unmarshal.
+   * 
+   * @param reader
+   * @throws org.exolab.castor.xml.MarshalException
+   *           if object is null or if any SAXException is thrown during
+   *           marshaling
+   * @throws org.exolab.castor.xml.ValidationException
+   *           if this object is an invalid instance according to the schema
+   * @return the unmarshaled jalview.schemabinding.version2.DoubleVector
+   */
+  public static jalview.schemabinding.version2.DoubleVector unmarshal(
+          final java.io.Reader reader)
+          throws org.exolab.castor.xml.MarshalException,
+          org.exolab.castor.xml.ValidationException
+  {
+    return (jalview.schemabinding.version2.DoubleVector) Unmarshaller
+            .unmarshal(jalview.schemabinding.version2.Row.class, reader);
+  }
+
+  /**
+   * 
+   * 
+   * @throws org.exolab.castor.xml.ValidationException
+   *           if this object is an invalid instance according to the schema
+   */
+  public void validate() throws org.exolab.castor.xml.ValidationException
+  {
+    org.exolab.castor.xml.Validator validator = new org.exolab.castor.xml.Validator();
+    validator.validate(this);
+  }
+
+}
diff --git a/src/jalview/schemabinding/version2/SeqPointMax.java b/src/jalview/schemabinding/version2/SeqPointMax.java
new file mode 100644 (file)
index 0000000..3ca78a2
--- /dev/null
@@ -0,0 +1,276 @@
+/*
+ * This class was automatically generated with 
+ * <a href="http://www.castor.org">Castor 1.1</a>, using an XML
+ * Schema.
+ * $Id$
+ */
+
+package jalview.schemabinding.version2;
+
+//---------------------------------/
+//- Imported classes and packages -/
+//---------------------------------/
+
+import org.exolab.castor.xml.Marshaller;
+import org.exolab.castor.xml.Unmarshaller;
+
+/**
+ * Class SeqPointMax.
+ * 
+ * @version $Revision$ $Date$
+ */
+public class SeqPointMax implements java.io.Serializable
+{
+
+  // --------------------------/
+  // - Class/Member Variables -/
+  // --------------------------/
+
+  /**
+   * Field _xPos.
+   */
+  private float _xPos;
+
+  /**
+   * keeps track of state for field: _xPos
+   */
+  private boolean _has_xPos;
+
+  /**
+   * Field _yPos.
+   */
+  private float _yPos;
+
+  /**
+   * keeps track of state for field: _yPos
+   */
+  private boolean _has_yPos;
+
+  /**
+   * Field _zPos.
+   */
+  private float _zPos;
+
+  /**
+   * keeps track of state for field: _zPos
+   */
+  private boolean _has_zPos;
+
+  // ----------------/
+  // - Constructors -/
+  // ----------------/
+
+  public SeqPointMax()
+  {
+    super();
+  }
+
+  // -----------/
+  // - Methods -/
+  // -----------/
+
+  /**
+   */
+  public void deleteXPos()
+  {
+    this._has_xPos = false;
+  }
+
+  /**
+   */
+  public void deleteYPos()
+  {
+    this._has_yPos = false;
+  }
+
+  /**
+   */
+  public void deleteZPos()
+  {
+    this._has_zPos = false;
+  }
+
+  /**
+   * Returns the value of field 'xPos'.
+   * 
+   * @return the value of field 'XPos'.
+   */
+  public float getXPos()
+  {
+    return this._xPos;
+  }
+
+  /**
+   * Returns the value of field 'yPos'.
+   * 
+   * @return the value of field 'YPos'.
+   */
+  public float getYPos()
+  {
+    return this._yPos;
+  }
+
+  /**
+   * Returns the value of field 'zPos'.
+   * 
+   * @return the value of field 'ZPos'.
+   */
+  public float getZPos()
+  {
+    return this._zPos;
+  }
+
+  /**
+   * Method hasXPos.
+   * 
+   * @return true if at least one XPos has been added
+   */
+  public boolean hasXPos()
+  {
+    return this._has_xPos;
+  }
+
+  /**
+   * Method hasYPos.
+   * 
+   * @return true if at least one YPos has been added
+   */
+  public boolean hasYPos()
+  {
+    return this._has_yPos;
+  }
+
+  /**
+   * Method hasZPos.
+   * 
+   * @return true if at least one ZPos has been added
+   */
+  public boolean hasZPos()
+  {
+    return this._has_zPos;
+  }
+
+  /**
+   * Method isValid.
+   * 
+   * @return true if this object is valid according to the schema
+   */
+  public boolean isValid()
+  {
+    try
+    {
+      validate();
+    } catch (org.exolab.castor.xml.ValidationException vex)
+    {
+      return false;
+    }
+    return true;
+  }
+
+  /**
+   * 
+   * 
+   * @param out
+   * @throws org.exolab.castor.xml.MarshalException
+   *           if object is null or if any SAXException is thrown during
+   *           marshaling
+   * @throws org.exolab.castor.xml.ValidationException
+   *           if this object is an invalid instance according to the schema
+   */
+  public void marshal(final java.io.Writer out)
+          throws org.exolab.castor.xml.MarshalException,
+          org.exolab.castor.xml.ValidationException
+  {
+    Marshaller.marshal(this, out);
+  }
+
+  /**
+   * 
+   * 
+   * @param handler
+   * @throws java.io.IOException
+   *           if an IOException occurs during marshaling
+   * @throws org.exolab.castor.xml.ValidationException
+   *           if this object is an invalid instance according to the schema
+   * @throws org.exolab.castor.xml.MarshalException
+   *           if object is null or if any SAXException is thrown during
+   *           marshaling
+   */
+  public void marshal(final org.xml.sax.ContentHandler handler)
+          throws java.io.IOException,
+          org.exolab.castor.xml.MarshalException,
+          org.exolab.castor.xml.ValidationException
+  {
+    Marshaller.marshal(this, handler);
+  }
+
+  /**
+   * Sets the value of field 'xPos'.
+   * 
+   * @param xPos
+   *          the value of field 'xPos'.
+   */
+  public void setXPos(final float xPos)
+  {
+    this._xPos = xPos;
+    this._has_xPos = true;
+  }
+
+  /**
+   * Sets the value of field 'yPos'.
+   * 
+   * @param yPos
+   *          the value of field 'yPos'.
+   */
+  public void setYPos(final float yPos)
+  {
+    this._yPos = yPos;
+    this._has_yPos = true;
+  }
+
+  /**
+   * Sets the value of field 'zPos'.
+   * 
+   * @param zPos
+   *          the value of field 'zPos'.
+   */
+  public void setZPos(final float zPos)
+  {
+    this._zPos = zPos;
+    this._has_zPos = true;
+  }
+
+  /**
+   * Method unmarshal.
+   * 
+   * @param reader
+   * @throws org.exolab.castor.xml.MarshalException
+   *           if object is null or if any SAXException is thrown during
+   *           marshaling
+   * @throws org.exolab.castor.xml.ValidationException
+   *           if this object is an invalid instance according to the schema
+   * @return the unmarshaled jalview.schemabinding.version2.SeqPointMax
+   */
+  public static jalview.schemabinding.version2.SeqPointMax unmarshal(
+          final java.io.Reader reader)
+          throws org.exolab.castor.xml.MarshalException,
+          org.exolab.castor.xml.ValidationException
+  {
+    return (jalview.schemabinding.version2.SeqPointMax) Unmarshaller
+            .unmarshal(jalview.schemabinding.version2.SeqPointMax.class,
+                    reader);
+  }
+
+  /**
+   * 
+   * 
+   * @throws org.exolab.castor.xml.ValidationException
+   *           if this object is an invalid instance according to the schema
+   */
+  public void validate() throws org.exolab.castor.xml.ValidationException
+  {
+    org.exolab.castor.xml.Validator validator = new org.exolab.castor.xml.Validator();
+    validator.validate(this);
+  }
+
+}
diff --git a/src/jalview/schemabinding/version2/SeqPointMin.java b/src/jalview/schemabinding/version2/SeqPointMin.java
new file mode 100644 (file)
index 0000000..4ce9fab
--- /dev/null
@@ -0,0 +1,276 @@
+/*
+ * This class was automatically generated with 
+ * <a href="http://www.castor.org">Castor 1.1</a>, using an XML
+ * Schema.
+ * $Id$
+ */
+
+package jalview.schemabinding.version2;
+
+//---------------------------------/
+//- Imported classes and packages -/
+//---------------------------------/
+
+import org.exolab.castor.xml.Marshaller;
+import org.exolab.castor.xml.Unmarshaller;
+
+/**
+ * Class SeqPointMin.
+ * 
+ * @version $Revision$ $Date$
+ */
+public class SeqPointMin implements java.io.Serializable
+{
+
+  // --------------------------/
+  // - Class/Member Variables -/
+  // --------------------------/
+
+  /**
+   * Field _xPos.
+   */
+  private float _xPos;
+
+  /**
+   * keeps track of state for field: _xPos
+   */
+  private boolean _has_xPos;
+
+  /**
+   * Field _yPos.
+   */
+  private float _yPos;
+
+  /**
+   * keeps track of state for field: _yPos
+   */
+  private boolean _has_yPos;
+
+  /**
+   * Field _zPos.
+   */
+  private float _zPos;
+
+  /**
+   * keeps track of state for field: _zPos
+   */
+  private boolean _has_zPos;
+
+  // ----------------/
+  // - Constructors -/
+  // ----------------/
+
+  public SeqPointMin()
+  {
+    super();
+  }
+
+  // -----------/
+  // - Methods -/
+  // -----------/
+
+  /**
+   */
+  public void deleteXPos()
+  {
+    this._has_xPos = false;
+  }
+
+  /**
+   */
+  public void deleteYPos()
+  {
+    this._has_yPos = false;
+  }
+
+  /**
+   */
+  public void deleteZPos()
+  {
+    this._has_zPos = false;
+  }
+
+  /**
+   * Returns the value of field 'xPos'.
+   * 
+   * @return the value of field 'XPos'.
+   */
+  public float getXPos()
+  {
+    return this._xPos;
+  }
+
+  /**
+   * Returns the value of field 'yPos'.
+   * 
+   * @return the value of field 'YPos'.
+   */
+  public float getYPos()
+  {
+    return this._yPos;
+  }
+
+  /**
+   * Returns the value of field 'zPos'.
+   * 
+   * @return the value of field 'ZPos'.
+   */
+  public float getZPos()
+  {
+    return this._zPos;
+  }
+
+  /**
+   * Method hasXPos.
+   * 
+   * @return true if at least one XPos has been added
+   */
+  public boolean hasXPos()
+  {
+    return this._has_xPos;
+  }
+
+  /**
+   * Method hasYPos.
+   * 
+   * @return true if at least one YPos has been added
+   */
+  public boolean hasYPos()
+  {
+    return this._has_yPos;
+  }
+
+  /**
+   * Method hasZPos.
+   * 
+   * @return true if at least one ZPos has been added
+   */
+  public boolean hasZPos()
+  {
+    return this._has_zPos;
+  }
+
+  /**
+   * Method isValid.
+   * 
+   * @return true if this object is valid according to the schema
+   */
+  public boolean isValid()
+  {
+    try
+    {
+      validate();
+    } catch (org.exolab.castor.xml.ValidationException vex)
+    {
+      return false;
+    }
+    return true;
+  }
+
+  /**
+   * 
+   * 
+   * @param out
+   * @throws org.exolab.castor.xml.MarshalException
+   *           if object is null or if any SAXException is thrown during
+   *           marshaling
+   * @throws org.exolab.castor.xml.ValidationException
+   *           if this object is an invalid instance according to the schema
+   */
+  public void marshal(final java.io.Writer out)
+          throws org.exolab.castor.xml.MarshalException,
+          org.exolab.castor.xml.ValidationException
+  {
+    Marshaller.marshal(this, out);
+  }
+
+  /**
+   * 
+   * 
+   * @param handler
+   * @throws java.io.IOException
+   *           if an IOException occurs during marshaling
+   * @throws org.exolab.castor.xml.ValidationException
+   *           if this object is an invalid instance according to the schema
+   * @throws org.exolab.castor.xml.MarshalException
+   *           if object is null or if any SAXException is thrown during
+   *           marshaling
+   */
+  public void marshal(final org.xml.sax.ContentHandler handler)
+          throws java.io.IOException,
+          org.exolab.castor.xml.MarshalException,
+          org.exolab.castor.xml.ValidationException
+  {
+    Marshaller.marshal(this, handler);
+  }
+
+  /**
+   * Sets the value of field 'xPos'.
+   * 
+   * @param xPos
+   *          the value of field 'xPos'.
+   */
+  public void setXPos(final float xPos)
+  {
+    this._xPos = xPos;
+    this._has_xPos = true;
+  }
+
+  /**
+   * Sets the value of field 'yPos'.
+   * 
+   * @param yPos
+   *          the value of field 'yPos'.
+   */
+  public void setYPos(final float yPos)
+  {
+    this._yPos = yPos;
+    this._has_yPos = true;
+  }
+
+  /**
+   * Sets the value of field 'zPos'.
+   * 
+   * @param zPos
+   *          the value of field 'zPos'.
+   */
+  public void setZPos(final float zPos)
+  {
+    this._zPos = zPos;
+    this._has_zPos = true;
+  }
+
+  /**
+   * Method unmarshal.
+   * 
+   * @param reader
+   * @throws org.exolab.castor.xml.MarshalException
+   *           if object is null or if any SAXException is thrown during
+   *           marshaling
+   * @throws org.exolab.castor.xml.ValidationException
+   *           if this object is an invalid instance according to the schema
+   * @return the unmarshaled jalview.schemabinding.version2.SeqPointMin
+   */
+  public static jalview.schemabinding.version2.SeqPointMin unmarshal(
+          final java.io.Reader reader)
+          throws org.exolab.castor.xml.MarshalException,
+          org.exolab.castor.xml.ValidationException
+  {
+    return (jalview.schemabinding.version2.SeqPointMin) Unmarshaller
+            .unmarshal(jalview.schemabinding.version2.SeqPointMin.class,
+                    reader);
+  }
+
+  /**
+   * 
+   * 
+   * @throws org.exolab.castor.xml.ValidationException
+   *           if this object is an invalid instance according to the schema
+   */
+  public void validate() throws org.exolab.castor.xml.ValidationException
+  {
+    org.exolab.castor.xml.Validator validator = new org.exolab.castor.xml.Validator();
+    validator.validate(this);
+  }
+
+}
diff --git a/src/jalview/schemabinding/version2/SequencePoint.java b/src/jalview/schemabinding/version2/SequencePoint.java
new file mode 100644 (file)
index 0000000..191c4dd
--- /dev/null
@@ -0,0 +1,302 @@
+/*
+ * This class was automatically generated with 
+ * <a href="http://www.castor.org">Castor 1.1</a>, using an XML
+ * Schema.
+ * $Id$
+ */
+
+package jalview.schemabinding.version2;
+
+//---------------------------------/
+//- Imported classes and packages -/
+//---------------------------------/
+
+import org.exolab.castor.xml.Marshaller;
+import org.exolab.castor.xml.Unmarshaller;
+
+/**
+ * Class SequencePoint.
+ * 
+ * @version $Revision$ $Date$
+ */
+public class SequencePoint implements java.io.Serializable
+{
+
+  // --------------------------/
+  // - Class/Member Variables -/
+  // --------------------------/
+
+  /**
+   * Field _sequenceRef.
+   */
+  private java.lang.String _sequenceRef;
+
+  /**
+   * Field _xPos.
+   */
+  private float _xPos;
+
+  /**
+   * keeps track of state for field: _xPos
+   */
+  private boolean _has_xPos;
+
+  /**
+   * Field _yPos.
+   */
+  private float _yPos;
+
+  /**
+   * keeps track of state for field: _yPos
+   */
+  private boolean _has_yPos;
+
+  /**
+   * Field _zPos.
+   */
+  private float _zPos;
+
+  /**
+   * keeps track of state for field: _zPos
+   */
+  private boolean _has_zPos;
+
+  // ----------------/
+  // - Constructors -/
+  // ----------------/
+
+  public SequencePoint()
+  {
+    super();
+  }
+
+  // -----------/
+  // - Methods -/
+  // -----------/
+
+  /**
+   */
+  public void deleteXPos()
+  {
+    this._has_xPos = false;
+  }
+
+  /**
+   */
+  public void deleteYPos()
+  {
+    this._has_yPos = false;
+  }
+
+  /**
+   */
+  public void deleteZPos()
+  {
+    this._has_zPos = false;
+  }
+
+  /**
+   * Returns the value of field 'sequenceRef'.
+   * 
+   * @return the value of field 'SequenceRef'.
+   */
+  public java.lang.String getSequenceRef()
+  {
+    return this._sequenceRef;
+  }
+
+  /**
+   * Returns the value of field 'xPos'.
+   * 
+   * @return the value of field 'XPos'.
+   */
+  public float getXPos()
+  {
+    return this._xPos;
+  }
+
+  /**
+   * Returns the value of field 'yPos'.
+   * 
+   * @return the value of field 'YPos'.
+   */
+  public float getYPos()
+  {
+    return this._yPos;
+  }
+
+  /**
+   * Returns the value of field 'zPos'.
+   * 
+   * @return the value of field 'ZPos'.
+   */
+  public float getZPos()
+  {
+    return this._zPos;
+  }
+
+  /**
+   * Method hasXPos.
+   * 
+   * @return true if at least one XPos has been added
+   */
+  public boolean hasXPos()
+  {
+    return this._has_xPos;
+  }
+
+  /**
+   * Method hasYPos.
+   * 
+   * @return true if at least one YPos has been added
+   */
+  public boolean hasYPos()
+  {
+    return this._has_yPos;
+  }
+
+  /**
+   * Method hasZPos.
+   * 
+   * @return true if at least one ZPos has been added
+   */
+  public boolean hasZPos()
+  {
+    return this._has_zPos;
+  }
+
+  /**
+   * Method isValid.
+   * 
+   * @return true if this object is valid according to the schema
+   */
+  public boolean isValid()
+  {
+    try
+    {
+      validate();
+    } catch (org.exolab.castor.xml.ValidationException vex)
+    {
+      return false;
+    }
+    return true;
+  }
+
+  /**
+   * 
+   * 
+   * @param out
+   * @throws org.exolab.castor.xml.MarshalException
+   *           if object is null or if any SAXException is thrown during
+   *           marshaling
+   * @throws org.exolab.castor.xml.ValidationException
+   *           if this object is an invalid instance according to the schema
+   */
+  public void marshal(final java.io.Writer out)
+          throws org.exolab.castor.xml.MarshalException,
+          org.exolab.castor.xml.ValidationException
+  {
+    Marshaller.marshal(this, out);
+  }
+
+  /**
+   * 
+   * 
+   * @param handler
+   * @throws java.io.IOException
+   *           if an IOException occurs during marshaling
+   * @throws org.exolab.castor.xml.ValidationException
+   *           if this object is an invalid instance according to the schema
+   * @throws org.exolab.castor.xml.MarshalException
+   *           if object is null or if any SAXException is thrown during
+   *           marshaling
+   */
+  public void marshal(final org.xml.sax.ContentHandler handler)
+          throws java.io.IOException,
+          org.exolab.castor.xml.MarshalException,
+          org.exolab.castor.xml.ValidationException
+  {
+    Marshaller.marshal(this, handler);
+  }
+
+  /**
+   * Sets the value of field 'sequenceRef'.
+   * 
+   * @param sequenceRef
+   *          the value of field 'sequenceRef'.
+   */
+  public void setSequenceRef(final java.lang.String sequenceRef)
+  {
+    this._sequenceRef = sequenceRef;
+  }
+
+  /**
+   * Sets the value of field 'xPos'.
+   * 
+   * @param xPos
+   *          the value of field 'xPos'.
+   */
+  public void setXPos(final float xPos)
+  {
+    this._xPos = xPos;
+    this._has_xPos = true;
+  }
+
+  /**
+   * Sets the value of field 'yPos'.
+   * 
+   * @param yPos
+   *          the value of field 'yPos'.
+   */
+  public void setYPos(final float yPos)
+  {
+    this._yPos = yPos;
+    this._has_yPos = true;
+  }
+
+  /**
+   * Sets the value of field 'zPos'.
+   * 
+   * @param zPos
+   *          the value of field 'zPos'.
+   */
+  public void setZPos(final float zPos)
+  {
+    this._zPos = zPos;
+    this._has_zPos = true;
+  }
+
+  /**
+   * Method unmarshal.
+   * 
+   * @param reader
+   * @throws org.exolab.castor.xml.MarshalException
+   *           if object is null or if any SAXException is thrown during
+   *           marshaling
+   * @throws org.exolab.castor.xml.ValidationException
+   *           if this object is an invalid instance according to the schema
+   * @return the unmarshaled jalview.schemabinding.version2.SequencePoint
+   */
+  public static jalview.schemabinding.version2.SequencePoint unmarshal(
+          final java.io.Reader reader)
+          throws org.exolab.castor.xml.MarshalException,
+          org.exolab.castor.xml.ValidationException
+  {
+    return (jalview.schemabinding.version2.SequencePoint) Unmarshaller
+            .unmarshal(jalview.schemabinding.version2.SequencePoint.class,
+                    reader);
+  }
+
+  /**
+   * 
+   * 
+   * @throws org.exolab.castor.xml.ValidationException
+   *           if this object is an invalid instance according to the schema
+   */
+  public void validate() throws org.exolab.castor.xml.ValidationException
+  {
+    org.exolab.castor.xml.Validator validator = new org.exolab.castor.xml.Validator();
+    validator.validate(this);
+  }
+
+}
diff --git a/src/jalview/schemabinding/version2/TridiagonalMatrix.java b/src/jalview/schemabinding/version2/TridiagonalMatrix.java
new file mode 100644 (file)
index 0000000..b22302c
--- /dev/null
@@ -0,0 +1,127 @@
+/*
+ * This class was automatically generated with 
+ * <a href="http://www.castor.org">Castor 1.1</a>, using an XML
+ * Schema.
+ * $Id$
+ */
+
+package jalview.schemabinding.version2;
+
+//---------------------------------/
+//- Imported classes and packages -/
+//---------------------------------/
+
+import org.exolab.castor.xml.Marshaller;
+import org.exolab.castor.xml.Unmarshaller;
+
+/**
+ * Class TridiagonalMatrix.
+ * 
+ * @version $Revision$ $Date$
+ */
+public class TridiagonalMatrix extends DoubleMatrix
+        implements java.io.Serializable
+{
+
+  // ----------------/
+  // - Constructors -/
+  // ----------------/
+
+  public TridiagonalMatrix()
+  {
+    super();
+  }
+
+  // -----------/
+  // - Methods -/
+  // -----------/
+
+  /**
+   * Method isValid.
+   * 
+   * @return true if this object is valid according to the schema
+   */
+  public boolean isValid()
+  {
+    try
+    {
+      validate();
+    } catch (org.exolab.castor.xml.ValidationException vex)
+    {
+      return false;
+    }
+    return true;
+  }
+
+  /**
+   * 
+   * 
+   * @param out
+   * @throws org.exolab.castor.xml.MarshalException
+   *           if object is null or if any SAXException is thrown during
+   *           marshaling
+   * @throws org.exolab.castor.xml.ValidationException
+   *           if this object is an invalid instance according to the schema
+   */
+  public void marshal(final java.io.Writer out)
+          throws org.exolab.castor.xml.MarshalException,
+          org.exolab.castor.xml.ValidationException
+  {
+    Marshaller.marshal(this, out);
+  }
+
+  /**
+   * 
+   * 
+   * @param handler
+   * @throws java.io.IOException
+   *           if an IOException occurs during marshaling
+   * @throws org.exolab.castor.xml.ValidationException
+   *           if this object is an invalid instance according to the schema
+   * @throws org.exolab.castor.xml.MarshalException
+   *           if object is null or if any SAXException is thrown during
+   *           marshaling
+   */
+  public void marshal(final org.xml.sax.ContentHandler handler)
+          throws java.io.IOException,
+          org.exolab.castor.xml.MarshalException,
+          org.exolab.castor.xml.ValidationException
+  {
+    Marshaller.marshal(this, handler);
+  }
+
+  /**
+   * Method unmarshal.
+   * 
+   * @param reader
+   * @throws org.exolab.castor.xml.MarshalException
+   *           if object is null or if any SAXException is thrown during
+   *           marshaling
+   * @throws org.exolab.castor.xml.ValidationException
+   *           if this object is an invalid instance according to the schema
+   * @return the unmarshaled jalview.schemabinding.version2.DoubleMatrix
+   */
+  public static jalview.schemabinding.version2.DoubleMatrix unmarshal(
+          final java.io.Reader reader)
+          throws org.exolab.castor.xml.MarshalException,
+          org.exolab.castor.xml.ValidationException
+  {
+    return (jalview.schemabinding.version2.DoubleMatrix) Unmarshaller
+            .unmarshal(
+                    jalview.schemabinding.version2.TridiagonalMatrix.class,
+                    reader);
+  }
+
+  /**
+   * 
+   * 
+   * @throws org.exolab.castor.xml.ValidationException
+   *           if this object is an invalid instance according to the schema
+   */
+  public void validate() throws org.exolab.castor.xml.ValidationException
+  {
+    org.exolab.castor.xml.Validator validator = new org.exolab.castor.xml.Validator();
+    validator.validate(this);
+  }
+
+}
diff --git a/src/jalview/schemabinding/version2/descriptors/AxisDescriptor.java b/src/jalview/schemabinding/version2/descriptors/AxisDescriptor.java
new file mode 100644 (file)
index 0000000..16444be
--- /dev/null
@@ -0,0 +1,319 @@
+/*
+ * This class was automatically generated with 
+ * <a href="http://www.castor.org">Castor 1.1</a>, using an XML
+ * Schema.
+ * $Id$
+ */
+
+package jalview.schemabinding.version2.descriptors;
+
+//---------------------------------/
+//- Imported classes and packages -/
+//---------------------------------/
+
+import jalview.schemabinding.version2.Axis;
+
+/**
+ * Class AxisDescriptor.
+ * 
+ * @version $Revision$ $Date$
+ */
+public class AxisDescriptor
+        extends org.exolab.castor.xml.util.XMLClassDescriptorImpl
+{
+
+  // --------------------------/
+  // - Class/Member Variables -/
+  // --------------------------/
+
+  /**
+   * Field _elementDefinition.
+   */
+  private boolean _elementDefinition;
+
+  /**
+   * Field _nsPrefix.
+   */
+  private java.lang.String _nsPrefix;
+
+  /**
+   * Field _nsURI.
+   */
+  private java.lang.String _nsURI;
+
+  /**
+   * Field _xmlName.
+   */
+  private java.lang.String _xmlName;
+
+  // ----------------/
+  // - Constructors -/
+  // ----------------/
+
+  public AxisDescriptor()
+  {
+    super();
+    _nsURI = "www.jalview.org";
+    _xmlName = "axis";
+    _elementDefinition = true;
+    org.exolab.castor.xml.util.XMLFieldDescriptorImpl desc = null;
+    org.exolab.castor.mapping.FieldHandler handler = null;
+    org.exolab.castor.xml.FieldValidator fieldValidator = null;
+    // -- initialize attribute descriptors
+
+    // -- _xPos
+    desc = new org.exolab.castor.xml.util.XMLFieldDescriptorImpl(
+            java.lang.Float.TYPE, "_xPos", "xPos",
+            org.exolab.castor.xml.NodeType.Attribute);
+    handler = new org.exolab.castor.xml.XMLFieldHandler()
+    {
+      public java.lang.Object getValue(java.lang.Object object)
+              throws IllegalStateException
+      {
+        Axis target = (Axis) object;
+        if (!target.hasXPos())
+        {
+          return null;
+        }
+        return new java.lang.Float(target.getXPos());
+      }
+
+      public void setValue(java.lang.Object object, java.lang.Object value)
+              throws IllegalStateException, IllegalArgumentException
+      {
+        try
+        {
+          Axis target = (Axis) object;
+          // if null, use delete method for optional primitives
+          if (value == null)
+          {
+            target.deleteXPos();
+            return;
+          }
+          target.setXPos(((java.lang.Float) value).floatValue());
+        } catch (java.lang.Exception ex)
+        {
+          throw new IllegalStateException(ex.toString());
+        }
+      }
+
+      public java.lang.Object newInstance(java.lang.Object parent)
+      {
+        return null;
+      }
+    };
+    desc.setHandler(handler);
+    desc.setMultivalued(false);
+    addFieldDescriptor(desc);
+
+    // -- validation code for: _xPos
+    fieldValidator = new org.exolab.castor.xml.FieldValidator();
+    { // -- local scope
+      org.exolab.castor.xml.validators.FloatValidator typeValidator;
+      typeValidator = new org.exolab.castor.xml.validators.FloatValidator();
+      fieldValidator.setValidator(typeValidator);
+      typeValidator.setMinInclusive((float) -3.4028235E38);
+      typeValidator.setMaxInclusive((float) 3.4028235E38);
+    }
+    desc.setValidator(fieldValidator);
+    // -- _yPos
+    desc = new org.exolab.castor.xml.util.XMLFieldDescriptorImpl(
+            java.lang.Float.TYPE, "_yPos", "yPos",
+            org.exolab.castor.xml.NodeType.Attribute);
+    handler = new org.exolab.castor.xml.XMLFieldHandler()
+    {
+      public java.lang.Object getValue(java.lang.Object object)
+              throws IllegalStateException
+      {
+        Axis target = (Axis) object;
+        if (!target.hasYPos())
+        {
+          return null;
+        }
+        return new java.lang.Float(target.getYPos());
+      }
+
+      public void setValue(java.lang.Object object, java.lang.Object value)
+              throws IllegalStateException, IllegalArgumentException
+      {
+        try
+        {
+          Axis target = (Axis) object;
+          // if null, use delete method for optional primitives
+          if (value == null)
+          {
+            target.deleteYPos();
+            return;
+          }
+          target.setYPos(((java.lang.Float) value).floatValue());
+        } catch (java.lang.Exception ex)
+        {
+          throw new IllegalStateException(ex.toString());
+        }
+      }
+
+      public java.lang.Object newInstance(java.lang.Object parent)
+      {
+        return null;
+      }
+    };
+    desc.setHandler(handler);
+    desc.setMultivalued(false);
+    addFieldDescriptor(desc);
+
+    // -- validation code for: _yPos
+    fieldValidator = new org.exolab.castor.xml.FieldValidator();
+    { // -- local scope
+      org.exolab.castor.xml.validators.FloatValidator typeValidator;
+      typeValidator = new org.exolab.castor.xml.validators.FloatValidator();
+      fieldValidator.setValidator(typeValidator);
+      typeValidator.setMinInclusive((float) -3.4028235E38);
+      typeValidator.setMaxInclusive((float) 3.4028235E38);
+    }
+    desc.setValidator(fieldValidator);
+    // -- _zPos
+    desc = new org.exolab.castor.xml.util.XMLFieldDescriptorImpl(
+            java.lang.Float.TYPE, "_zPos", "zPos",
+            org.exolab.castor.xml.NodeType.Attribute);
+    handler = new org.exolab.castor.xml.XMLFieldHandler()
+    {
+      public java.lang.Object getValue(java.lang.Object object)
+              throws IllegalStateException
+      {
+        Axis target = (Axis) object;
+        if (!target.hasZPos())
+        {
+          return null;
+        }
+        return new java.lang.Float(target.getZPos());
+      }
+
+      public void setValue(java.lang.Object object, java.lang.Object value)
+              throws IllegalStateException, IllegalArgumentException
+      {
+        try
+        {
+          Axis target = (Axis) object;
+          // if null, use delete method for optional primitives
+          if (value == null)
+          {
+            target.deleteZPos();
+            return;
+          }
+          target.setZPos(((java.lang.Float) value).floatValue());
+        } catch (java.lang.Exception ex)
+        {
+          throw new IllegalStateException(ex.toString());
+        }
+      }
+
+      public java.lang.Object newInstance(java.lang.Object parent)
+      {
+        return null;
+      }
+    };
+    desc.setHandler(handler);
+    desc.setMultivalued(false);
+    addFieldDescriptor(desc);
+
+    // -- validation code for: _zPos
+    fieldValidator = new org.exolab.castor.xml.FieldValidator();
+    { // -- local scope
+      org.exolab.castor.xml.validators.FloatValidator typeValidator;
+      typeValidator = new org.exolab.castor.xml.validators.FloatValidator();
+      fieldValidator.setValidator(typeValidator);
+      typeValidator.setMinInclusive((float) -3.4028235E38);
+      typeValidator.setMaxInclusive((float) 3.4028235E38);
+    }
+    desc.setValidator(fieldValidator);
+    // -- initialize element descriptors
+
+  }
+
+  // -----------/
+  // - Methods -/
+  // -----------/
+
+  /**
+   * Method getAccessMode.
+   * 
+   * @return the access mode specified for this class.
+   */
+  public org.exolab.castor.mapping.AccessMode getAccessMode()
+  {
+    return null;
+  }
+
+  /**
+   * Method getIdentity.
+   * 
+   * @return the identity field, null if this class has no identity.
+   */
+  public org.exolab.castor.mapping.FieldDescriptor getIdentity()
+  {
+    return super.getIdentity();
+  }
+
+  /**
+   * Method getJavaClass.
+   * 
+   * @return the Java class represented by this descriptor.
+   */
+  public java.lang.Class getJavaClass()
+  {
+    return jalview.schemabinding.version2.Axis.class;
+  }
+
+  /**
+   * Method getNameSpacePrefix.
+   * 
+   * @return the namespace prefix to use when marshaling as XML.
+   */
+  public java.lang.String getNameSpacePrefix()
+  {
+    return _nsPrefix;
+  }
+
+  /**
+   * Method getNameSpaceURI.
+   * 
+   * @return the namespace URI used when marshaling and unmarshaling as XML.
+   */
+  public java.lang.String getNameSpaceURI()
+  {
+    return _nsURI;
+  }
+
+  /**
+   * Method getValidator.
+   * 
+   * @return a specific validator for the class described by this
+   *         ClassDescriptor.
+   */
+  public org.exolab.castor.xml.TypeValidator getValidator()
+  {
+    return this;
+  }
+
+  /**
+   * Method getXMLName.
+   * 
+   * @return the XML Name for the Class being described.
+   */
+  public java.lang.String getXMLName()
+  {
+    return _xmlName;
+  }
+
+  /**
+   * Method isElementDefinition.
+   * 
+   * @return true if XML schema definition of this Class is that of a global
+   *         element or element with anonymous type definition.
+   */
+  public boolean isElementDefinition()
+  {
+    return _elementDefinition;
+  }
+
+}
diff --git a/src/jalview/schemabinding/version2/descriptors/DDescriptor.java b/src/jalview/schemabinding/version2/descriptors/DDescriptor.java
new file mode 100644 (file)
index 0000000..6eb4b59
--- /dev/null
@@ -0,0 +1,149 @@
+/*
+ * This class was automatically generated with 
+ * <a href="http://www.castor.org">Castor 1.1</a>, using an XML
+ * Schema.
+ * $Id$
+ */
+
+package jalview.schemabinding.version2.descriptors;
+
+//---------------------------------/
+//- Imported classes and packages -/
+//---------------------------------/
+
+import jalview.schemabinding.version2.D;
+
+/**
+ * Class DDescriptor.
+ * 
+ * @version $Revision$ $Date$
+ */
+public class DDescriptor extends
+        jalview.schemabinding.version2.descriptors.DoubleVectorDescriptor
+{
+
+  // --------------------------/
+  // - Class/Member Variables -/
+  // --------------------------/
+
+  /**
+   * Field _elementDefinition.
+   */
+  private boolean _elementDefinition;
+
+  /**
+   * Field _nsPrefix.
+   */
+  private java.lang.String _nsPrefix;
+
+  /**
+   * Field _nsURI.
+   */
+  private java.lang.String _nsURI;
+
+  /**
+   * Field _xmlName.
+   */
+  private java.lang.String _xmlName;
+
+  // ----------------/
+  // - Constructors -/
+  // ----------------/
+
+  public DDescriptor()
+  {
+    super();
+    setExtendsWithoutFlatten(
+            new jalview.schemabinding.version2.descriptors.DoubleVectorDescriptor());
+    _nsURI = "www.jalview.org";
+    _xmlName = "D";
+    _elementDefinition = true;
+  }
+
+  // -----------/
+  // - Methods -/
+  // -----------/
+
+  /**
+   * Method getAccessMode.
+   * 
+   * @return the access mode specified for this class.
+   */
+  public org.exolab.castor.mapping.AccessMode getAccessMode()
+  {
+    return null;
+  }
+
+  /**
+   * Method getIdentity.
+   * 
+   * @return the identity field, null if this class has no identity.
+   */
+  public org.exolab.castor.mapping.FieldDescriptor getIdentity()
+  {
+    return super.getIdentity();
+  }
+
+  /**
+   * Method getJavaClass.
+   * 
+   * @return the Java class represented by this descriptor.
+   */
+  public java.lang.Class getJavaClass()
+  {
+    return jalview.schemabinding.version2.D.class;
+  }
+
+  /**
+   * Method getNameSpacePrefix.
+   * 
+   * @return the namespace prefix to use when marshaling as XML.
+   */
+  public java.lang.String getNameSpacePrefix()
+  {
+    return _nsPrefix;
+  }
+
+  /**
+   * Method getNameSpaceURI.
+   * 
+   * @return the namespace URI used when marshaling and unmarshaling as XML.
+   */
+  public java.lang.String getNameSpaceURI()
+  {
+    return _nsURI;
+  }
+
+  /**
+   * Method getValidator.
+   * 
+   * @return a specific validator for the class described by this
+   *         ClassDescriptor.
+   */
+  public org.exolab.castor.xml.TypeValidator getValidator()
+  {
+    return this;
+  }
+
+  /**
+   * Method getXMLName.
+   * 
+   * @return the XML Name for the Class being described.
+   */
+  public java.lang.String getXMLName()
+  {
+    return _xmlName;
+  }
+
+  /**
+   * Method isElementDefinition.
+   * 
+   * @return true if XML schema definition of this Class is that of a global
+   *         element or element with anonymous type definition.
+   */
+  public boolean isElementDefinition()
+  {
+    return _elementDefinition;
+  }
+
+}
diff --git a/src/jalview/schemabinding/version2/descriptors/DoubleMatrixDescriptor.java b/src/jalview/schemabinding/version2/descriptors/DoubleMatrixDescriptor.java
new file mode 100644 (file)
index 0000000..f2d197b
--- /dev/null
@@ -0,0 +1,404 @@
+/*
+ * This class was automatically generated with 
+ * <a href="http://www.castor.org">Castor 1.1</a>, using an XML
+ * Schema.
+ * $Id$
+ */
+
+package jalview.schemabinding.version2.descriptors;
+
+//---------------------------------/
+//- Imported classes and packages -/
+//---------------------------------/
+
+import jalview.schemabinding.version2.DoubleMatrix;
+
+/**
+ * Class DoubleMatrixDescriptor.
+ * 
+ * @version $Revision$ $Date$
+ */
+public class DoubleMatrixDescriptor
+        extends org.exolab.castor.xml.util.XMLClassDescriptorImpl
+{
+
+  // --------------------------/
+  // - Class/Member Variables -/
+  // --------------------------/
+
+  /**
+   * Field _elementDefinition.
+   */
+  private boolean _elementDefinition;
+
+  /**
+   * Field _nsPrefix.
+   */
+  private java.lang.String _nsPrefix;
+
+  /**
+   * Field _nsURI.
+   */
+  private java.lang.String _nsURI;
+
+  /**
+   * Field _xmlName.
+   */
+  private java.lang.String _xmlName;
+
+  // ----------------/
+  // - Constructors -/
+  // ----------------/
+
+  public DoubleMatrixDescriptor()
+  {
+    super();
+    _nsURI = "www.jalview.org";
+    _xmlName = "DoubleMatrix";
+    _elementDefinition = false;
+
+    // -- set grouping compositor
+    setCompositorAsSequence();
+    org.exolab.castor.xml.util.XMLFieldDescriptorImpl desc = null;
+    org.exolab.castor.mapping.FieldHandler handler = null;
+    org.exolab.castor.xml.FieldValidator fieldValidator = null;
+    // -- initialize attribute descriptors
+
+    // -- _rows
+    desc = new org.exolab.castor.xml.util.XMLFieldDescriptorImpl(
+            java.lang.Integer.TYPE, "_rows", "rows",
+            org.exolab.castor.xml.NodeType.Attribute);
+    handler = new org.exolab.castor.xml.XMLFieldHandler()
+    {
+      public java.lang.Object getValue(java.lang.Object object)
+              throws IllegalStateException
+      {
+        DoubleMatrix target = (DoubleMatrix) object;
+        if (!target.hasRows())
+        {
+          return null;
+        }
+        return new java.lang.Integer(target.getRows());
+      }
+
+      public void setValue(java.lang.Object object, java.lang.Object value)
+              throws IllegalStateException, IllegalArgumentException
+      {
+        try
+        {
+          DoubleMatrix target = (DoubleMatrix) object;
+          // if null, use delete method for optional primitives
+          if (value == null)
+          {
+            target.deleteRows();
+            return;
+          }
+          target.setRows(((java.lang.Integer) value).intValue());
+        } catch (java.lang.Exception ex)
+        {
+          throw new IllegalStateException(ex.toString());
+        }
+      }
+
+      public java.lang.Object newInstance(java.lang.Object parent)
+      {
+        return null;
+      }
+    };
+    desc.setHandler(handler);
+    desc.setMultivalued(false);
+    addFieldDescriptor(desc);
+
+    // -- validation code for: _rows
+    fieldValidator = new org.exolab.castor.xml.FieldValidator();
+    { // -- local scope
+      org.exolab.castor.xml.validators.IntValidator typeValidator;
+      typeValidator = new org.exolab.castor.xml.validators.IntValidator();
+      fieldValidator.setValidator(typeValidator);
+      typeValidator.setMinInclusive(-2147483648);
+      typeValidator.setMaxInclusive(2147483647);
+    }
+    desc.setValidator(fieldValidator);
+    // -- _columns
+    desc = new org.exolab.castor.xml.util.XMLFieldDescriptorImpl(
+            java.lang.Integer.TYPE, "_columns", "columns",
+            org.exolab.castor.xml.NodeType.Attribute);
+    handler = new org.exolab.castor.xml.XMLFieldHandler()
+    {
+      public java.lang.Object getValue(java.lang.Object object)
+              throws IllegalStateException
+      {
+        DoubleMatrix target = (DoubleMatrix) object;
+        if (!target.hasColumns())
+        {
+          return null;
+        }
+        return new java.lang.Integer(target.getColumns());
+      }
+
+      public void setValue(java.lang.Object object, java.lang.Object value)
+              throws IllegalStateException, IllegalArgumentException
+      {
+        try
+        {
+          DoubleMatrix target = (DoubleMatrix) object;
+          // if null, use delete method for optional primitives
+          if (value == null)
+          {
+            target.deleteColumns();
+            return;
+          }
+          target.setColumns(((java.lang.Integer) value).intValue());
+        } catch (java.lang.Exception ex)
+        {
+          throw new IllegalStateException(ex.toString());
+        }
+      }
+
+      public java.lang.Object newInstance(java.lang.Object parent)
+      {
+        return null;
+      }
+    };
+    desc.setHandler(handler);
+    desc.setMultivalued(false);
+    addFieldDescriptor(desc);
+
+    // -- validation code for: _columns
+    fieldValidator = new org.exolab.castor.xml.FieldValidator();
+    { // -- local scope
+      org.exolab.castor.xml.validators.IntValidator typeValidator;
+      typeValidator = new org.exolab.castor.xml.validators.IntValidator();
+      fieldValidator.setValidator(typeValidator);
+      typeValidator.setMinInclusive(-2147483648);
+      typeValidator.setMaxInclusive(2147483647);
+    }
+    desc.setValidator(fieldValidator);
+    // -- initialize element descriptors
+
+    // -- _rowList
+    desc = new org.exolab.castor.xml.util.XMLFieldDescriptorImpl(
+            jalview.schemabinding.version2.Row.class, "_rowList", "row",
+            org.exolab.castor.xml.NodeType.Element);
+    handler = new org.exolab.castor.xml.XMLFieldHandler()
+    {
+      public java.lang.Object getValue(java.lang.Object object)
+              throws IllegalStateException
+      {
+        DoubleMatrix target = (DoubleMatrix) object;
+        return target.getRow();
+      }
+
+      public void setValue(java.lang.Object object, java.lang.Object value)
+              throws IllegalStateException, IllegalArgumentException
+      {
+        try
+        {
+          DoubleMatrix target = (DoubleMatrix) object;
+          target.addRow((jalview.schemabinding.version2.Row) value);
+        } catch (java.lang.Exception ex)
+        {
+          throw new IllegalStateException(ex.toString());
+        }
+      }
+
+      public void resetValue(Object object)
+              throws IllegalStateException, IllegalArgumentException
+      {
+        try
+        {
+          DoubleMatrix target = (DoubleMatrix) object;
+          target.removeAllRow();
+        } catch (java.lang.Exception ex)
+        {
+          throw new IllegalStateException(ex.toString());
+        }
+      }
+
+      public java.lang.Object newInstance(java.lang.Object parent)
+      {
+        return new jalview.schemabinding.version2.Row();
+      }
+    };
+    desc.setHandler(handler);
+    desc.setNameSpaceURI("www.jalview.org");
+    desc.setMultivalued(true);
+    addFieldDescriptor(desc);
+
+    // -- validation code for: _rowList
+    fieldValidator = new org.exolab.castor.xml.FieldValidator();
+    fieldValidator.setMinOccurs(0);
+    { // -- local scope
+    }
+    desc.setValidator(fieldValidator);
+    // -- _d
+    desc = new org.exolab.castor.xml.util.XMLFieldDescriptorImpl(
+            jalview.schemabinding.version2.D.class, "_d", "D",
+            org.exolab.castor.xml.NodeType.Element);
+    handler = new org.exolab.castor.xml.XMLFieldHandler()
+    {
+      public java.lang.Object getValue(java.lang.Object object)
+              throws IllegalStateException
+      {
+        DoubleMatrix target = (DoubleMatrix) object;
+        return target.getD();
+      }
+
+      public void setValue(java.lang.Object object, java.lang.Object value)
+              throws IllegalStateException, IllegalArgumentException
+      {
+        try
+        {
+          DoubleMatrix target = (DoubleMatrix) object;
+          target.setD((jalview.schemabinding.version2.D) value);
+        } catch (java.lang.Exception ex)
+        {
+          throw new IllegalStateException(ex.toString());
+        }
+      }
+
+      public java.lang.Object newInstance(java.lang.Object parent)
+      {
+        return new jalview.schemabinding.version2.D();
+      }
+    };
+    desc.setHandler(handler);
+    desc.setNameSpaceURI("www.jalview.org");
+    desc.setMultivalued(false);
+    addFieldDescriptor(desc);
+
+    // -- validation code for: _d
+    fieldValidator = new org.exolab.castor.xml.FieldValidator();
+    { // -- local scope
+    }
+    desc.setValidator(fieldValidator);
+    // -- _e
+    desc = new org.exolab.castor.xml.util.XMLFieldDescriptorImpl(
+            jalview.schemabinding.version2.E.class, "_e", "E",
+            org.exolab.castor.xml.NodeType.Element);
+    handler = new org.exolab.castor.xml.XMLFieldHandler()
+    {
+      public java.lang.Object getValue(java.lang.Object object)
+              throws IllegalStateException
+      {
+        DoubleMatrix target = (DoubleMatrix) object;
+        return target.getE();
+      }
+
+      public void setValue(java.lang.Object object, java.lang.Object value)
+              throws IllegalStateException, IllegalArgumentException
+      {
+        try
+        {
+          DoubleMatrix target = (DoubleMatrix) object;
+          target.setE((jalview.schemabinding.version2.E) value);
+        } catch (java.lang.Exception ex)
+        {
+          throw new IllegalStateException(ex.toString());
+        }
+      }
+
+      public java.lang.Object newInstance(java.lang.Object parent)
+      {
+        return new jalview.schemabinding.version2.E();
+      }
+    };
+    desc.setHandler(handler);
+    desc.setNameSpaceURI("www.jalview.org");
+    desc.setMultivalued(false);
+    addFieldDescriptor(desc);
+
+    // -- validation code for: _e
+    fieldValidator = new org.exolab.castor.xml.FieldValidator();
+    { // -- local scope
+    }
+    desc.setValidator(fieldValidator);
+  }
+
+  // -----------/
+  // - Methods -/
+  // -----------/
+
+  /**
+   * Method getAccessMode.
+   * 
+   * @return the access mode specified for this class.
+   */
+  public org.exolab.castor.mapping.AccessMode getAccessMode()
+  {
+    return null;
+  }
+
+  /**
+   * Method getIdentity.
+   * 
+   * @return the identity field, null if this class has no identity.
+   */
+  public org.exolab.castor.mapping.FieldDescriptor getIdentity()
+  {
+    return super.getIdentity();
+  }
+
+  /**
+   * Method getJavaClass.
+   * 
+   * @return the Java class represented by this descriptor.
+   */
+  public java.lang.Class getJavaClass()
+  {
+    return jalview.schemabinding.version2.DoubleMatrix.class;
+  }
+
+  /**
+   * Method getNameSpacePrefix.
+   * 
+   * @return the namespace prefix to use when marshaling as XML.
+   */
+  public java.lang.String getNameSpacePrefix()
+  {
+    return _nsPrefix;
+  }
+
+  /**
+   * Method getNameSpaceURI.
+   * 
+   * @return the namespace URI used when marshaling and unmarshaling as XML.
+   */
+  public java.lang.String getNameSpaceURI()
+  {
+    return _nsURI;
+  }
+
+  /**
+   * Method getValidator.
+   * 
+   * @return a specific validator for the class described by this
+   *         ClassDescriptor.
+   */
+  public org.exolab.castor.xml.TypeValidator getValidator()
+  {
+    return this;
+  }
+
+  /**
+   * Method getXMLName.
+   * 
+   * @return the XML Name for the Class being described.
+   */
+  public java.lang.String getXMLName()
+  {
+    return _xmlName;
+  }
+
+  /**
+   * Method isElementDefinition.
+   * 
+   * @return true if XML schema definition of this Class is that of a global
+   *         element or element with anonymous type definition.
+   */
+  public boolean isElementDefinition()
+  {
+    return _elementDefinition;
+  }
+
+}
diff --git a/src/jalview/schemabinding/version2/descriptors/DoubleVectorDescriptor.java b/src/jalview/schemabinding/version2/descriptors/DoubleVectorDescriptor.java
new file mode 100644 (file)
index 0000000..488ef8c
--- /dev/null
@@ -0,0 +1,223 @@
+/*
+ * This class was automatically generated with 
+ * <a href="http://www.castor.org">Castor 1.1</a>, using an XML
+ * Schema.
+ * $Id$
+ */
+
+package jalview.schemabinding.version2.descriptors;
+
+//---------------------------------/
+//- Imported classes and packages -/
+//---------------------------------/
+
+import jalview.schemabinding.version2.DoubleVector;
+
+/**
+ * Class DoubleVectorDescriptor.
+ * 
+ * @version $Revision$ $Date$
+ */
+public class DoubleVectorDescriptor
+        extends org.exolab.castor.xml.util.XMLClassDescriptorImpl
+{
+
+  // --------------------------/
+  // - Class/Member Variables -/
+  // --------------------------/
+
+  /**
+   * Field _elementDefinition.
+   */
+  private boolean _elementDefinition;
+
+  /**
+   * Field _nsPrefix.
+   */
+  private java.lang.String _nsPrefix;
+
+  /**
+   * Field _nsURI.
+   */
+  private java.lang.String _nsURI;
+
+  /**
+   * Field _xmlName.
+   */
+  private java.lang.String _xmlName;
+
+  // ----------------/
+  // - Constructors -/
+  // ----------------/
+
+  public DoubleVectorDescriptor()
+  {
+    super();
+    _nsURI = "www.jalview.org";
+    _xmlName = "DoubleVector";
+    _elementDefinition = false;
+
+    // -- set grouping compositor
+    setCompositorAsSequence();
+    org.exolab.castor.xml.util.XMLFieldDescriptorImpl desc = null;
+    org.exolab.castor.mapping.FieldHandler handler = null;
+    org.exolab.castor.xml.FieldValidator fieldValidator = null;
+    // -- initialize attribute descriptors
+
+    // -- initialize element descriptors
+
+    // -- _vList
+    desc = new org.exolab.castor.xml.util.XMLFieldDescriptorImpl(
+            java.lang.Double.TYPE, "_vList", "v",
+            org.exolab.castor.xml.NodeType.Element);
+    handler = new org.exolab.castor.xml.XMLFieldHandler()
+    {
+      public java.lang.Object getValue(java.lang.Object object)
+              throws IllegalStateException
+      {
+        DoubleVector target = (DoubleVector) object;
+        return target.getV();
+      }
+
+      public void setValue(java.lang.Object object, java.lang.Object value)
+              throws IllegalStateException, IllegalArgumentException
+      {
+        try
+        {
+          DoubleVector target = (DoubleVector) object;
+          // ignore null values for non optional primitives
+          if (value == null)
+          {
+            return;
+          }
+
+          target.addV(((java.lang.Double) value).doubleValue());
+        } catch (java.lang.Exception ex)
+        {
+          throw new IllegalStateException(ex.toString());
+        }
+      }
+
+      public void resetValue(Object object)
+              throws IllegalStateException, IllegalArgumentException
+      {
+        try
+        {
+          DoubleVector target = (DoubleVector) object;
+          target.removeAllV();
+        } catch (java.lang.Exception ex)
+        {
+          throw new IllegalStateException(ex.toString());
+        }
+      }
+
+      public java.lang.Object newInstance(java.lang.Object parent)
+      {
+        return null;
+      }
+    };
+    desc.setHandler(handler);
+    desc.setNameSpaceURI("www.jalview.org");
+    desc.setMultivalued(true);
+    addFieldDescriptor(desc);
+
+    // -- validation code for: _vList
+    fieldValidator = new org.exolab.castor.xml.FieldValidator();
+    fieldValidator.setMinOccurs(0);
+    { // -- local scope
+      org.exolab.castor.xml.validators.DoubleValidator typeValidator;
+      typeValidator = new org.exolab.castor.xml.validators.DoubleValidator();
+      fieldValidator.setValidator(typeValidator);
+      typeValidator.setMinInclusive(-1.7976931348623157E308);
+      typeValidator.setMaxInclusive(1.7976931348623157E308);
+    }
+    desc.setValidator(fieldValidator);
+  }
+
+  // -----------/
+  // - Methods -/
+  // -----------/
+
+  /**
+   * Method getAccessMode.
+   * 
+   * @return the access mode specified for this class.
+   */
+  public org.exolab.castor.mapping.AccessMode getAccessMode()
+  {
+    return null;
+  }
+
+  /**
+   * Method getIdentity.
+   * 
+   * @return the identity field, null if this class has no identity.
+   */
+  public org.exolab.castor.mapping.FieldDescriptor getIdentity()
+  {
+    return super.getIdentity();
+  }
+
+  /**
+   * Method getJavaClass.
+   * 
+   * @return the Java class represented by this descriptor.
+   */
+  public java.lang.Class getJavaClass()
+  {
+    return jalview.schemabinding.version2.DoubleVector.class;
+  }
+
+  /**
+   * Method getNameSpacePrefix.
+   * 
+   * @return the namespace prefix to use when marshaling as XML.
+   */
+  public java.lang.String getNameSpacePrefix()
+  {
+    return _nsPrefix;
+  }
+
+  /**
+   * Method getNameSpaceURI.
+   * 
+   * @return the namespace URI used when marshaling and unmarshaling as XML.
+   */
+  public java.lang.String getNameSpaceURI()
+  {
+    return _nsURI;
+  }
+
+  /**
+   * Method getValidator.
+   * 
+   * @return a specific validator for the class described by this
+   *         ClassDescriptor.
+   */
+  public org.exolab.castor.xml.TypeValidator getValidator()
+  {
+    return this;
+  }
+
+  /**
+   * Method getXMLName.
+   * 
+   * @return the XML Name for the Class being described.
+   */
+  public java.lang.String getXMLName()
+  {
+    return _xmlName;
+  }
+
+  /**
+   * Method isElementDefinition.
+   * 
+   * @return true if XML schema definition of this Class is that of a global
+   *         element or element with anonymous type definition.
+   */
+  public boolean isElementDefinition()
+  {
+    return _elementDefinition;
+  }
+
+}
diff --git a/src/jalview/schemabinding/version2/descriptors/EDescriptor.java b/src/jalview/schemabinding/version2/descriptors/EDescriptor.java
new file mode 100644 (file)
index 0000000..b35c3ed
--- /dev/null
@@ -0,0 +1,149 @@
+/*
+ * This class was automatically generated with 
+ * <a href="http://www.castor.org">Castor 1.1</a>, using an XML
+ * Schema.
+ * $Id$
+ */
+
+package jalview.schemabinding.version2.descriptors;
+
+//---------------------------------/
+//- Imported classes and packages -/
+//---------------------------------/
+
+import jalview.schemabinding.version2.E;
+
+/**
+ * Class EDescriptor.
+ * 
+ * @version $Revision$ $Date$
+ */
+public class EDescriptor extends
+        jalview.schemabinding.version2.descriptors.DoubleVectorDescriptor
+{
+
+  // --------------------------/
+  // - Class/Member Variables -/
+  // --------------------------/
+
+  /**
+   * Field _elementDefinition.
+   */
+  private boolean _elementDefinition;
+
+  /**
+   * Field _nsPrefix.
+   */
+  private java.lang.String _nsPrefix;
+
+  /**
+   * Field _nsURI.
+   */
+  private java.lang.String _nsURI;
+
+  /**
+   * Field _xmlName.
+   */
+  private java.lang.String _xmlName;
+
+  // ----------------/
+  // - Constructors -/
+  // ----------------/
+
+  public EDescriptor()
+  {
+    super();
+    setExtendsWithoutFlatten(
+            new jalview.schemabinding.version2.descriptors.DoubleVectorDescriptor());
+    _nsURI = "www.jalview.org";
+    _xmlName = "E";
+    _elementDefinition = true;
+  }
+
+  // -----------/
+  // - Methods -/
+  // -----------/
+
+  /**
+   * Method getAccessMode.
+   * 
+   * @return the access mode specified for this class.
+   */
+  public org.exolab.castor.mapping.AccessMode getAccessMode()
+  {
+    return null;
+  }
+
+  /**
+   * Method getIdentity.
+   * 
+   * @return the identity field, null if this class has no identity.
+   */
+  public org.exolab.castor.mapping.FieldDescriptor getIdentity()
+  {
+    return super.getIdentity();
+  }
+
+  /**
+   * Method getJavaClass.
+   * 
+   * @return the Java class represented by this descriptor.
+   */
+  public java.lang.Class getJavaClass()
+  {
+    return jalview.schemabinding.version2.E.class;
+  }
+
+  /**
+   * Method getNameSpacePrefix.
+   * 
+   * @return the namespace prefix to use when marshaling as XML.
+   */
+  public java.lang.String getNameSpacePrefix()
+  {
+    return _nsPrefix;
+  }
+
+  /**
+   * Method getNameSpaceURI.
+   * 
+   * @return the namespace URI used when marshaling and unmarshaling as XML.
+   */
+  public java.lang.String getNameSpaceURI()
+  {
+    return _nsURI;
+  }
+
+  /**
+   * Method getValidator.
+   * 
+   * @return a specific validator for the class described by this
+   *         ClassDescriptor.
+   */
+  public org.exolab.castor.xml.TypeValidator getValidator()
+  {
+    return this;
+  }
+
+  /**
+   * Method getXMLName.
+   * 
+   * @return the XML Name for the Class being described.
+   */
+  public java.lang.String getXMLName()
+  {
+    return _xmlName;
+  }
+
+  /**
+   * Method isElementDefinition.
+   * 
+   * @return true if XML schema definition of this Class is that of a global
+   *         element or element with anonymous type definition.
+   */
+  public boolean isElementDefinition()
+  {
+    return _elementDefinition;
+  }
+
+}
diff --git a/src/jalview/schemabinding/version2/descriptors/EigenMatrixDescriptor.java b/src/jalview/schemabinding/version2/descriptors/EigenMatrixDescriptor.java
new file mode 100644 (file)
index 0000000..92e2414
--- /dev/null
@@ -0,0 +1,149 @@
+/*
+ * This class was automatically generated with 
+ * <a href="http://www.castor.org">Castor 1.1</a>, using an XML
+ * Schema.
+ * $Id$
+ */
+
+package jalview.schemabinding.version2.descriptors;
+
+//---------------------------------/
+//- Imported classes and packages -/
+//---------------------------------/
+
+import jalview.schemabinding.version2.EigenMatrix;
+
+/**
+ * Class EigenMatrixDescriptor.
+ * 
+ * @version $Revision$ $Date$
+ */
+public class EigenMatrixDescriptor extends
+        jalview.schemabinding.version2.descriptors.DoubleMatrixDescriptor
+{
+
+  // --------------------------/
+  // - Class/Member Variables -/
+  // --------------------------/
+
+  /**
+   * Field _elementDefinition.
+   */
+  private boolean _elementDefinition;
+
+  /**
+   * Field _nsPrefix.
+   */
+  private java.lang.String _nsPrefix;
+
+  /**
+   * Field _nsURI.
+   */
+  private java.lang.String _nsURI;
+
+  /**
+   * Field _xmlName.
+   */
+  private java.lang.String _xmlName;
+
+  // ----------------/
+  // - Constructors -/
+  // ----------------/
+
+  public EigenMatrixDescriptor()
+  {
+    super();
+    setExtendsWithoutFlatten(
+            new jalview.schemabinding.version2.descriptors.DoubleMatrixDescriptor());
+    _nsURI = "www.jalview.org";
+    _xmlName = "eigenMatrix";
+    _elementDefinition = true;
+  }
+
+  // -----------/
+  // - Methods -/
+  // -----------/
+
+  /**
+   * Method getAccessMode.
+   * 
+   * @return the access mode specified for this class.
+   */
+  public org.exolab.castor.mapping.AccessMode getAccessMode()
+  {
+    return null;
+  }
+
+  /**
+   * Method getIdentity.
+   * 
+   * @return the identity field, null if this class has no identity.
+   */
+  public org.exolab.castor.mapping.FieldDescriptor getIdentity()
+  {
+    return super.getIdentity();
+  }
+
+  /**
+   * Method getJavaClass.
+   * 
+   * @return the Java class represented by this descriptor.
+   */
+  public java.lang.Class getJavaClass()
+  {
+    return jalview.schemabinding.version2.EigenMatrix.class;
+  }
+
+  /**
+   * Method getNameSpacePrefix.
+   * 
+   * @return the namespace prefix to use when marshaling as XML.
+   */
+  public java.lang.String getNameSpacePrefix()
+  {
+    return _nsPrefix;
+  }
+
+  /**
+   * Method getNameSpaceURI.
+   * 
+   * @return the namespace URI used when marshaling and unmarshaling as XML.
+   */
+  public java.lang.String getNameSpaceURI()
+  {
+    return _nsURI;
+  }
+
+  /**
+   * Method getValidator.
+   * 
+   * @return a specific validator for the class described by this
+   *         ClassDescriptor.
+   */
+  public org.exolab.castor.xml.TypeValidator getValidator()
+  {
+    return this;
+  }
+
+  /**
+   * Method getXMLName.
+   * 
+   * @return the XML Name for the Class being described.
+   */
+  public java.lang.String getXMLName()
+  {
+    return _xmlName;
+  }
+
+  /**
+   * Method isElementDefinition.
+   * 
+   * @return true if XML schema definition of this Class is that of a global
+   *         element or element with anonymous type definition.
+   */
+  public boolean isElementDefinition()
+  {
+    return _elementDefinition;
+  }
+
+}
diff --git a/src/jalview/schemabinding/version2/descriptors/PairwiseMatrixDescriptor.java b/src/jalview/schemabinding/version2/descriptors/PairwiseMatrixDescriptor.java
new file mode 100644 (file)
index 0000000..9520f58
--- /dev/null
@@ -0,0 +1,149 @@
+/*
+ * This class was automatically generated with 
+ * <a href="http://www.castor.org">Castor 1.1</a>, using an XML
+ * Schema.
+ * $Id$
+ */
+
+package jalview.schemabinding.version2.descriptors;
+
+//---------------------------------/
+//- Imported classes and packages -/
+//---------------------------------/
+
+import jalview.schemabinding.version2.PairwiseMatrix;
+
+/**
+ * Class PairwiseMatrixDescriptor.
+ * 
+ * @version $Revision$ $Date$
+ */
+public class PairwiseMatrixDescriptor extends
+        jalview.schemabinding.version2.descriptors.DoubleMatrixDescriptor
+{
+
+  // --------------------------/
+  // - Class/Member Variables -/
+  // --------------------------/
+
+  /**
+   * Field _elementDefinition.
+   */
+  private boolean _elementDefinition;
+
+  /**
+   * Field _nsPrefix.
+   */
+  private java.lang.String _nsPrefix;
+
+  /**
+   * Field _nsURI.
+   */
+  private java.lang.String _nsURI;
+
+  /**
+   * Field _xmlName.
+   */
+  private java.lang.String _xmlName;
+
+  // ----------------/
+  // - Constructors -/
+  // ----------------/
+
+  public PairwiseMatrixDescriptor()
+  {
+    super();
+    setExtendsWithoutFlatten(
+            new jalview.schemabinding.version2.descriptors.DoubleMatrixDescriptor());
+    _nsURI = "www.jalview.org";
+    _xmlName = "pairwiseMatrix";
+    _elementDefinition = true;
+  }
+
+  // -----------/
+  // - Methods -/
+  // -----------/
+
+  /**
+   * Method getAccessMode.
+   * 
+   * @return the access mode specified for this class.
+   */
+  public org.exolab.castor.mapping.AccessMode getAccessMode()
+  {
+    return null;
+  }
+
+  /**
+   * Method getIdentity.
+   * 
+   * @return the identity field, null if this class has no identity.
+   */
+  public org.exolab.castor.mapping.FieldDescriptor getIdentity()
+  {
+    return super.getIdentity();
+  }
+
+  /**
+   * Method getJavaClass.
+   * 
+   * @return the Java class represented by this descriptor.
+   */
+  public java.lang.Class getJavaClass()
+  {
+    return jalview.schemabinding.version2.PairwiseMatrix.class;
+  }
+
+  /**
+   * Method getNameSpacePrefix.
+   * 
+   * @return the namespace prefix to use when marshaling as XML.
+   */
+  public java.lang.String getNameSpacePrefix()
+  {
+    return _nsPrefix;
+  }
+
+  /**
+   * Method getNameSpaceURI.
+   * 
+   * @return the namespace URI used when marshaling and unmarshaling as XML.
+   */
+  public java.lang.String getNameSpaceURI()
+  {
+    return _nsURI;
+  }
+
+  /**
+   * Method getValidator.
+   * 
+   * @return a specific validator for the class described by this
+   *         ClassDescriptor.
+   */
+  public org.exolab.castor.xml.TypeValidator getValidator()
+  {
+    return this;
+  }
+
+  /**
+   * Method getXMLName.
+   * 
+   * @return the XML Name for the Class being described.
+   */
+  public java.lang.String getXMLName()
+  {
+    return _xmlName;
+  }
+
+  /**
+   * Method isElementDefinition.
+   * 
+   * @return true if XML schema definition of this Class is that of a global
+   *         element or element with anonymous type definition.
+   */
+  public boolean isElementDefinition()
+  {
+    return _elementDefinition;
+  }
+
+}
diff --git a/src/jalview/schemabinding/version2/descriptors/PcaDataDescriptor.java b/src/jalview/schemabinding/version2/descriptors/PcaDataDescriptor.java
new file mode 100644 (file)
index 0000000..29b551c
--- /dev/null
@@ -0,0 +1,149 @@
+/*
+ * This class was automatically generated with 
+ * <a href="http://www.castor.org">Castor 1.1</a>, using an XML
+ * Schema.
+ * $Id$
+ */
+
+package jalview.schemabinding.version2.descriptors;
+
+//---------------------------------/
+//- Imported classes and packages -/
+//---------------------------------/
+
+import jalview.schemabinding.version2.PcaData;
+
+/**
+ * Class PcaDataDescriptor.
+ * 
+ * @version $Revision$ $Date$
+ */
+public class PcaDataDescriptor extends
+        jalview.schemabinding.version2.descriptors.PcaDataTypeDescriptor
+{
+
+  // --------------------------/
+  // - Class/Member Variables -/
+  // --------------------------/
+
+  /**
+   * Field _elementDefinition.
+   */
+  private boolean _elementDefinition;
+
+  /**
+   * Field _nsPrefix.
+   */
+  private java.lang.String _nsPrefix;
+
+  /**
+   * Field _nsURI.
+   */
+  private java.lang.String _nsURI;
+
+  /**
+   * Field _xmlName.
+   */
+  private java.lang.String _xmlName;
+
+  // ----------------/
+  // - Constructors -/
+  // ----------------/
+
+  public PcaDataDescriptor()
+  {
+    super();
+    setExtendsWithoutFlatten(
+            new jalview.schemabinding.version2.descriptors.PcaDataTypeDescriptor());
+    _nsURI = "www.jalview.org";
+    _xmlName = "pcaData";
+    _elementDefinition = true;
+  }
+
+  // -----------/
+  // - Methods -/
+  // -----------/
+
+  /**
+   * Method getAccessMode.
+   * 
+   * @return the access mode specified for this class.
+   */
+  public org.exolab.castor.mapping.AccessMode getAccessMode()
+  {
+    return null;
+  }
+
+  /**
+   * Method getIdentity.
+   * 
+   * @return the identity field, null if this class has no identity.
+   */
+  public org.exolab.castor.mapping.FieldDescriptor getIdentity()
+  {
+    return super.getIdentity();
+  }
+
+  /**
+   * Method getJavaClass.
+   * 
+   * @return the Java class represented by this descriptor.
+   */
+  public java.lang.Class getJavaClass()
+  {
+    return jalview.schemabinding.version2.PcaData.class;
+  }
+
+  /**
+   * Method getNameSpacePrefix.
+   * 
+   * @return the namespace prefix to use when marshaling as XML.
+   */
+  public java.lang.String getNameSpacePrefix()
+  {
+    return _nsPrefix;
+  }
+
+  /**
+   * Method getNameSpaceURI.
+   * 
+   * @return the namespace URI used when marshaling and unmarshaling as XML.
+   */
+  public java.lang.String getNameSpaceURI()
+  {
+    return _nsURI;
+  }
+
+  /**
+   * Method getValidator.
+   * 
+   * @return a specific validator for the class described by this
+   *         ClassDescriptor.
+   */
+  public org.exolab.castor.xml.TypeValidator getValidator()
+  {
+    return this;
+  }
+
+  /**
+   * Method getXMLName.
+   * 
+   * @return the XML Name for the Class being described.
+   */
+  public java.lang.String getXMLName()
+  {
+    return _xmlName;
+  }
+
+  /**
+   * Method isElementDefinition.
+   * 
+   * @return true if XML schema definition of this Class is that of a global
+   *         element or element with anonymous type definition.
+   */
+  public boolean isElementDefinition()
+  {
+    return _elementDefinition;
+  }
+
+}
diff --git a/src/jalview/schemabinding/version2/descriptors/PcaDataTypeDescriptor.java b/src/jalview/schemabinding/version2/descriptors/PcaDataTypeDescriptor.java
new file mode 100644 (file)
index 0000000..49ad090
--- /dev/null
@@ -0,0 +1,292 @@
+/*
+ * This class was automatically generated with 
+ * <a href="http://www.castor.org">Castor 1.1</a>, using an XML
+ * Schema.
+ * $Id$
+ */
+
+package jalview.schemabinding.version2.descriptors;
+
+//---------------------------------/
+//- Imported classes and packages -/
+//---------------------------------/
+
+import jalview.schemabinding.version2.PcaDataType;
+
+/**
+ * Class PcaDataTypeDescriptor.
+ * 
+ * @version $Revision$ $Date$
+ */
+public class PcaDataTypeDescriptor
+        extends org.exolab.castor.xml.util.XMLClassDescriptorImpl
+{
+
+  // --------------------------/
+  // - Class/Member Variables -/
+  // --------------------------/
+
+  /**
+   * Field _elementDefinition.
+   */
+  private boolean _elementDefinition;
+
+  /**
+   * Field _nsPrefix.
+   */
+  private java.lang.String _nsPrefix;
+
+  /**
+   * Field _nsURI.
+   */
+  private java.lang.String _nsURI;
+
+  /**
+   * Field _xmlName.
+   */
+  private java.lang.String _xmlName;
+
+  // ----------------/
+  // - Constructors -/
+  // ----------------/
+
+  public PcaDataTypeDescriptor()
+  {
+    super();
+    _nsURI = "www.jalview.org";
+    _xmlName = "PcaDataType";
+    _elementDefinition = false;
+
+    // -- set grouping compositor
+    setCompositorAsSequence();
+    org.exolab.castor.xml.util.XMLFieldDescriptorImpl desc = null;
+    org.exolab.castor.mapping.FieldHandler handler = null;
+    org.exolab.castor.xml.FieldValidator fieldValidator = null;
+    // -- initialize attribute descriptors
+
+    // -- initialize element descriptors
+
+    // -- _pairwiseMatrix
+    desc = new org.exolab.castor.xml.util.XMLFieldDescriptorImpl(
+            jalview.schemabinding.version2.PairwiseMatrix.class,
+            "_pairwiseMatrix", "pairwiseMatrix",
+            org.exolab.castor.xml.NodeType.Element);
+    handler = new org.exolab.castor.xml.XMLFieldHandler()
+    {
+      public java.lang.Object getValue(java.lang.Object object)
+              throws IllegalStateException
+      {
+        PcaDataType target = (PcaDataType) object;
+        return target.getPairwiseMatrix();
+      }
+
+      public void setValue(java.lang.Object object, java.lang.Object value)
+              throws IllegalStateException, IllegalArgumentException
+      {
+        try
+        {
+          PcaDataType target = (PcaDataType) object;
+          target.setPairwiseMatrix(
+                  (jalview.schemabinding.version2.PairwiseMatrix) value);
+        } catch (java.lang.Exception ex)
+        {
+          throw new IllegalStateException(ex.toString());
+        }
+      }
+
+      public java.lang.Object newInstance(java.lang.Object parent)
+      {
+        return new jalview.schemabinding.version2.PairwiseMatrix();
+      }
+    };
+    desc.setHandler(handler);
+    desc.setNameSpaceURI("www.jalview.org");
+    desc.setRequired(true);
+    desc.setMultivalued(false);
+    addFieldDescriptor(desc);
+
+    // -- validation code for: _pairwiseMatrix
+    fieldValidator = new org.exolab.castor.xml.FieldValidator();
+    fieldValidator.setMinOccurs(1);
+    { // -- local scope
+    }
+    desc.setValidator(fieldValidator);
+    // -- _tridiagonalMatrix
+    desc = new org.exolab.castor.xml.util.XMLFieldDescriptorImpl(
+            jalview.schemabinding.version2.TridiagonalMatrix.class,
+            "_tridiagonalMatrix", "tridiagonalMatrix",
+            org.exolab.castor.xml.NodeType.Element);
+    handler = new org.exolab.castor.xml.XMLFieldHandler()
+    {
+      public java.lang.Object getValue(java.lang.Object object)
+              throws IllegalStateException
+      {
+        PcaDataType target = (PcaDataType) object;
+        return target.getTridiagonalMatrix();
+      }
+
+      public void setValue(java.lang.Object object, java.lang.Object value)
+              throws IllegalStateException, IllegalArgumentException
+      {
+        try
+        {
+          PcaDataType target = (PcaDataType) object;
+          target.setTridiagonalMatrix(
+                  (jalview.schemabinding.version2.TridiagonalMatrix) value);
+        } catch (java.lang.Exception ex)
+        {
+          throw new IllegalStateException(ex.toString());
+        }
+      }
+
+      public java.lang.Object newInstance(java.lang.Object parent)
+      {
+        return new jalview.schemabinding.version2.TridiagonalMatrix();
+      }
+    };
+    desc.setHandler(handler);
+    desc.setNameSpaceURI("www.jalview.org");
+    desc.setRequired(true);
+    desc.setMultivalued(false);
+    addFieldDescriptor(desc);
+
+    // -- validation code for: _tridiagonalMatrix
+    fieldValidator = new org.exolab.castor.xml.FieldValidator();
+    fieldValidator.setMinOccurs(1);
+    { // -- local scope
+    }
+    desc.setValidator(fieldValidator);
+    // -- _eigenMatrix
+    desc = new org.exolab.castor.xml.util.XMLFieldDescriptorImpl(
+            jalview.schemabinding.version2.EigenMatrix.class,
+            "_eigenMatrix", "eigenMatrix",
+            org.exolab.castor.xml.NodeType.Element);
+    handler = new org.exolab.castor.xml.XMLFieldHandler()
+    {
+      public java.lang.Object getValue(java.lang.Object object)
+              throws IllegalStateException
+      {
+        PcaDataType target = (PcaDataType) object;
+        return target.getEigenMatrix();
+      }
+
+      public void setValue(java.lang.Object object, java.lang.Object value)
+              throws IllegalStateException, IllegalArgumentException
+      {
+        try
+        {
+          PcaDataType target = (PcaDataType) object;
+          target.setEigenMatrix(
+                  (jalview.schemabinding.version2.EigenMatrix) value);
+        } catch (java.lang.Exception ex)
+        {
+          throw new IllegalStateException(ex.toString());
+        }
+      }
+
+      public java.lang.Object newInstance(java.lang.Object parent)
+      {
+        return new jalview.schemabinding.version2.EigenMatrix();
+      }
+    };
+    desc.setHandler(handler);
+    desc.setNameSpaceURI("www.jalview.org");
+    desc.setRequired(true);
+    desc.setMultivalued(false);
+    addFieldDescriptor(desc);
+
+    // -- validation code for: _eigenMatrix
+    fieldValidator = new org.exolab.castor.xml.FieldValidator();
+    fieldValidator.setMinOccurs(1);
+    { // -- local scope
+    }
+    desc.setValidator(fieldValidator);
+  }
+
+  // -----------/
+  // - Methods -/
+  // -----------/
+
+  /**
+   * Method getAccessMode.
+   * 
+   * @return the access mode specified for this class.
+   */
+  public org.exolab.castor.mapping.AccessMode getAccessMode()
+  {
+    return null;
+  }
+
+  /**
+   * Method getIdentity.
+   * 
+   * @return the identity field, null if this class has no identity.
+   */
+  public org.exolab.castor.mapping.FieldDescriptor getIdentity()
+  {
+    return super.getIdentity();
+  }
+
+  /**
+   * Method getJavaClass.
+   * 
+   * @return the Java class represented by this descriptor.
+   */
+  public java.lang.Class getJavaClass()
+  {
+    return jalview.schemabinding.version2.PcaDataType.class;
+  }
+
+  /**
+   * Method getNameSpacePrefix.
+   * 
+   * @return the namespace prefix to use when marshaling as XML.
+   */
+  public java.lang.String getNameSpacePrefix()
+  {
+    return _nsPrefix;
+  }
+
+  /**
+   * Method getNameSpaceURI.
+   * 
+   * @return the namespace URI used when marshaling and unmarshaling as XML.
+   */
+  public java.lang.String getNameSpaceURI()
+  {
+    return _nsURI;
+  }
+
+  /**
+   * Method getValidator.
+   * 
+   * @return a specific validator for the class described by this
+   *         ClassDescriptor.
+   */
+  public org.exolab.castor.xml.TypeValidator getValidator()
+  {
+    return this;
+  }
+
+  /**
+   * Method getXMLName.
+   * 
+   * @return the XML Name for the Class being described.
+   */
+  public java.lang.String getXMLName()
+  {
+    return _xmlName;
+  }
+
+  /**
+   * Method isElementDefinition.
+   * 
+   * @return true if XML schema definition of this Class is that of a global
+   *         element or element with anonymous type definition.
+   */
+  public boolean isElementDefinition()
+  {
+    return _elementDefinition;
+  }
+
+}
diff --git a/src/jalview/schemabinding/version2/descriptors/PcaViewerDescriptor.java b/src/jalview/schemabinding/version2/descriptors/PcaViewerDescriptor.java
new file mode 100644 (file)
index 0000000..630ae9a
--- /dev/null
@@ -0,0 +1,1320 @@
+/*
+ * This class was automatically generated with 
+ * <a href="http://www.castor.org">Castor 1.1</a>, using an XML
+ * Schema.
+ * $Id$
+ */
+
+package jalview.schemabinding.version2.descriptors;
+
+//---------------------------------/
+//- Imported classes and packages -/
+//---------------------------------/
+
+import jalview.schemabinding.version2.PcaViewer;
+
+/**
+ * Class PcaViewerDescriptor.
+ * 
+ * @version $Revision$ $Date$
+ */
+public class PcaViewerDescriptor
+        extends org.exolab.castor.xml.util.XMLClassDescriptorImpl
+{
+
+  // --------------------------/
+  // - Class/Member Variables -/
+  // --------------------------/
+
+  /**
+   * Field _elementDefinition.
+   */
+  private boolean _elementDefinition;
+
+  /**
+   * Field _nsPrefix.
+   */
+  private java.lang.String _nsPrefix;
+
+  /**
+   * Field _nsURI.
+   */
+  private java.lang.String _nsURI;
+
+  /**
+   * Field _xmlName.
+   */
+  private java.lang.String _xmlName;
+
+  // ----------------/
+  // - Constructors -/
+  // ----------------/
+
+  public PcaViewerDescriptor()
+  {
+    super();
+    _nsURI = "www.jalview.org";
+    _xmlName = "PcaViewer";
+    _elementDefinition = true;
+
+    // -- set grouping compositor
+    setCompositorAsSequence();
+    org.exolab.castor.xml.util.XMLFieldDescriptorImpl desc = null;
+    org.exolab.castor.mapping.FieldHandler handler = null;
+    org.exolab.castor.xml.FieldValidator fieldValidator = null;
+    // -- initialize attribute descriptors
+
+    // -- _title
+    desc = new org.exolab.castor.xml.util.XMLFieldDescriptorImpl(
+            java.lang.String.class, "_title", "title",
+            org.exolab.castor.xml.NodeType.Attribute);
+    desc.setImmutable(true);
+    handler = new org.exolab.castor.xml.XMLFieldHandler()
+    {
+      public java.lang.Object getValue(java.lang.Object object)
+              throws IllegalStateException
+      {
+        PcaViewer target = (PcaViewer) object;
+        return target.getTitle();
+      }
+
+      public void setValue(java.lang.Object object, java.lang.Object value)
+              throws IllegalStateException, IllegalArgumentException
+      {
+        try
+        {
+          PcaViewer target = (PcaViewer) object;
+          target.setTitle((java.lang.String) value);
+        } catch (java.lang.Exception ex)
+        {
+          throw new IllegalStateException(ex.toString());
+        }
+      }
+
+      public java.lang.Object newInstance(java.lang.Object parent)
+      {
+        return null;
+      }
+    };
+    desc.setHandler(handler);
+    desc.setMultivalued(false);
+    addFieldDescriptor(desc);
+
+    // -- validation code for: _title
+    fieldValidator = new org.exolab.castor.xml.FieldValidator();
+    { // -- local scope
+      org.exolab.castor.xml.validators.StringValidator typeValidator;
+      typeValidator = new org.exolab.castor.xml.validators.StringValidator();
+      fieldValidator.setValidator(typeValidator);
+      typeValidator.setWhiteSpace("preserve");
+    }
+    desc.setValidator(fieldValidator);
+    // -- _scoreModelName
+    desc = new org.exolab.castor.xml.util.XMLFieldDescriptorImpl(
+            java.lang.String.class, "_scoreModelName", "scoreModelName",
+            org.exolab.castor.xml.NodeType.Attribute);
+    desc.setImmutable(true);
+    handler = new org.exolab.castor.xml.XMLFieldHandler()
+    {
+      public java.lang.Object getValue(java.lang.Object object)
+              throws IllegalStateException
+      {
+        PcaViewer target = (PcaViewer) object;
+        return target.getScoreModelName();
+      }
+
+      public void setValue(java.lang.Object object, java.lang.Object value)
+              throws IllegalStateException, IllegalArgumentException
+      {
+        try
+        {
+          PcaViewer target = (PcaViewer) object;
+          target.setScoreModelName((java.lang.String) value);
+        } catch (java.lang.Exception ex)
+        {
+          throw new IllegalStateException(ex.toString());
+        }
+      }
+
+      public java.lang.Object newInstance(java.lang.Object parent)
+      {
+        return null;
+      }
+    };
+    desc.setHandler(handler);
+    desc.setMultivalued(false);
+    addFieldDescriptor(desc);
+
+    // -- validation code for: _scoreModelName
+    fieldValidator = new org.exolab.castor.xml.FieldValidator();
+    { // -- local scope
+      org.exolab.castor.xml.validators.StringValidator typeValidator;
+      typeValidator = new org.exolab.castor.xml.validators.StringValidator();
+      fieldValidator.setValidator(typeValidator);
+      typeValidator.setWhiteSpace("preserve");
+    }
+    desc.setValidator(fieldValidator);
+    // -- _xDim
+    desc = new org.exolab.castor.xml.util.XMLFieldDescriptorImpl(
+            java.lang.Integer.TYPE, "_xDim", "xDim",
+            org.exolab.castor.xml.NodeType.Attribute);
+    handler = new org.exolab.castor.xml.XMLFieldHandler()
+    {
+      public java.lang.Object getValue(java.lang.Object object)
+              throws IllegalStateException
+      {
+        PcaViewer target = (PcaViewer) object;
+        if (!target.hasXDim())
+        {
+          return null;
+        }
+        return new java.lang.Integer(target.getXDim());
+      }
+
+      public void setValue(java.lang.Object object, java.lang.Object value)
+              throws IllegalStateException, IllegalArgumentException
+      {
+        try
+        {
+          PcaViewer target = (PcaViewer) object;
+          // if null, use delete method for optional primitives
+          if (value == null)
+          {
+            target.deleteXDim();
+            return;
+          }
+          target.setXDim(((java.lang.Integer) value).intValue());
+        } catch (java.lang.Exception ex)
+        {
+          throw new IllegalStateException(ex.toString());
+        }
+      }
+
+      public java.lang.Object newInstance(java.lang.Object parent)
+      {
+        return null;
+      }
+    };
+    desc.setHandler(handler);
+    desc.setMultivalued(false);
+    addFieldDescriptor(desc);
+
+    // -- validation code for: _xDim
+    fieldValidator = new org.exolab.castor.xml.FieldValidator();
+    { // -- local scope
+      org.exolab.castor.xml.validators.IntValidator typeValidator;
+      typeValidator = new org.exolab.castor.xml.validators.IntValidator();
+      fieldValidator.setValidator(typeValidator);
+      typeValidator.setMinInclusive(-2147483648);
+      typeValidator.setMaxInclusive(2147483647);
+    }
+    desc.setValidator(fieldValidator);
+    // -- _yDim
+    desc = new org.exolab.castor.xml.util.XMLFieldDescriptorImpl(
+            java.lang.Integer.TYPE, "_yDim", "yDim",
+            org.exolab.castor.xml.NodeType.Attribute);
+    handler = new org.exolab.castor.xml.XMLFieldHandler()
+    {
+      public java.lang.Object getValue(java.lang.Object object)
+              throws IllegalStateException
+      {
+        PcaViewer target = (PcaViewer) object;
+        if (!target.hasYDim())
+        {
+          return null;
+        }
+        return new java.lang.Integer(target.getYDim());
+      }
+
+      public void setValue(java.lang.Object object, java.lang.Object value)
+              throws IllegalStateException, IllegalArgumentException
+      {
+        try
+        {
+          PcaViewer target = (PcaViewer) object;
+          // if null, use delete method for optional primitives
+          if (value == null)
+          {
+            target.deleteYDim();
+            return;
+          }
+          target.setYDim(((java.lang.Integer) value).intValue());
+        } catch (java.lang.Exception ex)
+        {
+          throw new IllegalStateException(ex.toString());
+        }
+      }
+
+      public java.lang.Object newInstance(java.lang.Object parent)
+      {
+        return null;
+      }
+    };
+    desc.setHandler(handler);
+    desc.setMultivalued(false);
+    addFieldDescriptor(desc);
+
+    // -- validation code for: _yDim
+    fieldValidator = new org.exolab.castor.xml.FieldValidator();
+    { // -- local scope
+      org.exolab.castor.xml.validators.IntValidator typeValidator;
+      typeValidator = new org.exolab.castor.xml.validators.IntValidator();
+      fieldValidator.setValidator(typeValidator);
+      typeValidator.setMinInclusive(-2147483648);
+      typeValidator.setMaxInclusive(2147483647);
+    }
+    desc.setValidator(fieldValidator);
+    // -- _zDim
+    desc = new org.exolab.castor.xml.util.XMLFieldDescriptorImpl(
+            java.lang.Integer.TYPE, "_zDim", "zDim",
+            org.exolab.castor.xml.NodeType.Attribute);
+    handler = new org.exolab.castor.xml.XMLFieldHandler()
+    {
+      public java.lang.Object getValue(java.lang.Object object)
+              throws IllegalStateException
+      {
+        PcaViewer target = (PcaViewer) object;
+        if (!target.hasZDim())
+        {
+          return null;
+        }
+        return new java.lang.Integer(target.getZDim());
+      }
+
+      public void setValue(java.lang.Object object, java.lang.Object value)
+              throws IllegalStateException, IllegalArgumentException
+      {
+        try
+        {
+          PcaViewer target = (PcaViewer) object;
+          // if null, use delete method for optional primitives
+          if (value == null)
+          {
+            target.deleteZDim();
+            return;
+          }
+          target.setZDim(((java.lang.Integer) value).intValue());
+        } catch (java.lang.Exception ex)
+        {
+          throw new IllegalStateException(ex.toString());
+        }
+      }
+
+      public java.lang.Object newInstance(java.lang.Object parent)
+      {
+        return null;
+      }
+    };
+    desc.setHandler(handler);
+    desc.setMultivalued(false);
+    addFieldDescriptor(desc);
+
+    // -- validation code for: _zDim
+    fieldValidator = new org.exolab.castor.xml.FieldValidator();
+    { // -- local scope
+      org.exolab.castor.xml.validators.IntValidator typeValidator;
+      typeValidator = new org.exolab.castor.xml.validators.IntValidator();
+      fieldValidator.setValidator(typeValidator);
+      typeValidator.setMinInclusive(-2147483648);
+      typeValidator.setMaxInclusive(2147483647);
+    }
+    desc.setValidator(fieldValidator);
+    // -- _bgColour
+    desc = new org.exolab.castor.xml.util.XMLFieldDescriptorImpl(
+            java.lang.Integer.TYPE, "_bgColour", "bgColour",
+            org.exolab.castor.xml.NodeType.Attribute);
+    handler = new org.exolab.castor.xml.XMLFieldHandler()
+    {
+      public java.lang.Object getValue(java.lang.Object object)
+              throws IllegalStateException
+      {
+        PcaViewer target = (PcaViewer) object;
+        if (!target.hasBgColour())
+        {
+          return null;
+        }
+        return new java.lang.Integer(target.getBgColour());
+      }
+
+      public void setValue(java.lang.Object object, java.lang.Object value)
+              throws IllegalStateException, IllegalArgumentException
+      {
+        try
+        {
+          PcaViewer target = (PcaViewer) object;
+          // if null, use delete method for optional primitives
+          if (value == null)
+          {
+            target.deleteBgColour();
+            return;
+          }
+          target.setBgColour(((java.lang.Integer) value).intValue());
+        } catch (java.lang.Exception ex)
+        {
+          throw new IllegalStateException(ex.toString());
+        }
+      }
+
+      public java.lang.Object newInstance(java.lang.Object parent)
+      {
+        return null;
+      }
+    };
+    desc.setHandler(handler);
+    desc.setMultivalued(false);
+    addFieldDescriptor(desc);
+
+    // -- validation code for: _bgColour
+    fieldValidator = new org.exolab.castor.xml.FieldValidator();
+    { // -- local scope
+      org.exolab.castor.xml.validators.IntValidator typeValidator;
+      typeValidator = new org.exolab.castor.xml.validators.IntValidator();
+      fieldValidator.setValidator(typeValidator);
+      typeValidator.setMinInclusive(-2147483648);
+      typeValidator.setMaxInclusive(2147483647);
+    }
+    desc.setValidator(fieldValidator);
+    // -- _scaleFactor
+    desc = new org.exolab.castor.xml.util.XMLFieldDescriptorImpl(
+            java.lang.Float.TYPE, "_scaleFactor", "scaleFactor",
+            org.exolab.castor.xml.NodeType.Attribute);
+    handler = new org.exolab.castor.xml.XMLFieldHandler()
+    {
+      public java.lang.Object getValue(java.lang.Object object)
+              throws IllegalStateException
+      {
+        PcaViewer target = (PcaViewer) object;
+        if (!target.hasScaleFactor())
+        {
+          return null;
+        }
+        return new java.lang.Float(target.getScaleFactor());
+      }
+
+      public void setValue(java.lang.Object object, java.lang.Object value)
+              throws IllegalStateException, IllegalArgumentException
+      {
+        try
+        {
+          PcaViewer target = (PcaViewer) object;
+          // if null, use delete method for optional primitives
+          if (value == null)
+          {
+            target.deleteScaleFactor();
+            return;
+          }
+          target.setScaleFactor(((java.lang.Float) value).floatValue());
+        } catch (java.lang.Exception ex)
+        {
+          throw new IllegalStateException(ex.toString());
+        }
+      }
+
+      public java.lang.Object newInstance(java.lang.Object parent)
+      {
+        return null;
+      }
+    };
+    desc.setHandler(handler);
+    desc.setMultivalued(false);
+    addFieldDescriptor(desc);
+
+    // -- validation code for: _scaleFactor
+    fieldValidator = new org.exolab.castor.xml.FieldValidator();
+    { // -- local scope
+      org.exolab.castor.xml.validators.FloatValidator typeValidator;
+      typeValidator = new org.exolab.castor.xml.validators.FloatValidator();
+      fieldValidator.setValidator(typeValidator);
+      typeValidator.setMinInclusive((float) -3.4028235E38);
+      typeValidator.setMaxInclusive((float) 3.4028235E38);
+    }
+    desc.setValidator(fieldValidator);
+    // -- _showLabels
+    desc = new org.exolab.castor.xml.util.XMLFieldDescriptorImpl(
+            java.lang.Boolean.TYPE, "_showLabels", "showLabels",
+            org.exolab.castor.xml.NodeType.Attribute);
+    handler = new org.exolab.castor.xml.XMLFieldHandler()
+    {
+      public java.lang.Object getValue(java.lang.Object object)
+              throws IllegalStateException
+      {
+        PcaViewer target = (PcaViewer) object;
+        if (!target.hasShowLabels())
+        {
+          return null;
+        }
+        return (target.getShowLabels() ? java.lang.Boolean.TRUE
+                : java.lang.Boolean.FALSE);
+      }
+
+      public void setValue(java.lang.Object object, java.lang.Object value)
+              throws IllegalStateException, IllegalArgumentException
+      {
+        try
+        {
+          PcaViewer target = (PcaViewer) object;
+          // if null, use delete method for optional primitives
+          if (value == null)
+          {
+            target.deleteShowLabels();
+            return;
+          }
+          target.setShowLabels(((java.lang.Boolean) value).booleanValue());
+        } catch (java.lang.Exception ex)
+        {
+          throw new IllegalStateException(ex.toString());
+        }
+      }
+
+      public java.lang.Object newInstance(java.lang.Object parent)
+      {
+        return null;
+      }
+    };
+    desc.setHandler(handler);
+    desc.setMultivalued(false);
+    addFieldDescriptor(desc);
+
+    // -- validation code for: _showLabels
+    fieldValidator = new org.exolab.castor.xml.FieldValidator();
+    { // -- local scope
+      org.exolab.castor.xml.validators.BooleanValidator typeValidator;
+      typeValidator = new org.exolab.castor.xml.validators.BooleanValidator();
+      fieldValidator.setValidator(typeValidator);
+    }
+    desc.setValidator(fieldValidator);
+    // -- _linkToAllViews
+    desc = new org.exolab.castor.xml.util.XMLFieldDescriptorImpl(
+            java.lang.Boolean.TYPE, "_linkToAllViews", "linkToAllViews",
+            org.exolab.castor.xml.NodeType.Attribute);
+    handler = new org.exolab.castor.xml.XMLFieldHandler()
+    {
+      public java.lang.Object getValue(java.lang.Object object)
+              throws IllegalStateException
+      {
+        PcaViewer target = (PcaViewer) object;
+        if (!target.hasLinkToAllViews())
+        {
+          return null;
+        }
+        return (target.getLinkToAllViews() ? java.lang.Boolean.TRUE
+                : java.lang.Boolean.FALSE);
+      }
+
+      public void setValue(java.lang.Object object, java.lang.Object value)
+              throws IllegalStateException, IllegalArgumentException
+      {
+        try
+        {
+          PcaViewer target = (PcaViewer) object;
+          // if null, use delete method for optional primitives
+          if (value == null)
+          {
+            target.deleteLinkToAllViews();
+            return;
+          }
+          target.setLinkToAllViews(
+                  ((java.lang.Boolean) value).booleanValue());
+        } catch (java.lang.Exception ex)
+        {
+          throw new IllegalStateException(ex.toString());
+        }
+      }
+
+      public java.lang.Object newInstance(java.lang.Object parent)
+      {
+        return null;
+      }
+    };
+    desc.setHandler(handler);
+    desc.setMultivalued(false);
+    addFieldDescriptor(desc);
+
+    // -- validation code for: _linkToAllViews
+    fieldValidator = new org.exolab.castor.xml.FieldValidator();
+    { // -- local scope
+      org.exolab.castor.xml.validators.BooleanValidator typeValidator;
+      typeValidator = new org.exolab.castor.xml.validators.BooleanValidator();
+      fieldValidator.setValidator(typeValidator);
+    }
+    desc.setValidator(fieldValidator);
+    // -- _includeGaps
+    desc = new org.exolab.castor.xml.util.XMLFieldDescriptorImpl(
+            java.lang.Boolean.TYPE, "_includeGaps", "includeGaps",
+            org.exolab.castor.xml.NodeType.Attribute);
+    handler = new org.exolab.castor.xml.XMLFieldHandler()
+    {
+      public java.lang.Object getValue(java.lang.Object object)
+              throws IllegalStateException
+      {
+        PcaViewer target = (PcaViewer) object;
+        if (!target.hasIncludeGaps())
+        {
+          return null;
+        }
+        return (target.getIncludeGaps() ? java.lang.Boolean.TRUE
+                : java.lang.Boolean.FALSE);
+      }
+
+      public void setValue(java.lang.Object object, java.lang.Object value)
+              throws IllegalStateException, IllegalArgumentException
+      {
+        try
+        {
+          PcaViewer target = (PcaViewer) object;
+          // if null, use delete method for optional primitives
+          if (value == null)
+          {
+            target.deleteIncludeGaps();
+            return;
+          }
+          target.setIncludeGaps(((java.lang.Boolean) value).booleanValue());
+        } catch (java.lang.Exception ex)
+        {
+          throw new IllegalStateException(ex.toString());
+        }
+      }
+
+      public java.lang.Object newInstance(java.lang.Object parent)
+      {
+        return null;
+      }
+    };
+    desc.setHandler(handler);
+    desc.setMultivalued(false);
+    addFieldDescriptor(desc);
+
+    // -- validation code for: _includeGaps
+    fieldValidator = new org.exolab.castor.xml.FieldValidator();
+    { // -- local scope
+      org.exolab.castor.xml.validators.BooleanValidator typeValidator;
+      typeValidator = new org.exolab.castor.xml.validators.BooleanValidator();
+      fieldValidator.setValidator(typeValidator);
+    }
+    desc.setValidator(fieldValidator);
+    // -- _matchGaps
+    desc = new org.exolab.castor.xml.util.XMLFieldDescriptorImpl(
+            java.lang.Boolean.TYPE, "_matchGaps", "matchGaps",
+            org.exolab.castor.xml.NodeType.Attribute);
+    handler = new org.exolab.castor.xml.XMLFieldHandler()
+    {
+      public java.lang.Object getValue(java.lang.Object object)
+              throws IllegalStateException
+      {
+        PcaViewer target = (PcaViewer) object;
+        if (!target.hasMatchGaps())
+        {
+          return null;
+        }
+        return (target.getMatchGaps() ? java.lang.Boolean.TRUE
+                : java.lang.Boolean.FALSE);
+      }
+
+      public void setValue(java.lang.Object object, java.lang.Object value)
+              throws IllegalStateException, IllegalArgumentException
+      {
+        try
+        {
+          PcaViewer target = (PcaViewer) object;
+          // if null, use delete method for optional primitives
+          if (value == null)
+          {
+            target.deleteMatchGaps();
+            return;
+          }
+          target.setMatchGaps(((java.lang.Boolean) value).booleanValue());
+        } catch (java.lang.Exception ex)
+        {
+          throw new IllegalStateException(ex.toString());
+        }
+      }
+
+      public java.lang.Object newInstance(java.lang.Object parent)
+      {
+        return null;
+      }
+    };
+    desc.setHandler(handler);
+    desc.setMultivalued(false);
+    addFieldDescriptor(desc);
+
+    // -- validation code for: _matchGaps
+    fieldValidator = new org.exolab.castor.xml.FieldValidator();
+    { // -- local scope
+      org.exolab.castor.xml.validators.BooleanValidator typeValidator;
+      typeValidator = new org.exolab.castor.xml.validators.BooleanValidator();
+      fieldValidator.setValidator(typeValidator);
+    }
+    desc.setValidator(fieldValidator);
+    // -- _includeGappedColumns
+    desc = new org.exolab.castor.xml.util.XMLFieldDescriptorImpl(
+            java.lang.Boolean.TYPE, "_includeGappedColumns",
+            "includeGappedColumns",
+            org.exolab.castor.xml.NodeType.Attribute);
+    handler = new org.exolab.castor.xml.XMLFieldHandler()
+    {
+      public java.lang.Object getValue(java.lang.Object object)
+              throws IllegalStateException
+      {
+        PcaViewer target = (PcaViewer) object;
+        if (!target.hasIncludeGappedColumns())
+        {
+          return null;
+        }
+        return (target.getIncludeGappedColumns() ? java.lang.Boolean.TRUE
+                : java.lang.Boolean.FALSE);
+      }
+
+      public void setValue(java.lang.Object object, java.lang.Object value)
+              throws IllegalStateException, IllegalArgumentException
+      {
+        try
+        {
+          PcaViewer target = (PcaViewer) object;
+          // if null, use delete method for optional primitives
+          if (value == null)
+          {
+            target.deleteIncludeGappedColumns();
+            return;
+          }
+          target.setIncludeGappedColumns(
+                  ((java.lang.Boolean) value).booleanValue());
+        } catch (java.lang.Exception ex)
+        {
+          throw new IllegalStateException(ex.toString());
+        }
+      }
+
+      public java.lang.Object newInstance(java.lang.Object parent)
+      {
+        return null;
+      }
+    };
+    desc.setHandler(handler);
+    desc.setMultivalued(false);
+    addFieldDescriptor(desc);
+
+    // -- validation code for: _includeGappedColumns
+    fieldValidator = new org.exolab.castor.xml.FieldValidator();
+    { // -- local scope
+      org.exolab.castor.xml.validators.BooleanValidator typeValidator;
+      typeValidator = new org.exolab.castor.xml.validators.BooleanValidator();
+      fieldValidator.setValidator(typeValidator);
+    }
+    desc.setValidator(fieldValidator);
+    // -- _denominateByShortestLength
+    desc = new org.exolab.castor.xml.util.XMLFieldDescriptorImpl(
+            java.lang.Boolean.TYPE, "_denominateByShortestLength",
+            "denominateByShortestLength",
+            org.exolab.castor.xml.NodeType.Attribute);
+    handler = new org.exolab.castor.xml.XMLFieldHandler()
+    {
+      public java.lang.Object getValue(java.lang.Object object)
+              throws IllegalStateException
+      {
+        PcaViewer target = (PcaViewer) object;
+        if (!target.hasDenominateByShortestLength())
+        {
+          return null;
+        }
+        return (target.getDenominateByShortestLength()
+                ? java.lang.Boolean.TRUE
+                : java.lang.Boolean.FALSE);
+      }
+
+      public void setValue(java.lang.Object object, java.lang.Object value)
+              throws IllegalStateException, IllegalArgumentException
+      {
+        try
+        {
+          PcaViewer target = (PcaViewer) object;
+          // if null, use delete method for optional primitives
+          if (value == null)
+          {
+            target.deleteDenominateByShortestLength();
+            return;
+          }
+          target.setDenominateByShortestLength(
+                  ((java.lang.Boolean) value).booleanValue());
+        } catch (java.lang.Exception ex)
+        {
+          throw new IllegalStateException(ex.toString());
+        }
+      }
+
+      public java.lang.Object newInstance(java.lang.Object parent)
+      {
+        return null;
+      }
+    };
+    desc.setHandler(handler);
+    desc.setMultivalued(false);
+    addFieldDescriptor(desc);
+
+    // -- validation code for: _denominateByShortestLength
+    fieldValidator = new org.exolab.castor.xml.FieldValidator();
+    { // -- local scope
+      org.exolab.castor.xml.validators.BooleanValidator typeValidator;
+      typeValidator = new org.exolab.castor.xml.validators.BooleanValidator();
+      fieldValidator.setValidator(typeValidator);
+    }
+    desc.setValidator(fieldValidator);
+    // -- _width
+    desc = new org.exolab.castor.xml.util.XMLFieldDescriptorImpl(
+            java.lang.Integer.TYPE, "_width", "width",
+            org.exolab.castor.xml.NodeType.Attribute);
+    handler = new org.exolab.castor.xml.XMLFieldHandler()
+    {
+      public java.lang.Object getValue(java.lang.Object object)
+              throws IllegalStateException
+      {
+        PcaViewer target = (PcaViewer) object;
+        if (!target.hasWidth())
+        {
+          return null;
+        }
+        return new java.lang.Integer(target.getWidth());
+      }
+
+      public void setValue(java.lang.Object object, java.lang.Object value)
+              throws IllegalStateException, IllegalArgumentException
+      {
+        try
+        {
+          PcaViewer target = (PcaViewer) object;
+          // if null, use delete method for optional primitives
+          if (value == null)
+          {
+            target.deleteWidth();
+            return;
+          }
+          target.setWidth(((java.lang.Integer) value).intValue());
+        } catch (java.lang.Exception ex)
+        {
+          throw new IllegalStateException(ex.toString());
+        }
+      }
+
+      public java.lang.Object newInstance(java.lang.Object parent)
+      {
+        return null;
+      }
+    };
+    desc.setHandler(handler);
+    desc.setMultivalued(false);
+    addFieldDescriptor(desc);
+
+    // -- validation code for: _width
+    fieldValidator = new org.exolab.castor.xml.FieldValidator();
+    { // -- local scope
+      org.exolab.castor.xml.validators.IntValidator typeValidator;
+      typeValidator = new org.exolab.castor.xml.validators.IntValidator();
+      fieldValidator.setValidator(typeValidator);
+      typeValidator.setMinInclusive(-2147483648);
+      typeValidator.setMaxInclusive(2147483647);
+    }
+    desc.setValidator(fieldValidator);
+    // -- _height
+    desc = new org.exolab.castor.xml.util.XMLFieldDescriptorImpl(
+            java.lang.Integer.TYPE, "_height", "height",
+            org.exolab.castor.xml.NodeType.Attribute);
+    handler = new org.exolab.castor.xml.XMLFieldHandler()
+    {
+      public java.lang.Object getValue(java.lang.Object object)
+              throws IllegalStateException
+      {
+        PcaViewer target = (PcaViewer) object;
+        if (!target.hasHeight())
+        {
+          return null;
+        }
+        return new java.lang.Integer(target.getHeight());
+      }
+
+      public void setValue(java.lang.Object object, java.lang.Object value)
+              throws IllegalStateException, IllegalArgumentException
+      {
+        try
+        {
+          PcaViewer target = (PcaViewer) object;
+          // if null, use delete method for optional primitives
+          if (value == null)
+          {
+            target.deleteHeight();
+            return;
+          }
+          target.setHeight(((java.lang.Integer) value).intValue());
+        } catch (java.lang.Exception ex)
+        {
+          throw new IllegalStateException(ex.toString());
+        }
+      }
+
+      public java.lang.Object newInstance(java.lang.Object parent)
+      {
+        return null;
+      }
+    };
+    desc.setHandler(handler);
+    desc.setMultivalued(false);
+    addFieldDescriptor(desc);
+
+    // -- validation code for: _height
+    fieldValidator = new org.exolab.castor.xml.FieldValidator();
+    { // -- local scope
+      org.exolab.castor.xml.validators.IntValidator typeValidator;
+      typeValidator = new org.exolab.castor.xml.validators.IntValidator();
+      fieldValidator.setValidator(typeValidator);
+      typeValidator.setMinInclusive(-2147483648);
+      typeValidator.setMaxInclusive(2147483647);
+    }
+    desc.setValidator(fieldValidator);
+    // -- _xpos
+    desc = new org.exolab.castor.xml.util.XMLFieldDescriptorImpl(
+            java.lang.Integer.TYPE, "_xpos", "xpos",
+            org.exolab.castor.xml.NodeType.Attribute);
+    handler = new org.exolab.castor.xml.XMLFieldHandler()
+    {
+      public java.lang.Object getValue(java.lang.Object object)
+              throws IllegalStateException
+      {
+        PcaViewer target = (PcaViewer) object;
+        if (!target.hasXpos())
+        {
+          return null;
+        }
+        return new java.lang.Integer(target.getXpos());
+      }
+
+      public void setValue(java.lang.Object object, java.lang.Object value)
+              throws IllegalStateException, IllegalArgumentException
+      {
+        try
+        {
+          PcaViewer target = (PcaViewer) object;
+          // if null, use delete method for optional primitives
+          if (value == null)
+          {
+            target.deleteXpos();
+            return;
+          }
+          target.setXpos(((java.lang.Integer) value).intValue());
+        } catch (java.lang.Exception ex)
+        {
+          throw new IllegalStateException(ex.toString());
+        }
+      }
+
+      public java.lang.Object newInstance(java.lang.Object parent)
+      {
+        return null;
+      }
+    };
+    desc.setHandler(handler);
+    desc.setMultivalued(false);
+    addFieldDescriptor(desc);
+
+    // -- validation code for: _xpos
+    fieldValidator = new org.exolab.castor.xml.FieldValidator();
+    { // -- local scope
+      org.exolab.castor.xml.validators.IntValidator typeValidator;
+      typeValidator = new org.exolab.castor.xml.validators.IntValidator();
+      fieldValidator.setValidator(typeValidator);
+      typeValidator.setMinInclusive(-2147483648);
+      typeValidator.setMaxInclusive(2147483647);
+    }
+    desc.setValidator(fieldValidator);
+    // -- _ypos
+    desc = new org.exolab.castor.xml.util.XMLFieldDescriptorImpl(
+            java.lang.Integer.TYPE, "_ypos", "ypos",
+            org.exolab.castor.xml.NodeType.Attribute);
+    handler = new org.exolab.castor.xml.XMLFieldHandler()
+    {
+      public java.lang.Object getValue(java.lang.Object object)
+              throws IllegalStateException
+      {
+        PcaViewer target = (PcaViewer) object;
+        if (!target.hasYpos())
+        {
+          return null;
+        }
+        return new java.lang.Integer(target.getYpos());
+      }
+
+      public void setValue(java.lang.Object object, java.lang.Object value)
+              throws IllegalStateException, IllegalArgumentException
+      {
+        try
+        {
+          PcaViewer target = (PcaViewer) object;
+          // if null, use delete method for optional primitives
+          if (value == null)
+          {
+            target.deleteYpos();
+            return;
+          }
+          target.setYpos(((java.lang.Integer) value).intValue());
+        } catch (java.lang.Exception ex)
+        {
+          throw new IllegalStateException(ex.toString());
+        }
+      }
+
+      public java.lang.Object newInstance(java.lang.Object parent)
+      {
+        return null;
+      }
+    };
+    desc.setHandler(handler);
+    desc.setMultivalued(false);
+    addFieldDescriptor(desc);
+
+    // -- validation code for: _ypos
+    fieldValidator = new org.exolab.castor.xml.FieldValidator();
+    { // -- local scope
+      org.exolab.castor.xml.validators.IntValidator typeValidator;
+      typeValidator = new org.exolab.castor.xml.validators.IntValidator();
+      fieldValidator.setValidator(typeValidator);
+      typeValidator.setMinInclusive(-2147483648);
+      typeValidator.setMaxInclusive(2147483647);
+    }
+    desc.setValidator(fieldValidator);
+    // -- initialize element descriptors
+
+    // -- _sequencePointList
+    desc = new org.exolab.castor.xml.util.XMLFieldDescriptorImpl(
+            jalview.schemabinding.version2.SequencePoint.class,
+            "_sequencePointList", "sequencePoint",
+            org.exolab.castor.xml.NodeType.Element);
+    handler = new org.exolab.castor.xml.XMLFieldHandler()
+    {
+      public java.lang.Object getValue(java.lang.Object object)
+              throws IllegalStateException
+      {
+        PcaViewer target = (PcaViewer) object;
+        return target.getSequencePoint();
+      }
+
+      public void setValue(java.lang.Object object, java.lang.Object value)
+              throws IllegalStateException, IllegalArgumentException
+      {
+        try
+        {
+          PcaViewer target = (PcaViewer) object;
+          target.addSequencePoint(
+                  (jalview.schemabinding.version2.SequencePoint) value);
+        } catch (java.lang.Exception ex)
+        {
+          throw new IllegalStateException(ex.toString());
+        }
+      }
+
+      public void resetValue(Object object)
+              throws IllegalStateException, IllegalArgumentException
+      {
+        try
+        {
+          PcaViewer target = (PcaViewer) object;
+          target.removeAllSequencePoint();
+        } catch (java.lang.Exception ex)
+        {
+          throw new IllegalStateException(ex.toString());
+        }
+      }
+
+      public java.lang.Object newInstance(java.lang.Object parent)
+      {
+        return new jalview.schemabinding.version2.SequencePoint();
+      }
+    };
+    desc.setHandler(handler);
+    desc.setNameSpaceURI("www.jalview.org");
+    desc.setRequired(true);
+    desc.setMultivalued(true);
+    addFieldDescriptor(desc);
+
+    // -- validation code for: _sequencePointList
+    fieldValidator = new org.exolab.castor.xml.FieldValidator();
+    fieldValidator.setMinOccurs(1);
+    { // -- local scope
+    }
+    desc.setValidator(fieldValidator);
+    // -- _axisList
+    desc = new org.exolab.castor.xml.util.XMLFieldDescriptorImpl(
+            jalview.schemabinding.version2.Axis.class, "_axisList", "axis",
+            org.exolab.castor.xml.NodeType.Element);
+    handler = new org.exolab.castor.xml.XMLFieldHandler()
+    {
+      public java.lang.Object getValue(java.lang.Object object)
+              throws IllegalStateException
+      {
+        PcaViewer target = (PcaViewer) object;
+        return target.getAxis();
+      }
+
+      public void setValue(java.lang.Object object, java.lang.Object value)
+              throws IllegalStateException, IllegalArgumentException
+      {
+        try
+        {
+          PcaViewer target = (PcaViewer) object;
+          target.addAxis((jalview.schemabinding.version2.Axis) value);
+        } catch (java.lang.Exception ex)
+        {
+          throw new IllegalStateException(ex.toString());
+        }
+      }
+
+      public void resetValue(Object object)
+              throws IllegalStateException, IllegalArgumentException
+      {
+        try
+        {
+          PcaViewer target = (PcaViewer) object;
+          target.removeAllAxis();
+        } catch (java.lang.Exception ex)
+        {
+          throw new IllegalStateException(ex.toString());
+        }
+      }
+
+      public java.lang.Object newInstance(java.lang.Object parent)
+      {
+        return new jalview.schemabinding.version2.Axis();
+      }
+    };
+    desc.setHandler(handler);
+    desc.setNameSpaceURI("www.jalview.org");
+    desc.setRequired(true);
+    desc.setMultivalued(true);
+    addFieldDescriptor(desc);
+
+    // -- validation code for: _axisList
+    fieldValidator = new org.exolab.castor.xml.FieldValidator();
+    fieldValidator.setMinOccurs(3);
+    fieldValidator.setMaxOccurs(3);
+    { // -- local scope
+    }
+    desc.setValidator(fieldValidator);
+    // -- _seqPointMin
+    desc = new org.exolab.castor.xml.util.XMLFieldDescriptorImpl(
+            jalview.schemabinding.version2.SeqPointMin.class,
+            "_seqPointMin", "seqPointMin",
+            org.exolab.castor.xml.NodeType.Element);
+    handler = new org.exolab.castor.xml.XMLFieldHandler()
+    {
+      public java.lang.Object getValue(java.lang.Object object)
+              throws IllegalStateException
+      {
+        PcaViewer target = (PcaViewer) object;
+        return target.getSeqPointMin();
+      }
+
+      public void setValue(java.lang.Object object, java.lang.Object value)
+              throws IllegalStateException, IllegalArgumentException
+      {
+        try
+        {
+          PcaViewer target = (PcaViewer) object;
+          target.setSeqPointMin(
+                  (jalview.schemabinding.version2.SeqPointMin) value);
+        } catch (java.lang.Exception ex)
+        {
+          throw new IllegalStateException(ex.toString());
+        }
+      }
+
+      public java.lang.Object newInstance(java.lang.Object parent)
+      {
+        return new jalview.schemabinding.version2.SeqPointMin();
+      }
+    };
+    desc.setHandler(handler);
+    desc.setNameSpaceURI("www.jalview.org");
+    desc.setRequired(true);
+    desc.setMultivalued(false);
+    addFieldDescriptor(desc);
+
+    // -- validation code for: _seqPointMin
+    fieldValidator = new org.exolab.castor.xml.FieldValidator();
+    fieldValidator.setMinOccurs(1);
+    { // -- local scope
+    }
+    desc.setValidator(fieldValidator);
+    // -- _seqPointMax
+    desc = new org.exolab.castor.xml.util.XMLFieldDescriptorImpl(
+            jalview.schemabinding.version2.SeqPointMax.class,
+            "_seqPointMax", "seqPointMax",
+            org.exolab.castor.xml.NodeType.Element);
+    handler = new org.exolab.castor.xml.XMLFieldHandler()
+    {
+      public java.lang.Object getValue(java.lang.Object object)
+              throws IllegalStateException
+      {
+        PcaViewer target = (PcaViewer) object;
+        return target.getSeqPointMax();
+      }
+
+      public void setValue(java.lang.Object object, java.lang.Object value)
+              throws IllegalStateException, IllegalArgumentException
+      {
+        try
+        {
+          PcaViewer target = (PcaViewer) object;
+          target.setSeqPointMax(
+                  (jalview.schemabinding.version2.SeqPointMax) value);
+        } catch (java.lang.Exception ex)
+        {
+          throw new IllegalStateException(ex.toString());
+        }
+      }
+
+      public java.lang.Object newInstance(java.lang.Object parent)
+      {
+        return new jalview.schemabinding.version2.SeqPointMax();
+      }
+    };
+    desc.setHandler(handler);
+    desc.setNameSpaceURI("www.jalview.org");
+    desc.setRequired(true);
+    desc.setMultivalued(false);
+    addFieldDescriptor(desc);
+
+    // -- validation code for: _seqPointMax
+    fieldValidator = new org.exolab.castor.xml.FieldValidator();
+    fieldValidator.setMinOccurs(1);
+    { // -- local scope
+    }
+    desc.setValidator(fieldValidator);
+    // -- _pcaData
+    desc = new org.exolab.castor.xml.util.XMLFieldDescriptorImpl(
+            jalview.schemabinding.version2.PcaData.class, "_pcaData",
+            "pcaData", org.exolab.castor.xml.NodeType.Element);
+    handler = new org.exolab.castor.xml.XMLFieldHandler()
+    {
+      public java.lang.Object getValue(java.lang.Object object)
+              throws IllegalStateException
+      {
+        PcaViewer target = (PcaViewer) object;
+        return target.getPcaData();
+      }
+
+      public void setValue(java.lang.Object object, java.lang.Object value)
+              throws IllegalStateException, IllegalArgumentException
+      {
+        try
+        {
+          PcaViewer target = (PcaViewer) object;
+          target.setPcaData((jalview.schemabinding.version2.PcaData) value);
+        } catch (java.lang.Exception ex)
+        {
+          throw new IllegalStateException(ex.toString());
+        }
+      }
+
+      public java.lang.Object newInstance(java.lang.Object parent)
+      {
+        return new jalview.schemabinding.version2.PcaData();
+      }
+    };
+    desc.setHandler(handler);
+    desc.setNameSpaceURI("www.jalview.org");
+    desc.setRequired(true);
+    desc.setMultivalued(false);
+    addFieldDescriptor(desc);
+
+    // -- validation code for: _pcaData
+    fieldValidator = new org.exolab.castor.xml.FieldValidator();
+    fieldValidator.setMinOccurs(1);
+    { // -- local scope
+    }
+    desc.setValidator(fieldValidator);
+  }
+
+  // -----------/
+  // - Methods -/
+  // -----------/
+
+  /**
+   * Method getAccessMode.
+   * 
+   * @return the access mode specified for this class.
+   */
+  public org.exolab.castor.mapping.AccessMode getAccessMode()
+  {
+    return null;
+  }
+
+  /**
+   * Method getIdentity.
+   * 
+   * @return the identity field, null if this class has no identity.
+   */
+  public org.exolab.castor.mapping.FieldDescriptor getIdentity()
+  {
+    return super.getIdentity();
+  }
+
+  /**
+   * Method getJavaClass.
+   * 
+   * @return the Java class represented by this descriptor.
+   */
+  public java.lang.Class getJavaClass()
+  {
+    return jalview.schemabinding.version2.PcaViewer.class;
+  }
+
+  /**
+   * Method getNameSpacePrefix.
+   * 
+   * @return the namespace prefix to use when marshaling as XML.
+   */
+  public java.lang.String getNameSpacePrefix()
+  {
+    return _nsPrefix;
+  }
+
+  /**
+   * Method getNameSpaceURI.
+   * 
+   * @return the namespace URI used when marshaling and unmarshaling as XML.
+   */
+  public java.lang.String getNameSpaceURI()
+  {
+    return _nsURI;
+  }
+
+  /**
+   * Method getValidator.
+   * 
+   * @return a specific validator for the class described by this
+   *         ClassDescriptor.
+   */
+  public org.exolab.castor.xml.TypeValidator getValidator()
+  {
+    return this;
+  }
+
+  /**
+   * Method getXMLName.
+   * 
+   * @return the XML Name for the Class being described.
+   */
+  public java.lang.String getXMLName()
+  {
+    return _xmlName;
+  }
+
+  /**
+   * Method isElementDefinition.
+   * 
+   * @return true if XML schema definition of this Class is that of a global
+   *         element or element with anonymous type definition.
+   */
+  public boolean isElementDefinition()
+  {
+    return _elementDefinition;
+  }
+
+}
diff --git a/src/jalview/schemabinding/version2/descriptors/RowDescriptor.java b/src/jalview/schemabinding/version2/descriptors/RowDescriptor.java
new file mode 100644 (file)
index 0000000..f9ca1a6
--- /dev/null
@@ -0,0 +1,149 @@
+/*
+ * This class was automatically generated with 
+ * <a href="http://www.castor.org">Castor 1.1</a>, using an XML
+ * Schema.
+ * $Id$
+ */
+
+package jalview.schemabinding.version2.descriptors;
+
+//---------------------------------/
+//- Imported classes and packages -/
+//---------------------------------/
+
+import jalview.schemabinding.version2.Row;
+
+/**
+ * Class RowDescriptor.
+ * 
+ * @version $Revision$ $Date$
+ */
+public class RowDescriptor extends
+        jalview.schemabinding.version2.descriptors.DoubleVectorDescriptor
+{
+
+  // --------------------------/
+  // - Class/Member Variables -/
+  // --------------------------/
+
+  /**
+   * Field _elementDefinition.
+   */
+  private boolean _elementDefinition;
+
+  /**
+   * Field _nsPrefix.
+   */
+  private java.lang.String _nsPrefix;
+
+  /**
+   * Field _nsURI.
+   */
+  private java.lang.String _nsURI;
+
+  /**
+   * Field _xmlName.
+   */
+  private java.lang.String _xmlName;
+
+  // ----------------/
+  // - Constructors -/
+  // ----------------/
+
+  public RowDescriptor()
+  {
+    super();
+    setExtendsWithoutFlatten(
+            new jalview.schemabinding.version2.descriptors.DoubleVectorDescriptor());
+    _nsURI = "www.jalview.org";
+    _xmlName = "row";
+    _elementDefinition = true;
+  }
+
+  // -----------/
+  // - Methods -/
+  // -----------/
+
+  /**
+   * Method getAccessMode.
+   * 
+   * @return the access mode specified for this class.
+   */
+  public org.exolab.castor.mapping.AccessMode getAccessMode()
+  {
+    return null;
+  }
+
+  /**
+   * Method getIdentity.
+   * 
+   * @return the identity field, null if this class has no identity.
+   */
+  public org.exolab.castor.mapping.FieldDescriptor getIdentity()
+  {
+    return super.getIdentity();
+  }
+
+  /**
+   * Method getJavaClass.
+   * 
+   * @return the Java class represented by this descriptor.
+   */
+  public java.lang.Class getJavaClass()
+  {
+    return jalview.schemabinding.version2.Row.class;
+  }
+
+  /**
+   * Method getNameSpacePrefix.
+   * 
+   * @return the namespace prefix to use when marshaling as XML.
+   */
+  public java.lang.String getNameSpacePrefix()
+  {
+    return _nsPrefix;
+  }
+
+  /**
+   * Method getNameSpaceURI.
+   * 
+   * @return the namespace URI used when marshaling and unmarshaling as XML.
+   */
+  public java.lang.String getNameSpaceURI()
+  {
+    return _nsURI;
+  }
+
+  /**
+   * Method getValidator.
+   * 
+   * @return a specific validator for the class described by this
+   *         ClassDescriptor.
+   */
+  public org.exolab.castor.xml.TypeValidator getValidator()
+  {
+    return this;
+  }
+
+  /**
+   * Method getXMLName.
+   * 
+   * @return the XML Name for the Class being described.
+   */
+  public java.lang.String getXMLName()
+  {
+    return _xmlName;
+  }
+
+  /**
+   * Method isElementDefinition.
+   * 
+   * @return true if XML schema definition of this Class is that of a global
+   *         element or element with anonymous type definition.
+   */
+  public boolean isElementDefinition()
+  {
+    return _elementDefinition;
+  }
+
+}
diff --git a/src/jalview/schemabinding/version2/descriptors/SeqPointMaxDescriptor.java b/src/jalview/schemabinding/version2/descriptors/SeqPointMaxDescriptor.java
new file mode 100644 (file)
index 0000000..18f0cb7
--- /dev/null
@@ -0,0 +1,319 @@
+/*
+ * This class was automatically generated with 
+ * <a href="http://www.castor.org">Castor 1.1</a>, using an XML
+ * Schema.
+ * $Id$
+ */
+
+package jalview.schemabinding.version2.descriptors;
+
+//---------------------------------/
+//- Imported classes and packages -/
+//---------------------------------/
+
+import jalview.schemabinding.version2.SeqPointMax;
+
+/**
+ * Class SeqPointMaxDescriptor.
+ * 
+ * @version $Revision$ $Date$
+ */
+public class SeqPointMaxDescriptor
+        extends org.exolab.castor.xml.util.XMLClassDescriptorImpl
+{
+
+  // --------------------------/
+  // - Class/Member Variables -/
+  // --------------------------/
+
+  /**
+   * Field _elementDefinition.
+   */
+  private boolean _elementDefinition;
+
+  /**
+   * Field _nsPrefix.
+   */
+  private java.lang.String _nsPrefix;
+
+  /**
+   * Field _nsURI.
+   */
+  private java.lang.String _nsURI;
+
+  /**
+   * Field _xmlName.
+   */
+  private java.lang.String _xmlName;
+
+  // ----------------/
+  // - Constructors -/
+  // ----------------/
+
+  public SeqPointMaxDescriptor()
+  {
+    super();
+    _nsURI = "www.jalview.org";
+    _xmlName = "seqPointMax";
+    _elementDefinition = true;
+    org.exolab.castor.xml.util.XMLFieldDescriptorImpl desc = null;
+    org.exolab.castor.mapping.FieldHandler handler = null;
+    org.exolab.castor.xml.FieldValidator fieldValidator = null;
+    // -- initialize attribute descriptors
+
+    // -- _xPos
+    desc = new org.exolab.castor.xml.util.XMLFieldDescriptorImpl(
+            java.lang.Float.TYPE, "_xPos", "xPos",
+            org.exolab.castor.xml.NodeType.Attribute);
+    handler = new org.exolab.castor.xml.XMLFieldHandler()
+    {
+      public java.lang.Object getValue(java.lang.Object object)
+              throws IllegalStateException
+      {
+        SeqPointMax target = (SeqPointMax) object;
+        if (!target.hasXPos())
+        {
+          return null;
+        }
+        return new java.lang.Float(target.getXPos());
+      }
+
+      public void setValue(java.lang.Object object, java.lang.Object value)
+              throws IllegalStateException, IllegalArgumentException
+      {
+        try
+        {
+          SeqPointMax target = (SeqPointMax) object;
+          // if null, use delete method for optional primitives
+          if (value == null)
+          {
+            target.deleteXPos();
+            return;
+          }
+          target.setXPos(((java.lang.Float) value).floatValue());
+        } catch (java.lang.Exception ex)
+        {
+          throw new IllegalStateException(ex.toString());
+        }
+      }
+
+      public java.lang.Object newInstance(java.lang.Object parent)
+      {
+        return null;
+      }
+    };
+    desc.setHandler(handler);
+    desc.setMultivalued(false);
+    addFieldDescriptor(desc);
+
+    // -- validation code for: _xPos
+    fieldValidator = new org.exolab.castor.xml.FieldValidator();
+    { // -- local scope
+      org.exolab.castor.xml.validators.FloatValidator typeValidator;
+      typeValidator = new org.exolab.castor.xml.validators.FloatValidator();
+      fieldValidator.setValidator(typeValidator);
+      typeValidator.setMinInclusive((float) -3.4028235E38);
+      typeValidator.setMaxInclusive((float) 3.4028235E38);
+    }
+    desc.setValidator(fieldValidator);
+    // -- _yPos
+    desc = new org.exolab.castor.xml.util.XMLFieldDescriptorImpl(
+            java.lang.Float.TYPE, "_yPos", "yPos",
+            org.exolab.castor.xml.NodeType.Attribute);
+    handler = new org.exolab.castor.xml.XMLFieldHandler()
+    {
+      public java.lang.Object getValue(java.lang.Object object)
+              throws IllegalStateException
+      {
+        SeqPointMax target = (SeqPointMax) object;
+        if (!target.hasYPos())
+        {
+          return null;
+        }
+        return new java.lang.Float(target.getYPos());
+      }
+
+      public void setValue(java.lang.Object object, java.lang.Object value)
+              throws IllegalStateException, IllegalArgumentException
+      {
+        try
+        {
+          SeqPointMax target = (SeqPointMax) object;
+          // if null, use delete method for optional primitives
+          if (value == null)
+          {
+            target.deleteYPos();
+            return;
+          }
+          target.setYPos(((java.lang.Float) value).floatValue());
+        } catch (java.lang.Exception ex)
+        {
+          throw new IllegalStateException(ex.toString());
+        }
+      }
+
+      public java.lang.Object newInstance(java.lang.Object parent)
+      {
+        return null;
+      }
+    };
+    desc.setHandler(handler);
+    desc.setMultivalued(false);
+    addFieldDescriptor(desc);
+
+    // -- validation code for: _yPos
+    fieldValidator = new org.exolab.castor.xml.FieldValidator();
+    { // -- local scope
+      org.exolab.castor.xml.validators.FloatValidator typeValidator;
+      typeValidator = new org.exolab.castor.xml.validators.FloatValidator();
+      fieldValidator.setValidator(typeValidator);
+      typeValidator.setMinInclusive((float) -3.4028235E38);
+      typeValidator.setMaxInclusive((float) 3.4028235E38);
+    }
+    desc.setValidator(fieldValidator);
+    // -- _zPos
+    desc = new org.exolab.castor.xml.util.XMLFieldDescriptorImpl(
+            java.lang.Float.TYPE, "_zPos", "zPos",
+            org.exolab.castor.xml.NodeType.Attribute);
+    handler = new org.exolab.castor.xml.XMLFieldHandler()
+    {
+      public java.lang.Object getValue(java.lang.Object object)
+              throws IllegalStateException
+      {
+        SeqPointMax target = (SeqPointMax) object;
+        if (!target.hasZPos())
+        {
+          return null;
+        }
+        return new java.lang.Float(target.getZPos());
+      }
+
+      public void setValue(java.lang.Object object, java.lang.Object value)
+              throws IllegalStateException, IllegalArgumentException
+      {
+        try
+        {
+          SeqPointMax target = (SeqPointMax) object;
+          // if null, use delete method for optional primitives
+          if (value == null)
+          {
+            target.deleteZPos();
+            return;
+          }
+          target.setZPos(((java.lang.Float) value).floatValue());
+        } catch (java.lang.Exception ex)
+        {
+          throw new IllegalStateException(ex.toString());
+        }
+      }
+
+      public java.lang.Object newInstance(java.lang.Object parent)
+      {
+        return null;
+      }
+    };
+    desc.setHandler(handler);
+    desc.setMultivalued(false);
+    addFieldDescriptor(desc);
+
+    // -- validation code for: _zPos
+    fieldValidator = new org.exolab.castor.xml.FieldValidator();
+    { // -- local scope
+      org.exolab.castor.xml.validators.FloatValidator typeValidator;
+      typeValidator = new org.exolab.castor.xml.validators.FloatValidator();
+      fieldValidator.setValidator(typeValidator);
+      typeValidator.setMinInclusive((float) -3.4028235E38);
+      typeValidator.setMaxInclusive((float) 3.4028235E38);
+    }
+    desc.setValidator(fieldValidator);
+    // -- initialize element descriptors
+
+  }
+
+  // -----------/
+  // - Methods -/
+  // -----------/
+
+  /**
+   * Method getAccessMode.
+   * 
+   * @return the access mode specified for this class.
+   */
+  public org.exolab.castor.mapping.AccessMode getAccessMode()
+  {
+    return null;
+  }
+
+  /**
+   * Method getIdentity.
+   * 
+   * @return the identity field, null if this class has no identity.
+   */
+  public org.exolab.castor.mapping.FieldDescriptor getIdentity()
+  {
+    return super.getIdentity();
+  }
+
+  /**
+   * Method getJavaClass.
+   * 
+   * @return the Java class represented by this descriptor.
+   */
+  public java.lang.Class getJavaClass()
+  {
+    return jalview.schemabinding.version2.SeqPointMax.class;
+  }
+
+  /**
+   * Method getNameSpacePrefix.
+   * 
+   * @return the namespace prefix to use when marshaling as XML.
+   */
+  public java.lang.String getNameSpacePrefix()
+  {
+    return _nsPrefix;
+  }
+
+  /**
+   * Method getNameSpaceURI.
+   * 
+   * @return the namespace URI used when marshaling and unmarshaling as XML.
+   */
+  public java.lang.String getNameSpaceURI()
+  {
+    return _nsURI;
+  }
+
+  /**
+   * Method getValidator.
+   * 
+   * @return a specific validator for the class described by this
+   *         ClassDescriptor.
+   */
+  public org.exolab.castor.xml.TypeValidator getValidator()
+  {
+    return this;
+  }
+
+  /**
+   * Method getXMLName.
+   * 
+   * @return the XML Name for the Class being described.
+   */
+  public java.lang.String getXMLName()
+  {
+    return _xmlName;
+  }
+
+  /**
+   * Method isElementDefinition.
+   * 
+   * @return true if XML schema definition of this Class is that of a global
+   *         element or element with anonymous type definition.
+   */
+  public boolean isElementDefinition()
+  {
+    return _elementDefinition;
+  }
+
+}
diff --git a/src/jalview/schemabinding/version2/descriptors/SeqPointMinDescriptor.java b/src/jalview/schemabinding/version2/descriptors/SeqPointMinDescriptor.java
new file mode 100644 (file)
index 0000000..fbf978e
--- /dev/null
@@ -0,0 +1,319 @@
+/*
+ * This class was automatically generated with 
+ * <a href="http://www.castor.org">Castor 1.1</a>, using an XML
+ * Schema.
+ * $Id$
+ */
+
+package jalview.schemabinding.version2.descriptors;
+
+//---------------------------------/
+//- Imported classes and packages -/
+//---------------------------------/
+
+import jalview.schemabinding.version2.SeqPointMin;
+
+/**
+ * Class SeqPointMinDescriptor.
+ * 
+ * @version $Revision$ $Date$
+ */
+public class SeqPointMinDescriptor
+        extends org.exolab.castor.xml.util.XMLClassDescriptorImpl
+{
+
+  // --------------------------/
+  // - Class/Member Variables -/
+  // --------------------------/
+
+  /**
+   * Field _elementDefinition.
+   */
+  private boolean _elementDefinition;
+
+  /**
+   * Field _nsPrefix.
+   */
+  private java.lang.String _nsPrefix;
+
+  /**
+   * Field _nsURI.
+   */
+  private java.lang.String _nsURI;
+
+  /**
+   * Field _xmlName.
+   */
+  private java.lang.String _xmlName;
+
+  // ----------------/
+  // - Constructors -/
+  // ----------------/
+
+  public SeqPointMinDescriptor()
+  {
+    super();
+    _nsURI = "www.jalview.org";
+    _xmlName = "seqPointMin";
+    _elementDefinition = true;
+    org.exolab.castor.xml.util.XMLFieldDescriptorImpl desc = null;
+    org.exolab.castor.mapping.FieldHandler handler = null;
+    org.exolab.castor.xml.FieldValidator fieldValidator = null;
+    // -- initialize attribute descriptors
+
+    // -- _xPos
+    desc = new org.exolab.castor.xml.util.XMLFieldDescriptorImpl(
+            java.lang.Float.TYPE, "_xPos", "xPos",
+            org.exolab.castor.xml.NodeType.Attribute);
+    handler = new org.exolab.castor.xml.XMLFieldHandler()
+    {
+      public java.lang.Object getValue(java.lang.Object object)
+              throws IllegalStateException
+      {
+        SeqPointMin target = (SeqPointMin) object;
+        if (!target.hasXPos())
+        {
+          return null;
+        }
+        return new java.lang.Float(target.getXPos());
+      }
+
+      public void setValue(java.lang.Object object, java.lang.Object value)
+              throws IllegalStateException, IllegalArgumentException
+      {
+        try
+        {
+          SeqPointMin target = (SeqPointMin) object;
+          // if null, use delete method for optional primitives
+          if (value == null)
+          {
+            target.deleteXPos();
+            return;
+          }
+          target.setXPos(((java.lang.Float) value).floatValue());
+        } catch (java.lang.Exception ex)
+        {
+          throw new IllegalStateException(ex.toString());
+        }
+      }
+
+      public java.lang.Object newInstance(java.lang.Object parent)
+      {
+        return null;
+      }
+    };
+    desc.setHandler(handler);
+    desc.setMultivalued(false);
+    addFieldDescriptor(desc);
+
+    // -- validation code for: _xPos
+    fieldValidator = new org.exolab.castor.xml.FieldValidator();
+    { // -- local scope
+      org.exolab.castor.xml.validators.FloatValidator typeValidator;
+      typeValidator = new org.exolab.castor.xml.validators.FloatValidator();
+      fieldValidator.setValidator(typeValidator);
+      typeValidator.setMinInclusive((float) -3.4028235E38);
+      typeValidator.setMaxInclusive((float) 3.4028235E38);
+    }
+    desc.setValidator(fieldValidator);
+    // -- _yPos
+    desc = new org.exolab.castor.xml.util.XMLFieldDescriptorImpl(
+            java.lang.Float.TYPE, "_yPos", "yPos",
+            org.exolab.castor.xml.NodeType.Attribute);
+    handler = new org.exolab.castor.xml.XMLFieldHandler()
+    {
+      public java.lang.Object getValue(java.lang.Object object)
+              throws IllegalStateException
+      {
+        SeqPointMin target = (SeqPointMin) object;
+        if (!target.hasYPos())
+        {
+          return null;
+        }
+        return new java.lang.Float(target.getYPos());
+      }
+
+      public void setValue(java.lang.Object object, java.lang.Object value)
+              throws IllegalStateException, IllegalArgumentException
+      {
+        try
+        {
+          SeqPointMin target = (SeqPointMin) object;
+          // if null, use delete method for optional primitives
+          if (value == null)
+          {
+            target.deleteYPos();
+            return;
+          }
+          target.setYPos(((java.lang.Float) value).floatValue());
+        } catch (java.lang.Exception ex)
+        {
+          throw new IllegalStateException(ex.toString());
+        }
+      }
+
+      public java.lang.Object newInstance(java.lang.Object parent)
+      {
+        return null;
+      }
+    };
+    desc.setHandler(handler);
+    desc.setMultivalued(false);
+    addFieldDescriptor(desc);
+
+    // -- validation code for: _yPos
+    fieldValidator = new org.exolab.castor.xml.FieldValidator();
+    { // -- local scope
+      org.exolab.castor.xml.validators.FloatValidator typeValidator;
+      typeValidator = new org.exolab.castor.xml.validators.FloatValidator();
+      fieldValidator.setValidator(typeValidator);
+      typeValidator.setMinInclusive((float) -3.4028235E38);
+      typeValidator.setMaxInclusive((float) 3.4028235E38);
+    }
+    desc.setValidator(fieldValidator);
+    // -- _zPos
+    desc = new org.exolab.castor.xml.util.XMLFieldDescriptorImpl(
+            java.lang.Float.TYPE, "_zPos", "zPos",
+            org.exolab.castor.xml.NodeType.Attribute);
+    handler = new org.exolab.castor.xml.XMLFieldHandler()
+    {
+      public java.lang.Object getValue(java.lang.Object object)
+              throws IllegalStateException
+      {
+        SeqPointMin target = (SeqPointMin) object;
+        if (!target.hasZPos())
+        {
+          return null;
+        }
+        return new java.lang.Float(target.getZPos());
+      }
+
+      public void setValue(java.lang.Object object, java.lang.Object value)
+              throws IllegalStateException, IllegalArgumentException
+      {
+        try
+        {
+          SeqPointMin target = (SeqPointMin) object;
+          // if null, use delete method for optional primitives
+          if (value == null)
+          {
+            target.deleteZPos();
+            return;
+          }
+          target.setZPos(((java.lang.Float) value).floatValue());
+        } catch (java.lang.Exception ex)
+        {
+          throw new IllegalStateException(ex.toString());
+        }
+      }
+
+      public java.lang.Object newInstance(java.lang.Object parent)
+      {
+        return null;
+      }
+    };
+    desc.setHandler(handler);
+    desc.setMultivalued(false);
+    addFieldDescriptor(desc);
+
+    // -- validation code for: _zPos
+    fieldValidator = new org.exolab.castor.xml.FieldValidator();
+    { // -- local scope
+      org.exolab.castor.xml.validators.FloatValidator typeValidator;
+      typeValidator = new org.exolab.castor.xml.validators.FloatValidator();
+      fieldValidator.setValidator(typeValidator);
+      typeValidator.setMinInclusive((float) -3.4028235E38);
+      typeValidator.setMaxInclusive((float) 3.4028235E38);
+    }
+    desc.setValidator(fieldValidator);
+    // -- initialize element descriptors
+
+  }
+
+  // -----------/
+  // - Methods -/
+  // -----------/
+
+  /**
+   * Method getAccessMode.
+   * 
+   * @return the access mode specified for this class.
+   */
+  public org.exolab.castor.mapping.AccessMode getAccessMode()
+  {
+    return null;
+  }
+
+  /**
+   * Method getIdentity.
+   * 
+   * @return the identity field, null if this class has no identity.
+   */
+  public org.exolab.castor.mapping.FieldDescriptor getIdentity()
+  {
+    return super.getIdentity();
+  }
+
+  /**
+   * Method getJavaClass.
+   * 
+   * @return the Java class represented by this descriptor.
+   */
+  public java.lang.Class getJavaClass()
+  {
+    return jalview.schemabinding.version2.SeqPointMin.class;
+  }
+
+  /**
+   * Method getNameSpacePrefix.
+   * 
+   * @return the namespace prefix to use when marshaling as XML.
+   */
+  public java.lang.String getNameSpacePrefix()
+  {
+    return _nsPrefix;
+  }
+
+  /**
+   * Method getNameSpaceURI.
+   * 
+   * @return the namespace URI used when marshaling and unmarshaling as XML.
+   */
+  public java.lang.String getNameSpaceURI()
+  {
+    return _nsURI;
+  }
+
+  /**
+   * Method getValidator.
+   * 
+   * @return a specific validator for the class described by this
+   *         ClassDescriptor.
+   */
+  public org.exolab.castor.xml.TypeValidator getValidator()
+  {
+    return this;
+  }
+
+  /**
+   * Method getXMLName.
+   * 
+   * @return the XML Name for the Class being described.
+   */
+  public java.lang.String getXMLName()
+  {
+    return _xmlName;
+  }
+
+  /**
+   * Method isElementDefinition.
+   * 
+   * @return true if XML schema definition of this Class is that of a global
+   *         element or element with anonymous type definition.
+   */
+  public boolean isElementDefinition()
+  {
+    return _elementDefinition;
+  }
+
+}
diff --git a/src/jalview/schemabinding/version2/descriptors/SequencePointDescriptor.java b/src/jalview/schemabinding/version2/descriptors/SequencePointDescriptor.java
new file mode 100644 (file)
index 0000000..0d48052
--- /dev/null
@@ -0,0 +1,364 @@
+/*
+ * This class was automatically generated with 
+ * <a href="http://www.castor.org">Castor 1.1</a>, using an XML
+ * Schema.
+ * $Id$
+ */
+
+package jalview.schemabinding.version2.descriptors;
+
+//---------------------------------/
+//- Imported classes and packages -/
+//---------------------------------/
+
+import jalview.schemabinding.version2.SequencePoint;
+
+/**
+ * Class SequencePointDescriptor.
+ * 
+ * @version $Revision$ $Date$
+ */
+public class SequencePointDescriptor
+        extends org.exolab.castor.xml.util.XMLClassDescriptorImpl
+{
+
+  // --------------------------/
+  // - Class/Member Variables -/
+  // --------------------------/
+
+  /**
+   * Field _elementDefinition.
+   */
+  private boolean _elementDefinition;
+
+  /**
+   * Field _nsPrefix.
+   */
+  private java.lang.String _nsPrefix;
+
+  /**
+   * Field _nsURI.
+   */
+  private java.lang.String _nsURI;
+
+  /**
+   * Field _xmlName.
+   */
+  private java.lang.String _xmlName;
+
+  // ----------------/
+  // - Constructors -/
+  // ----------------/
+
+  public SequencePointDescriptor()
+  {
+    super();
+    _nsURI = "www.jalview.org";
+    _xmlName = "sequencePoint";
+    _elementDefinition = true;
+    org.exolab.castor.xml.util.XMLFieldDescriptorImpl desc = null;
+    org.exolab.castor.mapping.FieldHandler handler = null;
+    org.exolab.castor.xml.FieldValidator fieldValidator = null;
+    // -- initialize attribute descriptors
+
+    // -- _sequenceRef
+    desc = new org.exolab.castor.xml.util.XMLFieldDescriptorImpl(
+            java.lang.String.class, "_sequenceRef", "sequenceRef",
+            org.exolab.castor.xml.NodeType.Attribute);
+    desc.setImmutable(true);
+    handler = new org.exolab.castor.xml.XMLFieldHandler()
+    {
+      public java.lang.Object getValue(java.lang.Object object)
+              throws IllegalStateException
+      {
+        SequencePoint target = (SequencePoint) object;
+        return target.getSequenceRef();
+      }
+
+      public void setValue(java.lang.Object object, java.lang.Object value)
+              throws IllegalStateException, IllegalArgumentException
+      {
+        try
+        {
+          SequencePoint target = (SequencePoint) object;
+          target.setSequenceRef((java.lang.String) value);
+        } catch (java.lang.Exception ex)
+        {
+          throw new IllegalStateException(ex.toString());
+        }
+      }
+
+      public java.lang.Object newInstance(java.lang.Object parent)
+      {
+        return null;
+      }
+    };
+    desc.setHandler(handler);
+    desc.setMultivalued(false);
+    addFieldDescriptor(desc);
+
+    // -- validation code for: _sequenceRef
+    fieldValidator = new org.exolab.castor.xml.FieldValidator();
+    { // -- local scope
+      org.exolab.castor.xml.validators.StringValidator typeValidator;
+      typeValidator = new org.exolab.castor.xml.validators.StringValidator();
+      fieldValidator.setValidator(typeValidator);
+      typeValidator.setWhiteSpace("preserve");
+    }
+    desc.setValidator(fieldValidator);
+    // -- _xPos
+    desc = new org.exolab.castor.xml.util.XMLFieldDescriptorImpl(
+            java.lang.Float.TYPE, "_xPos", "xPos",
+            org.exolab.castor.xml.NodeType.Attribute);
+    handler = new org.exolab.castor.xml.XMLFieldHandler()
+    {
+      public java.lang.Object getValue(java.lang.Object object)
+              throws IllegalStateException
+      {
+        SequencePoint target = (SequencePoint) object;
+        if (!target.hasXPos())
+        {
+          return null;
+        }
+        return new java.lang.Float(target.getXPos());
+      }
+
+      public void setValue(java.lang.Object object, java.lang.Object value)
+              throws IllegalStateException, IllegalArgumentException
+      {
+        try
+        {
+          SequencePoint target = (SequencePoint) object;
+          // if null, use delete method for optional primitives
+          if (value == null)
+          {
+            target.deleteXPos();
+            return;
+          }
+          target.setXPos(((java.lang.Float) value).floatValue());
+        } catch (java.lang.Exception ex)
+        {
+          throw new IllegalStateException(ex.toString());
+        }
+      }
+
+      public java.lang.Object newInstance(java.lang.Object parent)
+      {
+        return null;
+      }
+    };
+    desc.setHandler(handler);
+    desc.setMultivalued(false);
+    addFieldDescriptor(desc);
+
+    // -- validation code for: _xPos
+    fieldValidator = new org.exolab.castor.xml.FieldValidator();
+    { // -- local scope
+      org.exolab.castor.xml.validators.FloatValidator typeValidator;
+      typeValidator = new org.exolab.castor.xml.validators.FloatValidator();
+      fieldValidator.setValidator(typeValidator);
+      typeValidator.setMinInclusive((float) -3.4028235E38);
+      typeValidator.setMaxInclusive((float) 3.4028235E38);
+    }
+    desc.setValidator(fieldValidator);
+    // -- _yPos
+    desc = new org.exolab.castor.xml.util.XMLFieldDescriptorImpl(
+            java.lang.Float.TYPE, "_yPos", "yPos",
+            org.exolab.castor.xml.NodeType.Attribute);
+    handler = new org.exolab.castor.xml.XMLFieldHandler()
+    {
+      public java.lang.Object getValue(java.lang.Object object)
+              throws IllegalStateException
+      {
+        SequencePoint target = (SequencePoint) object;
+        if (!target.hasYPos())
+        {
+          return null;
+        }
+        return new java.lang.Float(target.getYPos());
+      }
+
+      public void setValue(java.lang.Object object, java.lang.Object value)
+              throws IllegalStateException, IllegalArgumentException
+      {
+        try
+        {
+          SequencePoint target = (SequencePoint) object;
+          // if null, use delete method for optional primitives
+          if (value == null)
+          {
+            target.deleteYPos();
+            return;
+          }
+          target.setYPos(((java.lang.Float) value).floatValue());
+        } catch (java.lang.Exception ex)
+        {
+          throw new IllegalStateException(ex.toString());
+        }
+      }
+
+      public java.lang.Object newInstance(java.lang.Object parent)
+      {
+        return null;
+      }
+    };
+    desc.setHandler(handler);
+    desc.setMultivalued(false);
+    addFieldDescriptor(desc);
+
+    // -- validation code for: _yPos
+    fieldValidator = new org.exolab.castor.xml.FieldValidator();
+    { // -- local scope
+      org.exolab.castor.xml.validators.FloatValidator typeValidator;
+      typeValidator = new org.exolab.castor.xml.validators.FloatValidator();
+      fieldValidator.setValidator(typeValidator);
+      typeValidator.setMinInclusive((float) -3.4028235E38);
+      typeValidator.setMaxInclusive((float) 3.4028235E38);
+    }
+    desc.setValidator(fieldValidator);
+    // -- _zPos
+    desc = new org.exolab.castor.xml.util.XMLFieldDescriptorImpl(
+            java.lang.Float.TYPE, "_zPos", "zPos",
+            org.exolab.castor.xml.NodeType.Attribute);
+    handler = new org.exolab.castor.xml.XMLFieldHandler()
+    {
+      public java.lang.Object getValue(java.lang.Object object)
+              throws IllegalStateException
+      {
+        SequencePoint target = (SequencePoint) object;
+        if (!target.hasZPos())
+        {
+          return null;
+        }
+        return new java.lang.Float(target.getZPos());
+      }
+
+      public void setValue(java.lang.Object object, java.lang.Object value)
+              throws IllegalStateException, IllegalArgumentException
+      {
+        try
+        {
+          SequencePoint target = (SequencePoint) object;
+          // if null, use delete method for optional primitives
+          if (value == null)
+          {
+            target.deleteZPos();
+            return;
+          }
+          target.setZPos(((java.lang.Float) value).floatValue());
+        } catch (java.lang.Exception ex)
+        {
+          throw new IllegalStateException(ex.toString());
+        }
+      }
+
+      public java.lang.Object newInstance(java.lang.Object parent)
+      {
+        return null;
+      }
+    };
+    desc.setHandler(handler);
+    desc.setMultivalued(false);
+    addFieldDescriptor(desc);
+
+    // -- validation code for: _zPos
+    fieldValidator = new org.exolab.castor.xml.FieldValidator();
+    { // -- local scope
+      org.exolab.castor.xml.validators.FloatValidator typeValidator;
+      typeValidator = new org.exolab.castor.xml.validators.FloatValidator();
+      fieldValidator.setValidator(typeValidator);
+      typeValidator.setMinInclusive((float) -3.4028235E38);
+      typeValidator.setMaxInclusive((float) 3.4028235E38);
+    }
+    desc.setValidator(fieldValidator);
+    // -- initialize element descriptors
+
+  }
+
+  // -----------/
+  // - Methods -/
+  // -----------/
+
+  /**
+   * Method getAccessMode.
+   * 
+   * @return the access mode specified for this class.
+   */
+  public org.exolab.castor.mapping.AccessMode getAccessMode()
+  {
+    return null;
+  }
+
+  /**
+   * Method getIdentity.
+   * 
+   * @return the identity field, null if this class has no identity.
+   */
+  public org.exolab.castor.mapping.FieldDescriptor getIdentity()
+  {
+    return super.getIdentity();
+  }
+
+  /**
+   * Method getJavaClass.
+   * 
+   * @return the Java class represented by this descriptor.
+   */
+  public java.lang.Class getJavaClass()
+  {
+    return jalview.schemabinding.version2.SequencePoint.class;
+  }
+
+  /**
+   * Method getNameSpacePrefix.
+   * 
+   * @return the namespace prefix to use when marshaling as XML.
+   */
+  public java.lang.String getNameSpacePrefix()
+  {
+    return _nsPrefix;
+  }
+
+  /**
+   * Method getNameSpaceURI.
+   * 
+   * @return the namespace URI used when marshaling and unmarshaling as XML.
+   */
+  public java.lang.String getNameSpaceURI()
+  {
+    return _nsURI;
+  }
+
+  /**
+   * Method getValidator.
+   * 
+   * @return a specific validator for the class described by this
+   *         ClassDescriptor.
+   */
+  public org.exolab.castor.xml.TypeValidator getValidator()
+  {
+    return this;
+  }
+
+  /**
+   * Method getXMLName.
+   * 
+   * @return the XML Name for the Class being described.
+   */
+  public java.lang.String getXMLName()
+  {
+    return _xmlName;
+  }
+
+  /**
+   * Method isElementDefinition.
+   * 
+   * @return true if XML schema definition of this Class is that of a global
+   *         element or element with anonymous type definition.
+   */
+  public boolean isElementDefinition()
+  {
+    return _elementDefinition;
+  }
+
+}
diff --git a/src/jalview/schemabinding/version2/descriptors/TridiagonalMatrixDescriptor.java b/src/jalview/schemabinding/version2/descriptors/TridiagonalMatrixDescriptor.java
new file mode 100644 (file)
index 0000000..3abbeab
--- /dev/null
@@ -0,0 +1,149 @@
+/*
+ * This class was automatically generated with 
+ * <a href="http://www.castor.org">Castor 1.1</a>, using an XML
+ * Schema.
+ * $Id$
+ */
+
+package jalview.schemabinding.version2.descriptors;
+
+//---------------------------------/
+//- Imported classes and packages -/
+//---------------------------------/
+
+import jalview.schemabinding.version2.TridiagonalMatrix;
+
+/**
+ * Class TridiagonalMatrixDescriptor.
+ * 
+ * @version $Revision$ $Date$
+ */
+public class TridiagonalMatrixDescriptor extends
+        jalview.schemabinding.version2.descriptors.DoubleMatrixDescriptor
+{
+
+  // --------------------------/
+  // - Class/Member Variables -/
+  // --------------------------/
+
+  /**
+   * Field _elementDefinition.
+   */
+  private boolean _elementDefinition;
+
+  /**
+   * Field _nsPrefix.
+   */
+  private java.lang.String _nsPrefix;
+
+  /**
+   * Field _nsURI.
+   */
+  private java.lang.String _nsURI;
+
+  /**
+   * Field _xmlName.
+   */
+  private java.lang.String _xmlName;
+
+  // ----------------/
+  // - Constructors -/
+  // ----------------/
+
+  public TridiagonalMatrixDescriptor()
+  {
+    super();
+    setExtendsWithoutFlatten(
+            new jalview.schemabinding.version2.descriptors.DoubleMatrixDescriptor());
+    _nsURI = "www.jalview.org";
+    _xmlName = "tridiagonalMatrix";
+    _elementDefinition = true;
+  }
+
+  // -----------/
+  // - Methods -/
+  // -----------/
+
+  /**
+   * Method getAccessMode.
+   * 
+   * @return the access mode specified for this class.
+   */
+  public org.exolab.castor.mapping.AccessMode getAccessMode()
+  {
+    return null;
+  }
+
+  /**
+   * Method getIdentity.
+   * 
+   * @return the identity field, null if this class has no identity.
+   */
+  public org.exolab.castor.mapping.FieldDescriptor getIdentity()
+  {
+    return super.getIdentity();
+  }
+
+  /**
+   * Method getJavaClass.
+   * 
+   * @return the Java class represented by this descriptor.
+   */
+  public java.lang.Class getJavaClass()
+  {
+    return jalview.schemabinding.version2.TridiagonalMatrix.class;
+  }
+
+  /**
+   * Method getNameSpacePrefix.
+   * 
+   * @return the namespace prefix to use when marshaling as XML.
+   */
+  public java.lang.String getNameSpacePrefix()
+  {
+    return _nsPrefix;
+  }
+
+  /**
+   * Method getNameSpaceURI.
+   * 
+   * @return the namespace URI used when marshaling and unmarshaling as XML.
+   */
+  public java.lang.String getNameSpaceURI()
+  {
+    return _nsURI;
+  }
+
+  /**
+   * Method getValidator.
+   * 
+   * @return a specific validator for the class described by this
+   *         ClassDescriptor.
+   */
+  public org.exolab.castor.xml.TypeValidator getValidator()
+  {
+    return this;
+  }
+
+  /**
+   * Method getXMLName.
+   * 
+   * @return the XML Name for the Class being described.
+   */
+  public java.lang.String getXMLName()
+  {
+    return _xmlName;
+  }
+
+  /**
+   * Method isElementDefinition.
+   * 
+   * @return true if XML schema definition of this Class is that of a global
+   *         element or element with anonymous type definition.
+   */
+  public boolean isElementDefinition()
+  {
+    return _elementDefinition;
+  }
+
+}
index 5e7fca2..1693294 100644 (file)
@@ -25,31 +25,39 @@ import jalview.api.RotatableCanvasI;
 import jalview.api.analysis.ScoreModelI;
 import jalview.api.analysis.SimilarityParamsI;
 import jalview.datamodel.AlignmentView;
+import jalview.datamodel.Point;
 import jalview.datamodel.SequenceI;
 import jalview.datamodel.SequencePoint;
 
+import java.util.List;
 import java.util.Vector;
 
 public class PCAModel
 {
-  private volatile PCA pca;
-
-  int top;
+  /*
+   * inputs
+   */
+  private AlignmentView inputData;
 
-  AlignmentView seqstrings;
+  private final SequenceI[] seqs;
 
-  SequenceI[] seqs;
+  private final SimilarityParamsI similarityParams;
 
   /*
-   * Name of score model used to calculate PCA
+   * options - score model, nucleotide / protein
    */
-  ScoreModelI scoreModel;
+  private ScoreModelI scoreModel;
 
   private boolean nucleotide = false;
 
-  private Vector<SequencePoint> points;
+  /*
+   * outputs
+   */
+  private PCA pca;
 
-  private SimilarityParamsI similarityParams;
+  int top;
+
+  private List<SequencePoint> points;
 
   /**
    * Constructor given sequence data, score model and score calculation
@@ -64,17 +72,21 @@ public class PCAModel
   public PCAModel(AlignmentView seqData, SequenceI[] sqs, boolean nuc,
           ScoreModelI modelName, SimilarityParamsI params)
   {
-    seqstrings = seqData;
+    inputData = seqData;
     seqs = sqs;
     nucleotide = nuc;
     scoreModel = modelName;
     similarityParams = params;
   }
 
-  public void run()
+  /**
+   * Performs the PCA calculation (in the same thread) and extracts result data
+   * needed for visualisation by PCAPanel
+   */
+  public void calculate()
   {
-    pca = new PCA(seqstrings, scoreModel, similarityParams);
-    pca.run();
+    pca = new PCA(inputData, scoreModel, similarityParams);
+    pca.run(); // executes in same thread, wait for completion
 
     // Now find the component coordinates
     int ii = 0;
@@ -88,13 +100,13 @@ public class PCAModel
     // top = pca.getM().height() - 1;
     top = height - 1;
 
-    points = new Vector<SequencePoint>();
-    float[][] scores = pca.getComponents(top - 1, top - 2, top - 3, 100);
+    points = new Vector<>();
+    Point[] scores = pca.getComponents(top - 1, top - 2, top - 3, 100);
 
     for (int i = 0; i < height; i++)
     {
       SequencePoint sp = new SequencePoint(seqs[i], scores[i]);
-      points.addElement(sp);
+      points.add(sp);
     }
   }
 
@@ -114,17 +126,22 @@ public class PCAModel
   }
 
   /**
+   * Answers the index of the principal dimension of the PCA
    * 
-   * 
-   * @return index of principle dimension of PCA
+   * @return
    */
   public int getTop()
   {
     return top;
   }
 
+  public void setTop(int t)
+  {
+    top = t;
+  }
+
   /**
-   * update the 2d coordinates for the list of points to the given dimensions
+   * Updates the 3D coordinates for the list of points to the given dimensions.
    * Principal dimension is getTop(). Next greatest eigenvector is getTop()-1.
    * Note - pca.getComponents starts counting the spectrum from rank-2 to zero,
    * rather than rank-1, so getComponents(dimN ...) == updateRcView(dimN+1 ..)
@@ -136,11 +153,11 @@ public class PCAModel
   public void updateRcView(int dim1, int dim2, int dim3)
   {
     // note: actual indices for components are dim1-1, etc (patch for JAL-1123)
-    float[][] scores = pca.getComponents(dim1 - 1, dim2 - 1, dim3 - 1, 100);
+    Point[] scores = pca.getComponents(dim1 - 1, dim2 - 1, dim3 - 1, 100);
 
     for (int i = 0; i < pca.getHeight(); i++)
     {
-      points.elementAt(i).coord = scores[i];
+      points.get(i).coord = scores[i];
     }
   }
 
@@ -149,9 +166,14 @@ public class PCAModel
     return pca.getDetails();
   }
 
-  public AlignmentView getSeqtrings()
+  public AlignmentView getInputData()
+  {
+    return inputData;
+  }
+
+  public void setInputData(AlignmentView data)
   {
-    return seqstrings;
+    inputData = data;
   }
 
   public String getPointsasCsv(boolean transformed, int xdim, int ydim,
@@ -192,42 +214,58 @@ public class PCAModel
       }
       else
       {
-        // output current x,y,z coords for points
-        fl = getPointPosition(s);
-        for (int d = 0; d < fl.length; d++)
-        {
-          csv.append(",");
-          csv.append(fl[d]);
-        }
+        Point p = points.get(s).coord;
+        csv.append(",").append(p.x);
+        csv.append(",").append(p.y);
+        csv.append(",").append(p.z);
       }
       csv.append("\n");
     }
     return csv.toString();
   }
 
+  public String getScoreModelName()
+  {
+    return scoreModel == null ? "" : scoreModel.getName();
+  }
+
+  public void setScoreModel(ScoreModelI sm)
+  {
+    this.scoreModel = sm;
+  }
+
   /**
+   * Answers the parameters configured for pairwise similarity calculations
    * 
-   * @return x,y,z positions of point s (index into points) under current
-   *         transform.
+   * @return
    */
-  public double[] getPointPosition(int s)
+  public SimilarityParamsI getSimilarityParameters()
   {
-    double pts[] = new double[3];
-    float[] p = points.elementAt(s).coord;
-    pts[0] = p[0];
-    pts[1] = p[1];
-    pts[2] = p[2];
-    return pts;
+    return similarityParams;
   }
 
-  public String getScoreModelName()
+  public List<SequencePoint> getSequencePoints()
   {
-    return scoreModel == null ? "" : scoreModel.getName();
+    return points;
   }
 
-  public void setScoreModel(ScoreModelI sm)
+  public void setSequencePoints(List<SequencePoint> sp)
   {
-    this.scoreModel = sm;
+    points = sp;
+  }
+
+  /**
+   * Answers the object holding the values of the computed PCA
+   * 
+   * @return
+   */
+  public PCA getPcaData()
+  {
+    return pca;
   }
 
+  public void setPCA(PCA data)
+  {
+    pca = data;
+  }
 }
index 061e70c..41e4d0d 100644 (file)
@@ -670,7 +670,8 @@ public class DBRefFetcher implements Runnable
             int startShift = absStart - sequenceStart + 1;
             if (startShift != 0)
             {
-              modified |= sequence.getFeatures().shiftFeatures(startShift);
+              modified |= sequence.getFeatures().shiftFeatures(1,
+                      startShift);
             }
           }
         }
index 370ecc5..83f1ee2 100644 (file)
@@ -2,7 +2,7 @@
 // This file was generated by the JavaTM Architecture for XML Binding(JAXB) Reference Implementation, v2.2.8-b130911.1802 
 // See <a href="http://java.sun.com/xml/jaxb">http://java.sun.com/xml/jaxb</a> 
 // Any modifications to this file will be lost upon recompilation of the source schema. 
-// Generated on: 2018.09.28 at 12:18:54 PM BST 
+// Generated on: 2018.12.20 at 11:47:26 AM GMT 
 //
 
 
index 148406e..0dbcad0 100644 (file)
@@ -2,7 +2,7 @@
 // This file was generated by the JavaTM Architecture for XML Binding(JAXB) Reference Implementation, v2.2.8-b130911.1802 
 // See <a href="http://java.sun.com/xml/jaxb">http://java.sun.com/xml/jaxb</a> 
 // Any modifications to this file will be lost upon recompilation of the source schema. 
-// Generated on: 2018.09.28 at 12:18:54 PM BST 
+// Generated on: 2018.12.20 at 11:47:26 AM GMT 
 //
 
 
index c9ee5f1..44affa2 100644 (file)
@@ -2,7 +2,7 @@
 // This file was generated by the JavaTM Architecture for XML Binding(JAXB) Reference Implementation, v2.2.8-b130911.1802 
 // See <a href="http://java.sun.com/xml/jaxb">http://java.sun.com/xml/jaxb</a> 
 // Any modifications to this file will be lost upon recompilation of the source schema. 
-// Generated on: 2018.09.28 at 12:18:54 PM BST 
+// Generated on: 2018.12.20 at 11:47:26 AM GMT 
 //
 
 
index 8cbd4fe..de408d2 100644 (file)
@@ -2,7 +2,7 @@
 // This file was generated by the JavaTM Architecture for XML Binding(JAXB) Reference Implementation, v2.2.8-b130911.1802 
 // See <a href="http://java.sun.com/xml/jaxb">http://java.sun.com/xml/jaxb</a> 
 // Any modifications to this file will be lost upon recompilation of the source schema. 
-// Generated on: 2018.09.28 at 12:18:54 PM BST 
+// Generated on: 2018.12.20 at 11:47:26 AM GMT 
 //
 
 
diff --git a/src/jalview/xml/binding/jalview/DoubleMatrix.java b/src/jalview/xml/binding/jalview/DoubleMatrix.java
new file mode 100644 (file)
index 0000000..b4c07bc
--- /dev/null
@@ -0,0 +1,186 @@
+//
+// This file was generated by the JavaTM Architecture for XML Binding(JAXB) Reference Implementation, v2.2.8-b130911.1802 
+// See <a href="http://java.sun.com/xml/jaxb">http://java.sun.com/xml/jaxb</a> 
+// Any modifications to this file will be lost upon recompilation of the source schema. 
+// Generated on: 2018.12.20 at 11:47:26 AM GMT 
+//
+
+
+package jalview.xml.binding.jalview;
+
+import java.util.ArrayList;
+import java.util.List;
+import javax.xml.bind.annotation.XmlAccessType;
+import javax.xml.bind.annotation.XmlAccessorType;
+import javax.xml.bind.annotation.XmlAttribute;
+import javax.xml.bind.annotation.XmlElement;
+import javax.xml.bind.annotation.XmlType;
+
+
+/**
+ * <p>Java class for DoubleMatrix complex type.
+ * 
+ * <p>The following schema fragment specifies the expected content contained within this class.
+ * 
+ * <pre>
+ * &lt;complexType name="DoubleMatrix">
+ *   &lt;complexContent>
+ *     &lt;restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
+ *       &lt;sequence>
+ *         &lt;element name="row" type="{www.jalview.org}DoubleVector" maxOccurs="unbounded" minOccurs="0"/>
+ *         &lt;element name="D" type="{www.jalview.org}DoubleVector" minOccurs="0"/>
+ *         &lt;element name="E" type="{www.jalview.org}DoubleVector" minOccurs="0"/>
+ *       &lt;/sequence>
+ *       &lt;attribute name="rows" type="{http://www.w3.org/2001/XMLSchema}int" />
+ *       &lt;attribute name="columns" type="{http://www.w3.org/2001/XMLSchema}int" />
+ *     &lt;/restriction>
+ *   &lt;/complexContent>
+ * &lt;/complexType>
+ * </pre>
+ * 
+ * 
+ */
+@XmlAccessorType(XmlAccessType.FIELD)
+@XmlType(name = "DoubleMatrix", namespace = "www.jalview.org", propOrder = {
+    "row",
+    "d",
+    "e"
+})
+public class DoubleMatrix {
+
+    protected List<DoubleVector> row;
+    @XmlElement(name = "D")
+    protected DoubleVector d;
+    @XmlElement(name = "E")
+    protected DoubleVector e;
+    @XmlAttribute(name = "rows")
+    protected Integer rows;
+    @XmlAttribute(name = "columns")
+    protected Integer columns;
+
+    /**
+     * Gets the value of the row property.
+     * 
+     * <p>
+     * This accessor method returns a reference to the live list,
+     * not a snapshot. Therefore any modification you make to the
+     * returned list will be present inside the JAXB object.
+     * This is why there is not a <CODE>set</CODE> method for the row property.
+     * 
+     * <p>
+     * For example, to add a new item, do as follows:
+     * <pre>
+     *    getRow().add(newItem);
+     * </pre>
+     * 
+     * 
+     * <p>
+     * Objects of the following type(s) are allowed in the list
+     * {@link DoubleVector }
+     * 
+     * 
+     */
+    public List<DoubleVector> getRow() {
+        if (row == null) {
+            row = new ArrayList<DoubleVector>();
+        }
+        return this.row;
+    }
+
+    /**
+     * Gets the value of the d property.
+     * 
+     * @return
+     *     possible object is
+     *     {@link DoubleVector }
+     *     
+     */
+    public DoubleVector getD() {
+        return d;
+    }
+
+    /**
+     * Sets the value of the d property.
+     * 
+     * @param value
+     *     allowed object is
+     *     {@link DoubleVector }
+     *     
+     */
+    public void setD(DoubleVector value) {
+        this.d = value;
+    }
+
+    /**
+     * Gets the value of the e property.
+     * 
+     * @return
+     *     possible object is
+     *     {@link DoubleVector }
+     *     
+     */
+    public DoubleVector getE() {
+        return e;
+    }
+
+    /**
+     * Sets the value of the e property.
+     * 
+     * @param value
+     *     allowed object is
+     *     {@link DoubleVector }
+     *     
+     */
+    public void setE(DoubleVector value) {
+        this.e = value;
+    }
+
+    /**
+     * Gets the value of the rows property.
+     * 
+     * @return
+     *     possible object is
+     *     {@link Integer }
+     *     
+     */
+    public Integer getRows() {
+        return rows;
+    }
+
+    /**
+     * Sets the value of the rows property.
+     * 
+     * @param value
+     *     allowed object is
+     *     {@link Integer }
+     *     
+     */
+    public void setRows(Integer value) {
+        this.rows = value;
+    }
+
+    /**
+     * Gets the value of the columns property.
+     * 
+     * @return
+     *     possible object is
+     *     {@link Integer }
+     *     
+     */
+    public Integer getColumns() {
+        return columns;
+    }
+
+    /**
+     * Sets the value of the columns property.
+     * 
+     * @param value
+     *     allowed object is
+     *     {@link Integer }
+     *     
+     */
+    public void setColumns(Integer value) {
+        this.columns = value;
+    }
+
+}
diff --git a/src/jalview/xml/binding/jalview/DoubleVector.java b/src/jalview/xml/binding/jalview/DoubleVector.java
new file mode 100644 (file)
index 0000000..e2592ab
--- /dev/null
@@ -0,0 +1,76 @@
+//
+// This file was generated by the JavaTM Architecture for XML Binding(JAXB) Reference Implementation, v2.2.8-b130911.1802 
+// See <a href="http://java.sun.com/xml/jaxb">http://java.sun.com/xml/jaxb</a> 
+// Any modifications to this file will be lost upon recompilation of the source schema. 
+// Generated on: 2018.12.20 at 11:47:26 AM GMT 
+//
+
+
+package jalview.xml.binding.jalview;
+
+import java.util.ArrayList;
+import java.util.List;
+import javax.xml.bind.annotation.XmlAccessType;
+import javax.xml.bind.annotation.XmlAccessorType;
+import javax.xml.bind.annotation.XmlElement;
+import javax.xml.bind.annotation.XmlType;
+
+
+/**
+ * <p>Java class for DoubleVector complex type.
+ * 
+ * <p>The following schema fragment specifies the expected content contained within this class.
+ * 
+ * <pre>
+ * &lt;complexType name="DoubleVector">
+ *   &lt;complexContent>
+ *     &lt;restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
+ *       &lt;sequence>
+ *         &lt;element name="v" type="{http://www.w3.org/2001/XMLSchema}double" maxOccurs="unbounded" minOccurs="0"/>
+ *       &lt;/sequence>
+ *     &lt;/restriction>
+ *   &lt;/complexContent>
+ * &lt;/complexType>
+ * </pre>
+ * 
+ * 
+ */
+@XmlAccessorType(XmlAccessType.FIELD)
+@XmlType(name = "DoubleVector", namespace = "www.jalview.org", propOrder = {
+    "v"
+})
+public class DoubleVector {
+
+    @XmlElement(type = Double.class)
+    protected List<Double> v;
+
+    /**
+     * Gets the value of the v property.
+     * 
+     * <p>
+     * This accessor method returns a reference to the live list,
+     * not a snapshot. Therefore any modification you make to the
+     * returned list will be present inside the JAXB object.
+     * This is why there is not a <CODE>set</CODE> method for the v property.
+     * 
+     * <p>
+     * For example, to add a new item, do as follows:
+     * <pre>
+     *    getV().add(newItem);
+     * </pre>
+     * 
+     * 
+     * <p>
+     * Objects of the following type(s) are allowed in the list
+     * {@link Double }
+     * 
+     * 
+     */
+    public List<Double> getV() {
+        if (v == null) {
+            v = new ArrayList<Double>();
+        }
+        return this.v;
+    }
+
+}
index 7585f83..9001ee2 100644 (file)
@@ -2,7 +2,7 @@
 // This file was generated by the JavaTM Architecture for XML Binding(JAXB) Reference Implementation, v2.2.8-b130911.1802 
 // See <a href="http://java.sun.com/xml/jaxb">http://java.sun.com/xml/jaxb</a> 
 // Any modifications to this file will be lost upon recompilation of the source schema. 
-// Generated on: 2018.09.28 at 12:18:54 PM BST 
+// Generated on: 2018.12.20 at 11:47:26 AM GMT 
 //
 
 
index 3161408..0daf56a 100644 (file)
@@ -2,7 +2,7 @@
 // This file was generated by the JavaTM Architecture for XML Binding(JAXB) Reference Implementation, v2.2.8-b130911.1802 
 // See <a href="http://java.sun.com/xml/jaxb">http://java.sun.com/xml/jaxb</a> 
 // Any modifications to this file will be lost upon recompilation of the source schema. 
-// Generated on: 2018.09.28 at 12:18:54 PM BST 
+// Generated on: 2018.12.20 at 11:47:26 AM GMT 
 //
 
 
index 5e181a1..bf69d5b 100644 (file)
@@ -2,7 +2,7 @@
 // This file was generated by the JavaTM Architecture for XML Binding(JAXB) Reference Implementation, v2.2.8-b130911.1802 
 // See <a href="http://java.sun.com/xml/jaxb">http://java.sun.com/xml/jaxb</a> 
 // Any modifications to this file will be lost upon recompilation of the source schema. 
-// Generated on: 2018.09.28 at 12:18:54 PM BST 
+// Generated on: 2018.12.20 at 11:47:26 AM GMT 
 //
 
 
index a854b63..5684acf 100644 (file)
@@ -2,7 +2,7 @@
 // This file was generated by the JavaTM Architecture for XML Binding(JAXB) Reference Implementation, v2.2.8-b130911.1802 
 // See <a href="http://java.sun.com/xml/jaxb">http://java.sun.com/xml/jaxb</a> 
 // Any modifications to this file will be lost upon recompilation of the source schema. 
-// Generated on: 2018.09.28 at 12:18:54 PM BST 
+// Generated on: 2018.12.20 at 11:47:26 AM GMT 
 //
 
 
index 0f538f2..ed57edc 100644 (file)
@@ -2,7 +2,7 @@
 // This file was generated by the JavaTM Architecture for XML Binding(JAXB) Reference Implementation, v2.2.8-b130911.1802 
 // See <a href="http://java.sun.com/xml/jaxb">http://java.sun.com/xml/jaxb</a> 
 // Any modifications to this file will be lost upon recompilation of the source schema. 
-// Generated on: 2018.09.28 at 12:18:54 PM BST 
+// Generated on: 2018.12.20 at 11:47:26 AM GMT 
 //
 
 
@@ -243,6 +243,66 @@ import javax.xml.datatype.XMLGregorianCalendar;
  *                   &lt;attribute name="fitToWindow" type="{http://www.w3.org/2001/XMLSchema}boolean" />
  *                   &lt;attribute name="currentTree" type="{http://www.w3.org/2001/XMLSchema}boolean" />
  *                   &lt;attribute name="id" type="{http://www.w3.org/2001/XMLSchema}ID" />
+ *                   &lt;attribute name="linkToAllViews" type="{http://www.w3.org/2001/XMLSchema}boolean" default="false" />
+ *                 &lt;/restriction>
+ *               &lt;/complexContent>
+ *             &lt;/complexType>
+ *           &lt;/element>
+ *           &lt;element name="PcaViewer" maxOccurs="unbounded" minOccurs="0">
+ *             &lt;complexType>
+ *               &lt;complexContent>
+ *                 &lt;restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
+ *                   &lt;sequence>
+ *                     &lt;element name="sequencePoint" maxOccurs="unbounded">
+ *                       &lt;complexType>
+ *                         &lt;complexContent>
+ *                           &lt;restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
+ *                             &lt;attGroup ref="{www.jalview.org}position"/>
+ *                             &lt;attribute name="sequenceRef" type="{http://www.w3.org/2001/XMLSchema}string" />
+ *                           &lt;/restriction>
+ *                         &lt;/complexContent>
+ *                       &lt;/complexType>
+ *                     &lt;/element>
+ *                     &lt;element name="axis" maxOccurs="3" minOccurs="3">
+ *                       &lt;complexType>
+ *                         &lt;complexContent>
+ *                           &lt;restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
+ *                             &lt;attGroup ref="{www.jalview.org}position"/>
+ *                           &lt;/restriction>
+ *                         &lt;/complexContent>
+ *                       &lt;/complexType>
+ *                     &lt;/element>
+ *                     &lt;element name="seqPointMin">
+ *                       &lt;complexType>
+ *                         &lt;complexContent>
+ *                           &lt;restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
+ *                             &lt;attGroup ref="{www.jalview.org}position"/>
+ *                           &lt;/restriction>
+ *                         &lt;/complexContent>
+ *                       &lt;/complexType>
+ *                     &lt;/element>
+ *                     &lt;element name="seqPointMax">
+ *                       &lt;complexType>
+ *                         &lt;complexContent>
+ *                           &lt;restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
+ *                             &lt;attGroup ref="{www.jalview.org}position"/>
+ *                           &lt;/restriction>
+ *                         &lt;/complexContent>
+ *                       &lt;/complexType>
+ *                     &lt;/element>
+ *                     &lt;element name="pcaData" type="{www.jalview.org}PcaDataType"/>
+ *                   &lt;/sequence>
+ *                   &lt;attGroup ref="{www.jalview.org}swingwindow"/>
+ *                   &lt;attGroup ref="{www.jalview.org}SimilarityParams"/>
+ *                   &lt;attribute name="title" type="{http://www.w3.org/2001/XMLSchema}string" />
+ *                   &lt;attribute name="scoreModelName" type="{http://www.w3.org/2001/XMLSchema}string" />
+ *                   &lt;attribute name="xDim" type="{http://www.w3.org/2001/XMLSchema}int" />
+ *                   &lt;attribute name="yDim" type="{http://www.w3.org/2001/XMLSchema}int" />
+ *                   &lt;attribute name="zDim" type="{http://www.w3.org/2001/XMLSchema}int" />
+ *                   &lt;attribute name="bgColour" type="{http://www.w3.org/2001/XMLSchema}int" />
+ *                   &lt;attribute name="scaleFactor" type="{http://www.w3.org/2001/XMLSchema}float" />
+ *                   &lt;attribute name="showLabels" type="{http://www.w3.org/2001/XMLSchema}boolean" />
+ *                   &lt;attribute name="linkToAllViews" type="{http://www.w3.org/2001/XMLSchema}boolean" />
  *                 &lt;/restriction>
  *               &lt;/complexContent>
  *             &lt;/complexType>
@@ -310,6 +370,7 @@ import javax.xml.datatype.XMLGregorianCalendar;
     "viewport",
     "userColours",
     "tree",
+    "pcaViewer",
     "featureSettings"
 })
 public class JalviewModel {
@@ -330,6 +391,8 @@ public class JalviewModel {
     @XmlElement(name = "UserColours")
     protected List<JalviewModel.UserColours> userColours;
     protected List<JalviewModel.Tree> tree;
+    @XmlElement(name = "PcaViewer")
+    protected List<JalviewModel.PcaViewer> pcaViewer;
     @XmlElement(name = "FeatureSettings")
     protected JalviewModel.FeatureSettings featureSettings;
 
@@ -551,6 +614,35 @@ public class JalviewModel {
     }
 
     /**
+     * Gets the value of the pcaViewer property.
+     * 
+     * <p>
+     * This accessor method returns a reference to the live list,
+     * not a snapshot. Therefore any modification you make to the
+     * returned list will be present inside the JAXB object.
+     * This is why there is not a <CODE>set</CODE> method for the pcaViewer property.
+     * 
+     * <p>
+     * For example, to add a new item, do as follows:
+     * <pre>
+     *    getPcaViewer().add(newItem);
+     * </pre>
+     * 
+     * 
+     * <p>
+     * Objects of the following type(s) are allowed in the list
+     * {@link JalviewModel.PcaViewer }
+     * 
+     * 
+     */
+    public List<JalviewModel.PcaViewer> getPcaViewer() {
+        if (pcaViewer == null) {
+            pcaViewer = new ArrayList<JalviewModel.PcaViewer>();
+        }
+        return this.pcaViewer;
+    }
+
+    /**
      * Gets the value of the featureSettings property.
      * 
      * @return
@@ -2974,21 +3066,57 @@ public class JalviewModel {
      * &lt;complexType>
      *   &lt;complexContent>
      *     &lt;restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
-     *       &lt;sequence minOccurs="0">
-     *         &lt;element name="title" type="{http://www.w3.org/2001/XMLSchema}string"/>
-     *         &lt;element name="newick" type="{http://www.w3.org/2001/XMLSchema}string"/>
+     *       &lt;sequence>
+     *         &lt;element name="sequencePoint" maxOccurs="unbounded">
+     *           &lt;complexType>
+     *             &lt;complexContent>
+     *               &lt;restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
+     *                 &lt;attGroup ref="{www.jalview.org}position"/>
+     *                 &lt;attribute name="sequenceRef" type="{http://www.w3.org/2001/XMLSchema}string" />
+     *               &lt;/restriction>
+     *             &lt;/complexContent>
+     *           &lt;/complexType>
+     *         &lt;/element>
+     *         &lt;element name="axis" maxOccurs="3" minOccurs="3">
+     *           &lt;complexType>
+     *             &lt;complexContent>
+     *               &lt;restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
+     *                 &lt;attGroup ref="{www.jalview.org}position"/>
+     *               &lt;/restriction>
+     *             &lt;/complexContent>
+     *           &lt;/complexType>
+     *         &lt;/element>
+     *         &lt;element name="seqPointMin">
+     *           &lt;complexType>
+     *             &lt;complexContent>
+     *               &lt;restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
+     *                 &lt;attGroup ref="{www.jalview.org}position"/>
+     *               &lt;/restriction>
+     *             &lt;/complexContent>
+     *           &lt;/complexType>
+     *         &lt;/element>
+     *         &lt;element name="seqPointMax">
+     *           &lt;complexType>
+     *             &lt;complexContent>
+     *               &lt;restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
+     *                 &lt;attGroup ref="{www.jalview.org}position"/>
+     *               &lt;/restriction>
+     *             &lt;/complexContent>
+     *           &lt;/complexType>
+     *         &lt;/element>
+     *         &lt;element name="pcaData" type="{www.jalview.org}PcaDataType"/>
      *       &lt;/sequence>
      *       &lt;attGroup ref="{www.jalview.org}swingwindow"/>
-     *       &lt;attribute name="fontName" type="{http://www.w3.org/2001/XMLSchema}string" />
-     *       &lt;attribute name="fontSize" type="{http://www.w3.org/2001/XMLSchema}int" />
-     *       &lt;attribute name="fontStyle" type="{http://www.w3.org/2001/XMLSchema}int" />
-     *       &lt;attribute name="threshold" type="{http://www.w3.org/2001/XMLSchema}float" />
-     *       &lt;attribute name="showBootstrap" type="{http://www.w3.org/2001/XMLSchema}boolean" />
-     *       &lt;attribute name="showDistances" type="{http://www.w3.org/2001/XMLSchema}boolean" />
-     *       &lt;attribute name="markUnlinked" type="{http://www.w3.org/2001/XMLSchema}boolean" />
-     *       &lt;attribute name="fitToWindow" type="{http://www.w3.org/2001/XMLSchema}boolean" />
-     *       &lt;attribute name="currentTree" type="{http://www.w3.org/2001/XMLSchema}boolean" />
-     *       &lt;attribute name="id" type="{http://www.w3.org/2001/XMLSchema}ID" />
+     *       &lt;attGroup ref="{www.jalview.org}SimilarityParams"/>
+     *       &lt;attribute name="title" type="{http://www.w3.org/2001/XMLSchema}string" />
+     *       &lt;attribute name="scoreModelName" type="{http://www.w3.org/2001/XMLSchema}string" />
+     *       &lt;attribute name="xDim" type="{http://www.w3.org/2001/XMLSchema}int" />
+     *       &lt;attribute name="yDim" type="{http://www.w3.org/2001/XMLSchema}int" />
+     *       &lt;attribute name="zDim" type="{http://www.w3.org/2001/XMLSchema}int" />
+     *       &lt;attribute name="bgColour" type="{http://www.w3.org/2001/XMLSchema}int" />
+     *       &lt;attribute name="scaleFactor" type="{http://www.w3.org/2001/XMLSchema}float" />
+     *       &lt;attribute name="showLabels" type="{http://www.w3.org/2001/XMLSchema}boolean" />
+     *       &lt;attribute name="linkToAllViews" type="{http://www.w3.org/2001/XMLSchema}boolean" />
      *     &lt;/restriction>
      *   &lt;/complexContent>
      * &lt;/complexType>
@@ -2998,38 +3126,42 @@ public class JalviewModel {
      */
     @XmlAccessorType(XmlAccessType.FIELD)
     @XmlType(name = "", propOrder = {
-        "title",
-        "newick"
+        "sequencePoint",
+        "axis",
+        "seqPointMin",
+        "seqPointMax",
+        "pcaData"
     })
-    public static class Tree {
+    public static class PcaViewer {
 
-        @XmlElement(namespace = "www.jalview.org")
+        @XmlElement(namespace = "www.jalview.org", required = true)
+        protected List<JalviewModel.PcaViewer.SequencePoint> sequencePoint;
+        @XmlElement(namespace = "www.jalview.org", required = true)
+        protected List<JalviewModel.PcaViewer.Axis> axis;
+        @XmlElement(namespace = "www.jalview.org", required = true)
+        protected JalviewModel.PcaViewer.SeqPointMin seqPointMin;
+        @XmlElement(namespace = "www.jalview.org", required = true)
+        protected JalviewModel.PcaViewer.SeqPointMax seqPointMax;
+        @XmlElement(namespace = "www.jalview.org", required = true)
+        protected PcaDataType pcaData;
+        @XmlAttribute(name = "title")
         protected String title;
-        @XmlElement(namespace = "www.jalview.org")
-        protected String newick;
-        @XmlAttribute(name = "fontName")
-        protected String fontName;
-        @XmlAttribute(name = "fontSize")
-        protected Integer fontSize;
-        @XmlAttribute(name = "fontStyle")
-        protected Integer fontStyle;
-        @XmlAttribute(name = "threshold")
-        protected Float threshold;
-        @XmlAttribute(name = "showBootstrap")
-        protected Boolean showBootstrap;
-        @XmlAttribute(name = "showDistances")
-        protected Boolean showDistances;
-        @XmlAttribute(name = "markUnlinked")
-        protected Boolean markUnlinked;
-        @XmlAttribute(name = "fitToWindow")
-        protected Boolean fitToWindow;
-        @XmlAttribute(name = "currentTree")
-        protected Boolean currentTree;
-        @XmlAttribute(name = "id")
-        @XmlJavaTypeAdapter(CollapsedStringAdapter.class)
-        @XmlID
-        @XmlSchemaType(name = "ID")
-        protected String id;
+        @XmlAttribute(name = "scoreModelName")
+        protected String scoreModelName;
+        @XmlAttribute(name = "xDim")
+        protected Integer xDim;
+        @XmlAttribute(name = "yDim")
+        protected Integer yDim;
+        @XmlAttribute(name = "zDim")
+        protected Integer zDim;
+        @XmlAttribute(name = "bgColour")
+        protected Integer bgColour;
+        @XmlAttribute(name = "scaleFactor")
+        protected Float scaleFactor;
+        @XmlAttribute(name = "showLabels")
+        protected Boolean showLabels;
+        @XmlAttribute(name = "linkToAllViews")
+        protected Boolean linkToAllViews;
         @XmlAttribute(name = "width")
         protected Integer width;
         @XmlAttribute(name = "height")
@@ -3038,201 +3170,1266 @@ public class JalviewModel {
         protected Integer xpos;
         @XmlAttribute(name = "ypos")
         protected Integer ypos;
+        @XmlAttribute(name = "includeGaps")
+        protected Boolean includeGaps;
+        @XmlAttribute(name = "matchGaps")
+        protected Boolean matchGaps;
+        @XmlAttribute(name = "includeGappedColumns")
+        protected Boolean includeGappedColumns;
+        @XmlAttribute(name = "denominateByShortestLength")
+        protected Boolean denominateByShortestLength;
 
         /**
-         * Gets the value of the title property.
+         * Gets the value of the sequencePoint property.
+         * 
+         * <p>
+         * This accessor method returns a reference to the live list,
+         * not a snapshot. Therefore any modification you make to the
+         * returned list will be present inside the JAXB object.
+         * This is why there is not a <CODE>set</CODE> method for the sequencePoint property.
+         * 
+         * <p>
+         * For example, to add a new item, do as follows:
+         * <pre>
+         *    getSequencePoint().add(newItem);
+         * </pre>
+         * 
+         * 
+         * <p>
+         * Objects of the following type(s) are allowed in the list
+         * {@link JalviewModel.PcaViewer.SequencePoint }
+         * 
          * 
-         * @return
-         *     possible object is
-         *     {@link String }
-         *     
          */
-        public String getTitle() {
-            return title;
+        public List<JalviewModel.PcaViewer.SequencePoint> getSequencePoint() {
+            if (sequencePoint == null) {
+                sequencePoint = new ArrayList<JalviewModel.PcaViewer.SequencePoint>();
+            }
+            return this.sequencePoint;
         }
 
         /**
-         * Sets the value of the title property.
+         * Gets the value of the axis property.
+         * 
+         * <p>
+         * This accessor method returns a reference to the live list,
+         * not a snapshot. Therefore any modification you make to the
+         * returned list will be present inside the JAXB object.
+         * This is why there is not a <CODE>set</CODE> method for the axis property.
+         * 
+         * <p>
+         * For example, to add a new item, do as follows:
+         * <pre>
+         *    getAxis().add(newItem);
+         * </pre>
+         * 
+         * 
+         * <p>
+         * Objects of the following type(s) are allowed in the list
+         * {@link JalviewModel.PcaViewer.Axis }
+         * 
          * 
-         * @param value
-         *     allowed object is
-         *     {@link String }
-         *     
          */
-        public void setTitle(String value) {
-            this.title = value;
+        public List<JalviewModel.PcaViewer.Axis> getAxis() {
+            if (axis == null) {
+                axis = new ArrayList<JalviewModel.PcaViewer.Axis>();
+            }
+            return this.axis;
         }
 
         /**
-         * Gets the value of the newick property.
+         * Gets the value of the seqPointMin property.
          * 
          * @return
          *     possible object is
-         *     {@link String }
+         *     {@link JalviewModel.PcaViewer.SeqPointMin }
          *     
          */
-        public String getNewick() {
-            return newick;
+        public JalviewModel.PcaViewer.SeqPointMin getSeqPointMin() {
+            return seqPointMin;
         }
 
         /**
-         * Sets the value of the newick property.
+         * Sets the value of the seqPointMin property.
          * 
          * @param value
          *     allowed object is
-         *     {@link String }
+         *     {@link JalviewModel.PcaViewer.SeqPointMin }
          *     
          */
-        public void setNewick(String value) {
-            this.newick = value;
+        public void setSeqPointMin(JalviewModel.PcaViewer.SeqPointMin value) {
+            this.seqPointMin = value;
         }
 
         /**
-         * Gets the value of the fontName property.
+         * Gets the value of the seqPointMax property.
          * 
          * @return
          *     possible object is
-         *     {@link String }
+         *     {@link JalviewModel.PcaViewer.SeqPointMax }
          *     
          */
-        public String getFontName() {
-            return fontName;
+        public JalviewModel.PcaViewer.SeqPointMax getSeqPointMax() {
+            return seqPointMax;
         }
 
         /**
-         * Sets the value of the fontName property.
+         * Sets the value of the seqPointMax property.
          * 
          * @param value
          *     allowed object is
-         *     {@link String }
+         *     {@link JalviewModel.PcaViewer.SeqPointMax }
          *     
          */
-        public void setFontName(String value) {
-            this.fontName = value;
+        public void setSeqPointMax(JalviewModel.PcaViewer.SeqPointMax value) {
+            this.seqPointMax = value;
         }
 
         /**
-         * Gets the value of the fontSize property.
+         * Gets the value of the pcaData property.
          * 
          * @return
          *     possible object is
-         *     {@link Integer }
+         *     {@link PcaDataType }
          *     
          */
-        public Integer getFontSize() {
-            return fontSize;
+        public PcaDataType getPcaData() {
+            return pcaData;
         }
 
         /**
-         * Sets the value of the fontSize property.
+         * Sets the value of the pcaData property.
          * 
          * @param value
          *     allowed object is
-         *     {@link Integer }
+         *     {@link PcaDataType }
          *     
          */
-        public void setFontSize(Integer value) {
-            this.fontSize = value;
+        public void setPcaData(PcaDataType value) {
+            this.pcaData = value;
         }
 
         /**
-         * Gets the value of the fontStyle property.
+         * Gets the value of the title property.
          * 
          * @return
          *     possible object is
-         *     {@link Integer }
+         *     {@link String }
          *     
          */
-        public Integer getFontStyle() {
-            return fontStyle;
+        public String getTitle() {
+            return title;
         }
 
         /**
-         * Sets the value of the fontStyle property.
+         * Sets the value of the title property.
          * 
          * @param value
          *     allowed object is
-         *     {@link Integer }
+         *     {@link String }
          *     
          */
-        public void setFontStyle(Integer value) {
-            this.fontStyle = value;
+        public void setTitle(String value) {
+            this.title = value;
         }
 
         /**
-         * Gets the value of the threshold property.
+         * Gets the value of the scoreModelName property.
          * 
          * @return
          *     possible object is
-         *     {@link Float }
+         *     {@link String }
          *     
          */
-        public Float getThreshold() {
-            return threshold;
+        public String getScoreModelName() {
+            return scoreModelName;
         }
 
         /**
-         * Sets the value of the threshold property.
+         * Sets the value of the scoreModelName property.
          * 
          * @param value
          *     allowed object is
-         *     {@link Float }
+         *     {@link String }
          *     
          */
-        public void setThreshold(Float value) {
-            this.threshold = value;
+        public void setScoreModelName(String value) {
+            this.scoreModelName = value;
         }
 
         /**
-         * Gets the value of the showBootstrap property.
+         * Gets the value of the xDim property.
          * 
          * @return
          *     possible object is
-         *     {@link Boolean }
+         *     {@link Integer }
          *     
          */
-        public Boolean isShowBootstrap() {
-            return showBootstrap;
+        public Integer getXDim() {
+            return xDim;
         }
 
         /**
-         * Sets the value of the showBootstrap property.
+         * Sets the value of the xDim property.
          * 
          * @param value
          *     allowed object is
-         *     {@link Boolean }
+         *     {@link Integer }
          *     
          */
-        public void setShowBootstrap(Boolean value) {
-            this.showBootstrap = value;
+        public void setXDim(Integer value) {
+            this.xDim = value;
         }
 
         /**
-         * Gets the value of the showDistances property.
+         * Gets the value of the yDim property.
          * 
          * @return
          *     possible object is
-         *     {@link Boolean }
+         *     {@link Integer }
          *     
          */
-        public Boolean isShowDistances() {
-            return showDistances;
+        public Integer getYDim() {
+            return yDim;
         }
 
         /**
-         * Sets the value of the showDistances property.
+         * Sets the value of the yDim property.
          * 
          * @param value
          *     allowed object is
-         *     {@link Boolean }
+         *     {@link Integer }
          *     
          */
-        public void setShowDistances(Boolean value) {
-            this.showDistances = value;
+        public void setYDim(Integer value) {
+            this.yDim = value;
         }
 
         /**
-         * Gets the value of the markUnlinked property.
+         * Gets the value of the zDim property.
+         * 
+         * @return
+         *     possible object is
+         *     {@link Integer }
+         *     
+         */
+        public Integer getZDim() {
+            return zDim;
+        }
+
+        /**
+         * Sets the value of the zDim property.
+         * 
+         * @param value
+         *     allowed object is
+         *     {@link Integer }
+         *     
+         */
+        public void setZDim(Integer value) {
+            this.zDim = value;
+        }
+
+        /**
+         * Gets the value of the bgColour property.
+         * 
+         * @return
+         *     possible object is
+         *     {@link Integer }
+         *     
+         */
+        public Integer getBgColour() {
+            return bgColour;
+        }
+
+        /**
+         * Sets the value of the bgColour property.
+         * 
+         * @param value
+         *     allowed object is
+         *     {@link Integer }
+         *     
+         */
+        public void setBgColour(Integer value) {
+            this.bgColour = value;
+        }
+
+        /**
+         * Gets the value of the scaleFactor property.
+         * 
+         * @return
+         *     possible object is
+         *     {@link Float }
+         *     
+         */
+        public Float getScaleFactor() {
+            return scaleFactor;
+        }
+
+        /**
+         * Sets the value of the scaleFactor property.
+         * 
+         * @param value
+         *     allowed object is
+         *     {@link Float }
+         *     
+         */
+        public void setScaleFactor(Float value) {
+            this.scaleFactor = value;
+        }
+
+        /**
+         * Gets the value of the showLabels property.
+         * 
+         * @return
+         *     possible object is
+         *     {@link Boolean }
+         *     
+         */
+        public Boolean isShowLabels() {
+            return showLabels;
+        }
+
+        /**
+         * Sets the value of the showLabels property.
+         * 
+         * @param value
+         *     allowed object is
+         *     {@link Boolean }
+         *     
+         */
+        public void setShowLabels(Boolean value) {
+            this.showLabels = value;
+        }
+
+        /**
+         * Gets the value of the linkToAllViews property.
+         * 
+         * @return
+         *     possible object is
+         *     {@link Boolean }
+         *     
+         */
+        public Boolean isLinkToAllViews() {
+            return linkToAllViews;
+        }
+
+        /**
+         * Sets the value of the linkToAllViews property.
+         * 
+         * @param value
+         *     allowed object is
+         *     {@link Boolean }
+         *     
+         */
+        public void setLinkToAllViews(Boolean value) {
+            this.linkToAllViews = value;
+        }
+
+        /**
+         * Gets the value of the width property.
+         * 
+         * @return
+         *     possible object is
+         *     {@link Integer }
+         *     
+         */
+        public Integer getWidth() {
+            return width;
+        }
+
+        /**
+         * Sets the value of the width property.
+         * 
+         * @param value
+         *     allowed object is
+         *     {@link Integer }
+         *     
+         */
+        public void setWidth(Integer value) {
+            this.width = value;
+        }
+
+        /**
+         * Gets the value of the height property.
+         * 
+         * @return
+         *     possible object is
+         *     {@link Integer }
+         *     
+         */
+        public Integer getHeight() {
+            return height;
+        }
+
+        /**
+         * Sets the value of the height property.
+         * 
+         * @param value
+         *     allowed object is
+         *     {@link Integer }
+         *     
+         */
+        public void setHeight(Integer value) {
+            this.height = value;
+        }
+
+        /**
+         * Gets the value of the xpos property.
+         * 
+         * @return
+         *     possible object is
+         *     {@link Integer }
+         *     
+         */
+        public Integer getXpos() {
+            return xpos;
+        }
+
+        /**
+         * Sets the value of the xpos property.
+         * 
+         * @param value
+         *     allowed object is
+         *     {@link Integer }
+         *     
+         */
+        public void setXpos(Integer value) {
+            this.xpos = value;
+        }
+
+        /**
+         * Gets the value of the ypos property.
+         * 
+         * @return
+         *     possible object is
+         *     {@link Integer }
+         *     
+         */
+        public Integer getYpos() {
+            return ypos;
+        }
+
+        /**
+         * Sets the value of the ypos property.
+         * 
+         * @param value
+         *     allowed object is
+         *     {@link Integer }
+         *     
+         */
+        public void setYpos(Integer value) {
+            this.ypos = value;
+        }
+
+        /**
+         * Gets the value of the includeGaps property.
+         * 
+         * @return
+         *     possible object is
+         *     {@link Boolean }
+         *     
+         */
+        public Boolean isIncludeGaps() {
+            return includeGaps;
+        }
+
+        /**
+         * Sets the value of the includeGaps property.
+         * 
+         * @param value
+         *     allowed object is
+         *     {@link Boolean }
+         *     
+         */
+        public void setIncludeGaps(Boolean value) {
+            this.includeGaps = value;
+        }
+
+        /**
+         * Gets the value of the matchGaps property.
+         * 
+         * @return
+         *     possible object is
+         *     {@link Boolean }
+         *     
+         */
+        public Boolean isMatchGaps() {
+            return matchGaps;
+        }
+
+        /**
+         * Sets the value of the matchGaps property.
+         * 
+         * @param value
+         *     allowed object is
+         *     {@link Boolean }
+         *     
+         */
+        public void setMatchGaps(Boolean value) {
+            this.matchGaps = value;
+        }
+
+        /**
+         * Gets the value of the includeGappedColumns property.
+         * 
+         * @return
+         *     possible object is
+         *     {@link Boolean }
+         *     
+         */
+        public Boolean isIncludeGappedColumns() {
+            return includeGappedColumns;
+        }
+
+        /**
+         * Sets the value of the includeGappedColumns property.
+         * 
+         * @param value
+         *     allowed object is
+         *     {@link Boolean }
+         *     
+         */
+        public void setIncludeGappedColumns(Boolean value) {
+            this.includeGappedColumns = value;
+        }
+
+        /**
+         * Gets the value of the denominateByShortestLength property.
+         * 
+         * @return
+         *     possible object is
+         *     {@link Boolean }
+         *     
+         */
+        public Boolean isDenominateByShortestLength() {
+            return denominateByShortestLength;
+        }
+
+        /**
+         * Sets the value of the denominateByShortestLength property.
+         * 
+         * @param value
+         *     allowed object is
+         *     {@link Boolean }
+         *     
+         */
+        public void setDenominateByShortestLength(Boolean value) {
+            this.denominateByShortestLength = value;
+        }
+
+
+        /**
+         * <p>Java class for anonymous complex type.
+         * 
+         * <p>The following schema fragment specifies the expected content contained within this class.
+         * 
+         * <pre>
+         * &lt;complexType>
+         *   &lt;complexContent>
+         *     &lt;restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
+         *       &lt;attGroup ref="{www.jalview.org}position"/>
+         *     &lt;/restriction>
+         *   &lt;/complexContent>
+         * &lt;/complexType>
+         * </pre>
+         * 
+         * 
+         */
+        @XmlAccessorType(XmlAccessType.FIELD)
+        @XmlType(name = "")
+        public static class Axis {
+
+            @XmlAttribute(name = "xPos")
+            protected Float xPos;
+            @XmlAttribute(name = "yPos")
+            protected Float yPos;
+            @XmlAttribute(name = "zPos")
+            protected Float zPos;
+
+            /**
+             * Gets the value of the xPos property.
+             * 
+             * @return
+             *     possible object is
+             *     {@link Float }
+             *     
+             */
+            public Float getXPos() {
+                return xPos;
+            }
+
+            /**
+             * Sets the value of the xPos property.
+             * 
+             * @param value
+             *     allowed object is
+             *     {@link Float }
+             *     
+             */
+            public void setXPos(Float value) {
+                this.xPos = value;
+            }
+
+            /**
+             * Gets the value of the yPos property.
+             * 
+             * @return
+             *     possible object is
+             *     {@link Float }
+             *     
+             */
+            public Float getYPos() {
+                return yPos;
+            }
+
+            /**
+             * Sets the value of the yPos property.
+             * 
+             * @param value
+             *     allowed object is
+             *     {@link Float }
+             *     
+             */
+            public void setYPos(Float value) {
+                this.yPos = value;
+            }
+
+            /**
+             * Gets the value of the zPos property.
+             * 
+             * @return
+             *     possible object is
+             *     {@link Float }
+             *     
+             */
+            public Float getZPos() {
+                return zPos;
+            }
+
+            /**
+             * Sets the value of the zPos property.
+             * 
+             * @param value
+             *     allowed object is
+             *     {@link Float }
+             *     
+             */
+            public void setZPos(Float value) {
+                this.zPos = value;
+            }
+
+        }
+
+
+        /**
+         * <p>Java class for anonymous complex type.
+         * 
+         * <p>The following schema fragment specifies the expected content contained within this class.
+         * 
+         * <pre>
+         * &lt;complexType>
+         *   &lt;complexContent>
+         *     &lt;restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
+         *       &lt;attGroup ref="{www.jalview.org}position"/>
+         *     &lt;/restriction>
+         *   &lt;/complexContent>
+         * &lt;/complexType>
+         * </pre>
+         * 
+         * 
+         */
+        @XmlAccessorType(XmlAccessType.FIELD)
+        @XmlType(name = "")
+        public static class SeqPointMax {
+
+            @XmlAttribute(name = "xPos")
+            protected Float xPos;
+            @XmlAttribute(name = "yPos")
+            protected Float yPos;
+            @XmlAttribute(name = "zPos")
+            protected Float zPos;
+
+            /**
+             * Gets the value of the xPos property.
+             * 
+             * @return
+             *     possible object is
+             *     {@link Float }
+             *     
+             */
+            public Float getXPos() {
+                return xPos;
+            }
+
+            /**
+             * Sets the value of the xPos property.
+             * 
+             * @param value
+             *     allowed object is
+             *     {@link Float }
+             *     
+             */
+            public void setXPos(Float value) {
+                this.xPos = value;
+            }
+
+            /**
+             * Gets the value of the yPos property.
+             * 
+             * @return
+             *     possible object is
+             *     {@link Float }
+             *     
+             */
+            public Float getYPos() {
+                return yPos;
+            }
+
+            /**
+             * Sets the value of the yPos property.
+             * 
+             * @param value
+             *     allowed object is
+             *     {@link Float }
+             *     
+             */
+            public void setYPos(Float value) {
+                this.yPos = value;
+            }
+
+            /**
+             * Gets the value of the zPos property.
+             * 
+             * @return
+             *     possible object is
+             *     {@link Float }
+             *     
+             */
+            public Float getZPos() {
+                return zPos;
+            }
+
+            /**
+             * Sets the value of the zPos property.
+             * 
+             * @param value
+             *     allowed object is
+             *     {@link Float }
+             *     
+             */
+            public void setZPos(Float value) {
+                this.zPos = value;
+            }
+
+        }
+
+
+        /**
+         * <p>Java class for anonymous complex type.
+         * 
+         * <p>The following schema fragment specifies the expected content contained within this class.
+         * 
+         * <pre>
+         * &lt;complexType>
+         *   &lt;complexContent>
+         *     &lt;restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
+         *       &lt;attGroup ref="{www.jalview.org}position"/>
+         *     &lt;/restriction>
+         *   &lt;/complexContent>
+         * &lt;/complexType>
+         * </pre>
+         * 
+         * 
+         */
+        @XmlAccessorType(XmlAccessType.FIELD)
+        @XmlType(name = "")
+        public static class SeqPointMin {
+
+            @XmlAttribute(name = "xPos")
+            protected Float xPos;
+            @XmlAttribute(name = "yPos")
+            protected Float yPos;
+            @XmlAttribute(name = "zPos")
+            protected Float zPos;
+
+            /**
+             * Gets the value of the xPos property.
+             * 
+             * @return
+             *     possible object is
+             *     {@link Float }
+             *     
+             */
+            public Float getXPos() {
+                return xPos;
+            }
+
+            /**
+             * Sets the value of the xPos property.
+             * 
+             * @param value
+             *     allowed object is
+             *     {@link Float }
+             *     
+             */
+            public void setXPos(Float value) {
+                this.xPos = value;
+            }
+
+            /**
+             * Gets the value of the yPos property.
+             * 
+             * @return
+             *     possible object is
+             *     {@link Float }
+             *     
+             */
+            public Float getYPos() {
+                return yPos;
+            }
+
+            /**
+             * Sets the value of the yPos property.
+             * 
+             * @param value
+             *     allowed object is
+             *     {@link Float }
+             *     
+             */
+            public void setYPos(Float value) {
+                this.yPos = value;
+            }
+
+            /**
+             * Gets the value of the zPos property.
+             * 
+             * @return
+             *     possible object is
+             *     {@link Float }
+             *     
+             */
+            public Float getZPos() {
+                return zPos;
+            }
+
+            /**
+             * Sets the value of the zPos property.
+             * 
+             * @param value
+             *     allowed object is
+             *     {@link Float }
+             *     
+             */
+            public void setZPos(Float value) {
+                this.zPos = value;
+            }
+
+        }
+
+
+        /**
+         * <p>Java class for anonymous complex type.
+         * 
+         * <p>The following schema fragment specifies the expected content contained within this class.
+         * 
+         * <pre>
+         * &lt;complexType>
+         *   &lt;complexContent>
+         *     &lt;restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
+         *       &lt;attGroup ref="{www.jalview.org}position"/>
+         *       &lt;attribute name="sequenceRef" type="{http://www.w3.org/2001/XMLSchema}string" />
+         *     &lt;/restriction>
+         *   &lt;/complexContent>
+         * &lt;/complexType>
+         * </pre>
+         * 
+         * 
+         */
+        @XmlAccessorType(XmlAccessType.FIELD)
+        @XmlType(name = "")
+        public static class SequencePoint {
+
+            @XmlAttribute(name = "sequenceRef")
+            protected String sequenceRef;
+            @XmlAttribute(name = "xPos")
+            protected Float xPos;
+            @XmlAttribute(name = "yPos")
+            protected Float yPos;
+            @XmlAttribute(name = "zPos")
+            protected Float zPos;
+
+            /**
+             * Gets the value of the sequenceRef property.
+             * 
+             * @return
+             *     possible object is
+             *     {@link String }
+             *     
+             */
+            public String getSequenceRef() {
+                return sequenceRef;
+            }
+
+            /**
+             * Sets the value of the sequenceRef property.
+             * 
+             * @param value
+             *     allowed object is
+             *     {@link String }
+             *     
+             */
+            public void setSequenceRef(String value) {
+                this.sequenceRef = value;
+            }
+
+            /**
+             * Gets the value of the xPos property.
+             * 
+             * @return
+             *     possible object is
+             *     {@link Float }
+             *     
+             */
+            public Float getXPos() {
+                return xPos;
+            }
+
+            /**
+             * Sets the value of the xPos property.
+             * 
+             * @param value
+             *     allowed object is
+             *     {@link Float }
+             *     
+             */
+            public void setXPos(Float value) {
+                this.xPos = value;
+            }
+
+            /**
+             * Gets the value of the yPos property.
+             * 
+             * @return
+             *     possible object is
+             *     {@link Float }
+             *     
+             */
+            public Float getYPos() {
+                return yPos;
+            }
+
+            /**
+             * Sets the value of the yPos property.
+             * 
+             * @param value
+             *     allowed object is
+             *     {@link Float }
+             *     
+             */
+            public void setYPos(Float value) {
+                this.yPos = value;
+            }
+
+            /**
+             * Gets the value of the zPos property.
+             * 
+             * @return
+             *     possible object is
+             *     {@link Float }
+             *     
+             */
+            public Float getZPos() {
+                return zPos;
+            }
+
+            /**
+             * Sets the value of the zPos property.
+             * 
+             * @param value
+             *     allowed object is
+             *     {@link Float }
+             *     
+             */
+            public void setZPos(Float value) {
+                this.zPos = value;
+            }
+
+        }
+
+    }
+
+
+    /**
+     * <p>Java class for anonymous complex type.
+     * 
+     * <p>The following schema fragment specifies the expected content contained within this class.
+     * 
+     * <pre>
+     * &lt;complexType>
+     *   &lt;complexContent>
+     *     &lt;restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
+     *       &lt;sequence minOccurs="0">
+     *         &lt;element name="title" type="{http://www.w3.org/2001/XMLSchema}string"/>
+     *         &lt;element name="newick" type="{http://www.w3.org/2001/XMLSchema}string"/>
+     *       &lt;/sequence>
+     *       &lt;attGroup ref="{www.jalview.org}swingwindow"/>
+     *       &lt;attribute name="fontName" type="{http://www.w3.org/2001/XMLSchema}string" />
+     *       &lt;attribute name="fontSize" type="{http://www.w3.org/2001/XMLSchema}int" />
+     *       &lt;attribute name="fontStyle" type="{http://www.w3.org/2001/XMLSchema}int" />
+     *       &lt;attribute name="threshold" type="{http://www.w3.org/2001/XMLSchema}float" />
+     *       &lt;attribute name="showBootstrap" type="{http://www.w3.org/2001/XMLSchema}boolean" />
+     *       &lt;attribute name="showDistances" type="{http://www.w3.org/2001/XMLSchema}boolean" />
+     *       &lt;attribute name="markUnlinked" type="{http://www.w3.org/2001/XMLSchema}boolean" />
+     *       &lt;attribute name="fitToWindow" type="{http://www.w3.org/2001/XMLSchema}boolean" />
+     *       &lt;attribute name="currentTree" type="{http://www.w3.org/2001/XMLSchema}boolean" />
+     *       &lt;attribute name="id" type="{http://www.w3.org/2001/XMLSchema}ID" />
+     *       &lt;attribute name="linkToAllViews" type="{http://www.w3.org/2001/XMLSchema}boolean" default="false" />
+     *     &lt;/restriction>
+     *   &lt;/complexContent>
+     * &lt;/complexType>
+     * </pre>
+     * 
+     * 
+     */
+    @XmlAccessorType(XmlAccessType.FIELD)
+    @XmlType(name = "", propOrder = {
+        "title",
+        "newick"
+    })
+    public static class Tree {
+
+        @XmlElement(namespace = "www.jalview.org")
+        protected String title;
+        @XmlElement(namespace = "www.jalview.org")
+        protected String newick;
+        @XmlAttribute(name = "fontName")
+        protected String fontName;
+        @XmlAttribute(name = "fontSize")
+        protected Integer fontSize;
+        @XmlAttribute(name = "fontStyle")
+        protected Integer fontStyle;
+        @XmlAttribute(name = "threshold")
+        protected Float threshold;
+        @XmlAttribute(name = "showBootstrap")
+        protected Boolean showBootstrap;
+        @XmlAttribute(name = "showDistances")
+        protected Boolean showDistances;
+        @XmlAttribute(name = "markUnlinked")
+        protected Boolean markUnlinked;
+        @XmlAttribute(name = "fitToWindow")
+        protected Boolean fitToWindow;
+        @XmlAttribute(name = "currentTree")
+        protected Boolean currentTree;
+        @XmlAttribute(name = "id")
+        @XmlJavaTypeAdapter(CollapsedStringAdapter.class)
+        @XmlID
+        @XmlSchemaType(name = "ID")
+        protected String id;
+        @XmlAttribute(name = "linkToAllViews")
+        protected Boolean linkToAllViews;
+        @XmlAttribute(name = "width")
+        protected Integer width;
+        @XmlAttribute(name = "height")
+        protected Integer height;
+        @XmlAttribute(name = "xpos")
+        protected Integer xpos;
+        @XmlAttribute(name = "ypos")
+        protected Integer ypos;
+
+        /**
+         * Gets the value of the title property.
+         * 
+         * @return
+         *     possible object is
+         *     {@link String }
+         *     
+         */
+        public String getTitle() {
+            return title;
+        }
+
+        /**
+         * Sets the value of the title property.
+         * 
+         * @param value
+         *     allowed object is
+         *     {@link String }
+         *     
+         */
+        public void setTitle(String value) {
+            this.title = value;
+        }
+
+        /**
+         * Gets the value of the newick property.
+         * 
+         * @return
+         *     possible object is
+         *     {@link String }
+         *     
+         */
+        public String getNewick() {
+            return newick;
+        }
+
+        /**
+         * Sets the value of the newick property.
+         * 
+         * @param value
+         *     allowed object is
+         *     {@link String }
+         *     
+         */
+        public void setNewick(String value) {
+            this.newick = value;
+        }
+
+        /**
+         * Gets the value of the fontName property.
+         * 
+         * @return
+         *     possible object is
+         *     {@link String }
+         *     
+         */
+        public String getFontName() {
+            return fontName;
+        }
+
+        /**
+         * Sets the value of the fontName property.
+         * 
+         * @param value
+         *     allowed object is
+         *     {@link String }
+         *     
+         */
+        public void setFontName(String value) {
+            this.fontName = value;
+        }
+
+        /**
+         * Gets the value of the fontSize property.
+         * 
+         * @return
+         *     possible object is
+         *     {@link Integer }
+         *     
+         */
+        public Integer getFontSize() {
+            return fontSize;
+        }
+
+        /**
+         * Sets the value of the fontSize property.
+         * 
+         * @param value
+         *     allowed object is
+         *     {@link Integer }
+         *     
+         */
+        public void setFontSize(Integer value) {
+            this.fontSize = value;
+        }
+
+        /**
+         * Gets the value of the fontStyle property.
+         * 
+         * @return
+         *     possible object is
+         *     {@link Integer }
+         *     
+         */
+        public Integer getFontStyle() {
+            return fontStyle;
+        }
+
+        /**
+         * Sets the value of the fontStyle property.
+         * 
+         * @param value
+         *     allowed object is
+         *     {@link Integer }
+         *     
+         */
+        public void setFontStyle(Integer value) {
+            this.fontStyle = value;
+        }
+
+        /**
+         * Gets the value of the threshold property.
+         * 
+         * @return
+         *     possible object is
+         *     {@link Float }
+         *     
+         */
+        public Float getThreshold() {
+            return threshold;
+        }
+
+        /**
+         * Sets the value of the threshold property.
+         * 
+         * @param value
+         *     allowed object is
+         *     {@link Float }
+         *     
+         */
+        public void setThreshold(Float value) {
+            this.threshold = value;
+        }
+
+        /**
+         * Gets the value of the showBootstrap property.
+         * 
+         * @return
+         *     possible object is
+         *     {@link Boolean }
+         *     
+         */
+        public Boolean isShowBootstrap() {
+            return showBootstrap;
+        }
+
+        /**
+         * Sets the value of the showBootstrap property.
+         * 
+         * @param value
+         *     allowed object is
+         *     {@link Boolean }
+         *     
+         */
+        public void setShowBootstrap(Boolean value) {
+            this.showBootstrap = value;
+        }
+
+        /**
+         * Gets the value of the showDistances property.
+         * 
+         * @return
+         *     possible object is
+         *     {@link Boolean }
+         *     
+         */
+        public Boolean isShowDistances() {
+            return showDistances;
+        }
+
+        /**
+         * Sets the value of the showDistances property.
+         * 
+         * @param value
+         *     allowed object is
+         *     {@link Boolean }
+         *     
+         */
+        public void setShowDistances(Boolean value) {
+            this.showDistances = value;
+        }
+
+        /**
+         * Gets the value of the markUnlinked property.
          * 
          * @return
          *     possible object is
@@ -3328,6 +4525,34 @@ public class JalviewModel {
         }
 
         /**
+         * Gets the value of the linkToAllViews property.
+         * 
+         * @return
+         *     possible object is
+         *     {@link Boolean }
+         *     
+         */
+        public boolean isLinkToAllViews() {
+            if (linkToAllViews == null) {
+                return false;
+            } else {
+                return linkToAllViews;
+            }
+        }
+
+        /**
+         * Sets the value of the linkToAllViews property.
+         * 
+         * @param value
+         *     allowed object is
+         *     {@link Boolean }
+         *     
+         */
+        public void setLinkToAllViews(Boolean value) {
+            this.linkToAllViews = value;
+        }
+
+        /**
          * Gets the value of the width property.
          * 
          * @return
index 0de2ac0..701647c 100644 (file)
@@ -2,7 +2,7 @@
 // This file was generated by the JavaTM Architecture for XML Binding(JAXB) Reference Implementation, v2.2.8-b130911.1802 
 // See <a href="http://java.sun.com/xml/jaxb">http://java.sun.com/xml/jaxb</a> 
 // Any modifications to this file will be lost upon recompilation of the source schema. 
-// Generated on: 2018.09.28 at 12:18:54 PM BST 
+// Generated on: 2018.12.20 at 11:47:26 AM GMT 
 //
 
 
index 345556f..3d7b5eb 100644 (file)
@@ -2,7 +2,7 @@
 // This file was generated by the JavaTM Architecture for XML Binding(JAXB) Reference Implementation, v2.2.8-b130911.1802 
 // See <a href="http://java.sun.com/xml/jaxb">http://java.sun.com/xml/jaxb</a> 
 // Any modifications to this file will be lost upon recompilation of the source schema. 
-// Generated on: 2018.09.28 at 12:18:54 PM BST 
+// Generated on: 2018.12.20 at 11:47:26 AM GMT 
 //
 
 
index cd82a2a..3cbebc0 100644 (file)
@@ -2,7 +2,7 @@
 // This file was generated by the JavaTM Architecture for XML Binding(JAXB) Reference Implementation, v2.2.8-b130911.1802 
 // See <a href="http://java.sun.com/xml/jaxb">http://java.sun.com/xml/jaxb</a> 
 // Any modifications to this file will be lost upon recompilation of the source schema. 
-// Generated on: 2018.09.28 at 12:18:54 PM BST 
+// Generated on: 2018.12.20 at 11:47:26 AM GMT 
 //
 
 
index 8fd65f0..15fc45d 100644 (file)
@@ -2,7 +2,7 @@
 // This file was generated by the JavaTM Architecture for XML Binding(JAXB) Reference Implementation, v2.2.8-b130911.1802 
 // See <a href="http://java.sun.com/xml/jaxb">http://java.sun.com/xml/jaxb</a> 
 // Any modifications to this file will be lost upon recompilation of the source schema. 
-// Generated on: 2018.09.28 at 12:18:54 PM BST 
+// Generated on: 2018.12.20 at 11:47:26 AM GMT 
 //
 
 
index 0903928..6858f07 100644 (file)
@@ -2,7 +2,7 @@
 // This file was generated by the JavaTM Architecture for XML Binding(JAXB) Reference Implementation, v2.2.8-b130911.1802 
 // See <a href="http://java.sun.com/xml/jaxb">http://java.sun.com/xml/jaxb</a> 
 // Any modifications to this file will be lost upon recompilation of the source schema. 
-// Generated on: 2018.09.28 at 12:18:54 PM BST 
+// Generated on: 2018.12.20 at 11:47:26 AM GMT 
 //
 
 
@@ -131,6 +131,14 @@ public class ObjectFactory {
     }
 
     /**
+     * Create an instance of {@link JalviewModel.PcaViewer }
+     * 
+     */
+    public JalviewModel.PcaViewer createJalviewModelPcaViewer() {
+        return new JalviewModel.PcaViewer();
+    }
+
+    /**
      * Create an instance of {@link JalviewModel.Viewport }
      * 
      */
@@ -163,6 +171,14 @@ public class ObjectFactory {
     }
 
     /**
+     * Create an instance of {@link DoubleMatrix }
+     * 
+     */
+    public DoubleMatrix createDoubleMatrix() {
+        return new DoubleMatrix();
+    }
+
+    /**
      * Create an instance of {@link AnnotationColourScheme }
      * 
      */
@@ -171,6 +187,22 @@ public class ObjectFactory {
     }
 
     /**
+     * Create an instance of {@link PcaDataType }
+     * 
+     */
+    public PcaDataType createPcaDataType() {
+        return new PcaDataType();
+    }
+
+    /**
+     * Create an instance of {@link DoubleVector }
+     * 
+     */
+    public DoubleVector createDoubleVector() {
+        return new DoubleVector();
+    }
+
+    /**
      * Create an instance of {@link AlcodonFrame.Alcodon }
      * 
      */
@@ -363,6 +395,38 @@ public class ObjectFactory {
     }
 
     /**
+     * Create an instance of {@link JalviewModel.PcaViewer.SequencePoint }
+     * 
+     */
+    public JalviewModel.PcaViewer.SequencePoint createJalviewModelPcaViewerSequencePoint() {
+        return new JalviewModel.PcaViewer.SequencePoint();
+    }
+
+    /**
+     * Create an instance of {@link JalviewModel.PcaViewer.Axis }
+     * 
+     */
+    public JalviewModel.PcaViewer.Axis createJalviewModelPcaViewerAxis() {
+        return new JalviewModel.PcaViewer.Axis();
+    }
+
+    /**
+     * Create an instance of {@link JalviewModel.PcaViewer.SeqPointMin }
+     * 
+     */
+    public JalviewModel.PcaViewer.SeqPointMin createJalviewModelPcaViewerSeqPointMin() {
+        return new JalviewModel.PcaViewer.SeqPointMin();
+    }
+
+    /**
+     * Create an instance of {@link JalviewModel.PcaViewer.SeqPointMax }
+     * 
+     */
+    public JalviewModel.PcaViewer.SeqPointMax createJalviewModelPcaViewerSeqPointMax() {
+        return new JalviewModel.PcaViewer.SeqPointMax();
+    }
+
+    /**
      * Create an instance of {@link JalviewModel.Viewport.HiddenColumns }
      * 
      */
diff --git a/src/jalview/xml/binding/jalview/PcaDataType.java b/src/jalview/xml/binding/jalview/PcaDataType.java
new file mode 100644 (file)
index 0000000..e8c7cf2
--- /dev/null
@@ -0,0 +1,129 @@
+//
+// This file was generated by the JavaTM Architecture for XML Binding(JAXB) Reference Implementation, v2.2.8-b130911.1802 
+// See <a href="http://java.sun.com/xml/jaxb">http://java.sun.com/xml/jaxb</a> 
+// Any modifications to this file will be lost upon recompilation of the source schema. 
+// Generated on: 2018.12.20 at 11:47:26 AM GMT 
+//
+
+
+package jalview.xml.binding.jalview;
+
+import javax.xml.bind.annotation.XmlAccessType;
+import javax.xml.bind.annotation.XmlAccessorType;
+import javax.xml.bind.annotation.XmlElement;
+import javax.xml.bind.annotation.XmlType;
+
+
+/**
+ * 
+ *                             The results of a PCA calculation
+ *                     
+ * 
+ * <p>Java class for PcaDataType complex type.
+ * 
+ * <p>The following schema fragment specifies the expected content contained within this class.
+ * 
+ * <pre>
+ * &lt;complexType name="PcaDataType">
+ *   &lt;complexContent>
+ *     &lt;restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
+ *       &lt;sequence>
+ *         &lt;element name="pairwiseMatrix" type="{www.jalview.org}DoubleMatrix"/>
+ *         &lt;element name="tridiagonalMatrix" type="{www.jalview.org}DoubleMatrix"/>
+ *         &lt;element name="eigenMatrix" type="{www.jalview.org}DoubleMatrix"/>
+ *       &lt;/sequence>
+ *     &lt;/restriction>
+ *   &lt;/complexContent>
+ * &lt;/complexType>
+ * </pre>
+ * 
+ * 
+ */
+@XmlAccessorType(XmlAccessType.FIELD)
+@XmlType(name = "PcaDataType", namespace = "www.jalview.org", propOrder = {
+    "pairwiseMatrix",
+    "tridiagonalMatrix",
+    "eigenMatrix"
+})
+public class PcaDataType {
+
+    @XmlElement(required = true)
+    protected DoubleMatrix pairwiseMatrix;
+    @XmlElement(required = true)
+    protected DoubleMatrix tridiagonalMatrix;
+    @XmlElement(required = true)
+    protected DoubleMatrix eigenMatrix;
+
+    /**
+     * Gets the value of the pairwiseMatrix property.
+     * 
+     * @return
+     *     possible object is
+     *     {@link DoubleMatrix }
+     *     
+     */
+    public DoubleMatrix getPairwiseMatrix() {
+        return pairwiseMatrix;
+    }
+
+    /**
+     * Sets the value of the pairwiseMatrix property.
+     * 
+     * @param value
+     *     allowed object is
+     *     {@link DoubleMatrix }
+     *     
+     */
+    public void setPairwiseMatrix(DoubleMatrix value) {
+        this.pairwiseMatrix = value;
+    }
+
+    /**
+     * Gets the value of the tridiagonalMatrix property.
+     * 
+     * @return
+     *     possible object is
+     *     {@link DoubleMatrix }
+     *     
+     */
+    public DoubleMatrix getTridiagonalMatrix() {
+        return tridiagonalMatrix;
+    }
+
+    /**
+     * Sets the value of the tridiagonalMatrix property.
+     * 
+     * @param value
+     *     allowed object is
+     *     {@link DoubleMatrix }
+     *     
+     */
+    public void setTridiagonalMatrix(DoubleMatrix value) {
+        this.tridiagonalMatrix = value;
+    }
+
+    /**
+     * Gets the value of the eigenMatrix property.
+     * 
+     * @return
+     *     possible object is
+     *     {@link DoubleMatrix }
+     *     
+     */
+    public DoubleMatrix getEigenMatrix() {
+        return eigenMatrix;
+    }
+
+    /**
+     * Sets the value of the eigenMatrix property.
+     * 
+     * @param value
+     *     allowed object is
+     *     {@link DoubleMatrix }
+     *     
+     */
+    public void setEigenMatrix(DoubleMatrix value) {
+        this.eigenMatrix = value;
+    }
+
+}
index 4accccd..843ea6c 100644 (file)
@@ -2,7 +2,7 @@
 // This file was generated by the JavaTM Architecture for XML Binding(JAXB) Reference Implementation, v2.2.8-b130911.1802 
 // See <a href="http://java.sun.com/xml/jaxb">http://java.sun.com/xml/jaxb</a> 
 // Any modifications to this file will be lost upon recompilation of the source schema. 
-// Generated on: 2018.09.28 at 12:18:54 PM BST 
+// Generated on: 2018.12.20 at 11:47:26 AM GMT 
 //
 
 
index 937142a..abb40c9 100644 (file)
@@ -2,7 +2,7 @@
 // This file was generated by the JavaTM Architecture for XML Binding(JAXB) Reference Implementation, v2.2.8-b130911.1802 
 // See <a href="http://java.sun.com/xml/jaxb">http://java.sun.com/xml/jaxb</a> 
 // Any modifications to this file will be lost upon recompilation of the source schema. 
-// Generated on: 2018.09.28 at 12:18:54 PM BST 
+// Generated on: 2018.12.20 at 11:47:26 AM GMT 
 //
 
 
index 7bd7c1e..0fc7771 100644 (file)
@@ -2,7 +2,7 @@
 // This file was generated by the JavaTM Architecture for XML Binding(JAXB) Reference Implementation, v2.2.8-b130911.1802 
 // See <a href="http://java.sun.com/xml/jaxb">http://java.sun.com/xml/jaxb</a> 
 // Any modifications to this file will be lost upon recompilation of the source schema. 
-// Generated on: 2018.09.28 at 12:18:54 PM BST 
+// Generated on: 2018.12.20 at 11:47:26 AM GMT 
 //
 
 
index 004119f..07b8c24 100644 (file)
@@ -2,7 +2,7 @@
 // This file was generated by the JavaTM Architecture for XML Binding(JAXB) Reference Implementation, v2.2.8-b130911.1802 
 // See <a href="http://java.sun.com/xml/jaxb">http://java.sun.com/xml/jaxb</a> 
 // Any modifications to this file will be lost upon recompilation of the source schema. 
-// Generated on: 2018.09.28 at 12:18:54 PM BST 
+// Generated on: 2018.12.20 at 11:47:26 AM GMT 
 //
 
 
index 7ec43c7..e8b7e28 100644 (file)
@@ -2,7 +2,7 @@
 // This file was generated by the JavaTM Architecture for XML Binding(JAXB) Reference Implementation, v2.2.8-b130911.1802 
 // See <a href="http://java.sun.com/xml/jaxb">http://java.sun.com/xml/jaxb</a> 
 // Any modifications to this file will be lost upon recompilation of the source schema. 
-// Generated on: 2018.09.28 at 12:18:54 PM BST 
+// Generated on: 2018.12.20 at 11:47:26 AM GMT 
 //
 
 
index 70799ea..1f68de9 100644 (file)
@@ -2,7 +2,7 @@
 // This file was generated by the JavaTM Architecture for XML Binding(JAXB) Reference Implementation, v2.2.8-b130911.1802 
 // See <a href="http://java.sun.com/xml/jaxb">http://java.sun.com/xml/jaxb</a> 
 // Any modifications to this file will be lost upon recompilation of the source schema. 
-// Generated on: 2018.09.28 at 12:18:54 PM BST 
+// Generated on: 2018.12.20 at 11:47:26 AM GMT 
 //
 
 
index fea0324..c884556 100644 (file)
@@ -2,7 +2,7 @@
 // This file was generated by the JavaTM Architecture for XML Binding(JAXB) Reference Implementation, v2.2.8-b130911.1802 
 // See <a href="http://java.sun.com/xml/jaxb">http://java.sun.com/xml/jaxb</a> 
 // Any modifications to this file will be lost upon recompilation of the source schema. 
-// Generated on: 2018.09.28 at 12:18:54 PM BST 
+// Generated on: 2018.12.20 at 11:47:26 AM GMT 
 //
 
 
index 4235c64..bd6dc77 100644 (file)
@@ -2,7 +2,7 @@
 // This file was generated by the JavaTM Architecture for XML Binding(JAXB) Reference Implementation, v2.2.8-b130911.1802 
 // See <a href="http://java.sun.com/xml/jaxb">http://java.sun.com/xml/jaxb</a> 
 // Any modifications to this file will be lost upon recompilation of the source schema. 
-// Generated on: 2018.09.28 at 12:18:54 PM BST 
+// Generated on: 2018.12.20 at 11:47:26 AM GMT 
 //
 
 @javax.xml.bind.annotation.XmlSchema(namespace = "www.vamsas.ac.uk/jalview/version2", elementFormDefault = javax.xml.bind.annotation.XmlNsForm.QUALIFIED)
index ffcd1a8..5e44d3d 100644 (file)
@@ -45,16 +45,16 @@ public class ScoreModelsTest
     assertTrue(sm instanceof SimilarityScoreModel);
     assertTrue(sm instanceof PairwiseScoreModelI);
     assertFalse(sm instanceof DistanceScoreModel);
-    assertEquals(sm.getName(), "PID");
-    assertEquals(((PairwiseScoreModelI) sm).getPairwiseScore('R', 'C'), 0f);
-    assertEquals(((PairwiseScoreModelI) sm).getPairwiseScore('R', 'r'), 1f);
+    assertEquals(sm.getName(), "DNA");
+    assertEquals(((PairwiseScoreModelI) sm).getPairwiseScore('c', 'x'), 1f);
 
     sm = models.next();
     assertTrue(sm instanceof SimilarityScoreModel);
     assertTrue(sm instanceof PairwiseScoreModelI);
     assertFalse(sm instanceof DistanceScoreModel);
-    assertEquals(sm.getName(), "DNA");
-    assertEquals(((PairwiseScoreModelI) sm).getPairwiseScore('c', 'x'), 1f);
+    assertEquals(sm.getName(), "PID");
+    assertEquals(((PairwiseScoreModelI) sm).getPairwiseScore('R', 'C'), 0f);
+    assertEquals(((PairwiseScoreModelI) sm).getPairwiseScore('R', 'r'), 1f);
 
     sm = models.next();
     assertFalse(sm instanceof SimilarityScoreModel);
index 155f00e..2160657 100644 (file)
@@ -21,8 +21,8 @@
 package jalview.commands;
 
 import static org.testng.AssertJUnit.assertEquals;
-import static org.testng.AssertJUnit.assertNull;
 import static org.testng.AssertJUnit.assertSame;
+import static org.testng.AssertJUnit.assertTrue;
 
 import jalview.commands.EditCommand.Action;
 import jalview.commands.EditCommand.Edit;
@@ -34,6 +34,8 @@ import jalview.datamodel.SequenceI;
 import jalview.datamodel.features.SequenceFeatures;
 import jalview.gui.JvOptionPane;
 
+import java.util.Collections;
+import java.util.Comparator;
 import java.util.List;
 import java.util.Map;
 
@@ -50,6 +52,22 @@ import org.testng.annotations.Test;
  */
 public class EditCommandTest
 {
+  private static Comparator<SequenceFeature> BY_DESCRIPTION = new Comparator<SequenceFeature>()
+  {
+
+    @Override
+    public int compare(SequenceFeature o1, SequenceFeature o2)
+    {
+      return o1.getDescription().compareTo(o2.getDescription());
+    }
+  };
+
+  private EditCommand testee;
+
+  private SequenceI[] seqs;
+
+  private Alignment al;
+
   /*
    * compute n(n+1)/2 e.g. 
    * func(5) = 5 + 4 + 3 + 2 + 1 = 15
@@ -66,12 +84,6 @@ public class EditCommandTest
     JvOptionPane.setMockResponse(JvOptionPane.CANCEL_OPTION);
   }
 
-  private EditCommand testee;
-
-  private SequenceI[] seqs;
-
-  private Alignment al;
-
   @BeforeMethod(alwaysRun = true)
   public void setUp()
   {
@@ -141,18 +153,23 @@ public class EditCommandTest
   }
 
   /**
-   * Test a Paste action, where this adds sequences to an alignment.
+   * Test a Paste action, followed by Undo and Redo
    */
   @Test(groups = { "Functional" }, enabled = false)
-  // TODO fix so it works
-  public void testPaste_addToAlignment()
+  public void testPaste_undo_redo()
   {
+    // TODO code this test properly, bearing in mind that:
+    // Paste action requires something on the clipboard (Cut/Copy)
+    // - EditCommand.paste doesn't add sequences to the alignment
+    // ... that is done in AlignFrame.paste()
+    // ... unless as a Redo
+    // ...
+
     SequenceI[] newSeqs = new SequenceI[2];
     newSeqs[0] = new Sequence("newseq0", "ACEFKL");
     newSeqs[1] = new Sequence("newseq1", "JWMPDH");
 
-    Edit ec = testee.new Edit(Action.PASTE, newSeqs, 0, al.getWidth(), al);
-    EditCommand.paste(ec, new AlignmentI[] { al });
+    new EditCommand("Paste", Action.PASTE, newSeqs, 0, al.getWidth(), al);
     assertEquals(6, al.getSequences().size());
     assertEquals("1234567890", seqs[3].getSequenceAsString());
     assertEquals("ACEFKL", seqs[4].getSequenceAsString());
@@ -262,12 +279,123 @@ public class EditCommandTest
   {
     // seem to need a dataset sequence on the edited sequence here
     seqs[1].createDatasetSequence();
-    new EditCommand("", Action.REPLACE, "ZXY", new SequenceI[] { seqs[1] },
+    assertEquals("fghjklmnopq", seqs[1].getSequenceAsString());
+    // NB command.number holds end position for a Replace command
+    new EditCommand("", Action.REPLACE, "Z-xY", new SequenceI[] { seqs[1] },
             4, 8, al);
     assertEquals("abcdefghjk", seqs[0].getSequenceAsString());
+    assertEquals("fghjZ-xYopq", seqs[1].getSequenceAsString());
+    assertEquals("fghjZxYopq",
+            seqs[1].getDatasetSequence().getSequenceAsString());
     assertEquals("qrstuvwxyz", seqs[2].getSequenceAsString());
     assertEquals("1234567890", seqs[3].getSequenceAsString());
-    seqs[1] = new Sequence("seq1", "fghjZXYnopq");
+  }
+
+  /**
+   * Test the replace command (used to manually edit a sequence)
+   */
+  @Test(groups = { "Functional" })
+  public void testReplace_withGaps()
+  {
+    SequenceI seq = new Sequence("seq", "ABC--DEF");
+    seq.createDatasetSequence();
+    assertEquals("ABCDEF", seq.getDatasetSequence().getSequenceAsString());
+    assertEquals(1, seq.getStart());
+    assertEquals(6, seq.getEnd());
+
+    /*
+     * replace C- with XYZ
+     * NB arg4 = start column of selection for edit (base 0)
+     * arg5 = column after end of selection for edit
+     */
+    EditCommand edit = new EditCommand("", Action.REPLACE, "xyZ",
+            new SequenceI[]
+            { seq }, 2,
+            4, al);
+    assertEquals("ABxyZ-DEF", seq.getSequenceAsString());
+    assertEquals(1, seq.getStart());
+    assertEquals(8, seq.getEnd());
+    assertEquals("ABxyZDEF",
+            seq.getDatasetSequence().getSequenceAsString());
+    assertEquals(8, seq.getDatasetSequence().getEnd());
+
+    /*
+     * undo the edit
+     */
+    AlignmentI[] views = new AlignmentI[]
+    { new Alignment(new SequenceI[] { seq }) };
+    edit.undoCommand(views);
+
+    assertEquals("ABC--DEF", seq.getSequenceAsString());
+    assertEquals("ABCDEF", seq.getDatasetSequence().getSequenceAsString());
+    assertEquals(1, seq.getStart());
+    assertEquals(6, seq.getEnd());
+    assertEquals(6, seq.getDatasetSequence().getEnd());
+
+    /*
+     * redo the edit
+     */
+    edit.doCommand(views);
+
+    assertEquals("ABxyZ-DEF", seq.getSequenceAsString());
+    assertEquals(1, seq.getStart());
+    assertEquals(8, seq.getEnd());
+    assertEquals("ABxyZDEF",
+            seq.getDatasetSequence().getSequenceAsString());
+    assertEquals(8, seq.getDatasetSequence().getEnd());
+
+  }
+
+  /**
+   * Test replace command when it doesn't cause a sequence edit (see comment in
+   */
+  @Test(groups = { "Functional" })
+  public void testReplaceFirstResiduesWithGaps()
+  {
+    // test replace when gaps are inserted at start. Start/end should change
+    // w.r.t. original edited sequence.
+    SequenceI dsseq = seqs[1].getDatasetSequence();
+    EditCommand edit = new EditCommand("", Action.REPLACE, "----",
+            new SequenceI[]
+            { seqs[1] }, 0, 4, al);
+
+    // trimmed start
+    assertEquals("----klmnopq", seqs[1].getSequenceAsString());
+    // and ds is preserved
+    assertTrue(dsseq == seqs[1].getDatasetSequence());
+    // and it is unchanged
+    assertEquals("fghjklmnopq", dsseq.getSequenceAsString());
+    // and that alignment sequence start has been adjusted
+    assertEquals(5, seqs[1].getStart());
+    assertEquals(11, seqs[1].getEnd());
+
+    AlignmentI[] views = new AlignmentI[] { new Alignment(seqs) };
+    // and undo
+    edit.undoCommand(views);
+
+    // dataset sequence unchanged
+    assertTrue(dsseq == seqs[1].getDatasetSequence());
+    // restore sequence
+    assertEquals("fghjklmnopq", seqs[1].getSequenceAsString());
+    // and start/end numbering also restored
+    assertEquals(1, seqs[1].getStart());
+    assertEquals(11, seqs[1].getEnd());
+
+    // now redo
+    edit.undoCommand(views);
+
+    // and repeat asserts for the original edit
+
+    // trimmed start
+    assertEquals("----klmnopq", seqs[1].getSequenceAsString());
+    // and ds is preserved
+    assertTrue(dsseq == seqs[1].getDatasetSequence());
+    // and it is unchanged
+    assertEquals("fghjklmnopq", dsseq.getSequenceAsString());
+    // and that alignment sequence start has been adjusted
+    assertEquals(5, seqs[1].getStart());
+    assertEquals(11, seqs[1].getEnd());
+
   }
 
   /**
@@ -663,7 +791,7 @@ public class EditCommandTest
      * create sequence features before, after and overlapping
      * a cut of columns/residues 4-7
      */
-    SequenceI seq0 = seqs[0];
+    SequenceI seq0 = seqs[0]; // abcdefghjk/1-10
     seq0.addSequenceFeature(new SequenceFeature("before", "", 1, 3, 0f,
             null));
     seq0.addSequenceFeature(new SequenceFeature("overlap left", "", 2, 6,
@@ -675,29 +803,52 @@ public class EditCommandTest
     seq0.addSequenceFeature(new SequenceFeature("after", "", 8, 10, 0f,
             null));
 
+    /*
+     * add some contact features
+     */
+    SequenceFeature internalContact = new SequenceFeature("disulphide bond", "", 5,
+            6, 0f, null);
+    seq0.addSequenceFeature(internalContact); // should get deleted
+    SequenceFeature overlapLeftContact = new SequenceFeature(
+            "disulphide bond", "", 2, 6, 0f, null);
+    seq0.addSequenceFeature(overlapLeftContact); // should get deleted
+    SequenceFeature overlapRightContact = new SequenceFeature(
+            "disulphide bond", "", 5, 8, 0f, null);
+    seq0.addSequenceFeature(overlapRightContact); // should get deleted
+    SequenceFeature spanningContact = new SequenceFeature(
+            "disulphide bond", "", 2, 9, 0f, null);
+    seq0.addSequenceFeature(spanningContact); // should get shortened 3'
+
+    /*
+     * cut columns 3-6 (base 0), residues d-g 4-7
+     */
     Edit ec = testee.new Edit(Action.CUT, seqs, 3, 4, al); // cols 3-6 base 0
     EditCommand.cut(ec, new AlignmentI[] { al });
 
     List<SequenceFeature> sfs = seq0.getSequenceFeatures();
     SequenceFeatures.sortFeatures(sfs, true);
 
-    assertEquals(4, sfs.size()); // feature internal to cut has been deleted
+    assertEquals(5, sfs.size()); // features internal to cut were deleted
     SequenceFeature sf = sfs.get(0);
     assertEquals("before", sf.getType());
     assertEquals(1, sf.getBegin());
     assertEquals(3, sf.getEnd());
     sf = sfs.get(1);
+    assertEquals("disulphide bond", sf.getType());
+    assertEquals(2, sf.getBegin());
+    assertEquals(5, sf.getEnd()); // truncated by cut
+    sf = sfs.get(2);
     assertEquals("overlap left", sf.getType());
     assertEquals(2, sf.getBegin());
     assertEquals(3, sf.getEnd()); // truncated by cut
-    sf = sfs.get(2);
-    assertEquals("overlap right", sf.getType());
-    assertEquals(4, sf.getBegin()); // shifted left by cut
-    assertEquals(5, sf.getEnd()); // truncated by cut
     sf = sfs.get(3);
     assertEquals("after", sf.getType());
     assertEquals(4, sf.getBegin()); // shifted left by cut
     assertEquals(6, sf.getEnd()); // shifted left by cut
+    sf = sfs.get(4);
+    assertEquals("overlap right", sf.getType());
+    assertEquals(4, sf.getBegin()); // shifted left by cut
+    assertEquals(4, sf.getEnd()); // truncated by cut
   }
 
   /**
@@ -711,16 +862,28 @@ public class EditCommandTest
      * create a sequence features on each subrange of 1-5
      */
     SequenceI seq0 = new Sequence("seq", "ABCDE");
+    int start = 8;
+    int end = 12;
+    seq0.setStart(start);
+    seq0.setEnd(end);
     AlignmentI alignment = new Alignment(new SequenceI[] { seq0 });
     alignment.setDataset(null);
-    for (int from = 1; from <= seq0.getLength(); from++)
+
+    /*
+     * create a new alignment with shared dataset sequence
+     */
+    AlignmentI copy = new Alignment(
+            new SequenceI[]
+            { alignment.getDataset().getSequenceAt(0).deriveSequence() });
+    SequenceI copySeq0 = copy.getSequenceAt(0);
+
+    for (int from = start; from <= end; from++)
     {
-      for (int to = from; to <= seq0.getLength(); to++)
+      for (int to = from; to <= end; to++)
       {
         String desc = String.format("%d-%d", from, to);
         SequenceFeature sf = new SequenceFeature("test", desc, from, to,
-                0f,
-                null);
+                0f, null);
         sf.setValue("from", Integer.valueOf(from));
         sf.setValue("to", Integer.valueOf(to));
         seq0.addSequenceFeature(sf);
@@ -729,109 +892,234 @@ public class EditCommandTest
     // sanity check
     List<SequenceFeature> sfs = seq0.getSequenceFeatures();
     assertEquals(func(5), sfs.size());
+    assertEquals(sfs, copySeq0.getSequenceFeatures());
+    String copySequenceFeatures = copySeq0.getSequenceFeatures().toString();
 
     /*
-     * now perform all possible cuts of subranges of 1-5 (followed by Undo)
+     * now perform all possible cuts of subranges of columns 1-5
      * and validate the resulting remaining sequence features!
      */
     SequenceI[] sqs = new SequenceI[] { seq0 };
 
-    // goal is to have this passing for all from/to values!!
-    // for (int from = 0; from < seq0.getLength(); from++)
-    // {
-    // for (int to = from; to < seq0.getLength(); to++)
-    for (int from = 1; from < 3; from++)
+    for (int from = 0; from < seq0.getLength(); from++)
     {
-      for (int to = 2; to < 3; to++)
+      for (int to = from; to < seq0.getLength(); to++)
       {
-        testee.appendEdit(Action.CUT, sqs, from, (to - from + 1),
-                alignment, true);
+        EditCommand ec = new EditCommand("Cut", Action.CUT, sqs, from, (to
+                - from + 1), alignment);
+        final String msg = String.format("Cut %d-%d ", from + 1, to + 1);
+        boolean newDatasetSequence = copySeq0.getDatasetSequence() != seq0
+                .getDatasetSequence();
+
+        verifyCut(seq0, from, to, msg, start);
+
+        /*
+         * verify copy alignment dataset sequence unaffected
+         */
+        assertEquals("Original dataset sequence was modified",
+                copySequenceFeatures,
+                copySeq0.getSequenceFeatures().toString());
 
+        /*
+         * verify any new dataset sequence was added to the
+         * alignment dataset
+         */
+        assertEquals("Wrong Dataset size after " + msg,
+                newDatasetSequence ? 2 : 1,
+                alignment.getDataset().getHeight());
+
+        /*
+         * undo and verify all restored
+         */
+        AlignmentI[] views = new AlignmentI[] { alignment };
+        ec.undoCommand(views);
         sfs = seq0.getSequenceFeatures();
+        assertEquals("After undo of " + msg, func(5), sfs.size());
+        verifyUndo(from, to, sfs);
+
+        /*
+         * verify copy alignment dataset sequence still unaffected
+         * and alignment dataset has shrunk (if it was added to)
+         */
+        assertEquals("Original dataset sequence was modified",
+                copySequenceFeatures,
+                copySeq0.getSequenceFeatures().toString());
+        assertEquals("Wrong Dataset size after Undo of " + msg, 1,
+                alignment.getDataset().getHeight());
 
         /*
-         * confirm the number of features has reduced by the
-         * number of features within the cut region i.e. by
-         * func(length of cut)
+         * redo and verify
          */
-        String msg = String.format("Cut %d-%d ", from, to);
-        if (to - from == 4)
-        {
-          // all columns cut
-          assertNull(sfs);
-        }
-        else
-        {
-          assertEquals(msg + "wrong number of features left", func(5)
-                  - func(to - from + 1), sfs.size());
-        }
+        ec.doCommand(views);
+        verifyCut(seq0, from, to, msg, start);
 
         /*
-         * inspect individual features
+         * verify copy alignment dataset sequence unaffected
+         * and any new dataset sequence readded to alignment dataset
          */
-        if (sfs != null)
-        {
-          for (SequenceFeature sf : sfs)
-          {
-            checkFeatureRelocation(sf, from + 1, to + 1);
-          }
-        }
+        assertEquals("Original dataset sequence was modified",
+                copySequenceFeatures,
+                copySeq0.getSequenceFeatures().toString());
+        assertEquals("Wrong Dataset size after Redo of " + msg,
+                newDatasetSequence ? 2 : 1,
+                alignment.getDataset().getHeight());
+
         /*
          * undo ready for next cut
          */
-        testee.undoCommand(new AlignmentI[] { alignment });
-        assertEquals(func(5), seq0.getSequenceFeatures().size());
+        ec.undoCommand(views);
+
+        /*
+         * final verify that copy alignment dataset sequence is still unaffected
+         * and that alignment dataset has shrunk
+         */
+        assertEquals("Original dataset sequence was modified",
+                copySequenceFeatures,
+                copySeq0.getSequenceFeatures().toString());
+        assertEquals("Wrong Dataset size after final Undo of " + msg, 1,
+                alignment.getDataset().getHeight());
       }
     }
   }
 
   /**
+   * Verify by inspection that the sequence features left on the sequence after
+   * a cut match the expected results. The trick to this is that we can parse
+   * each feature's original start-end positions from its description.
+   * 
+   * @param seq0
+   * @param from
+   * @param to
+   * @param msg
+   * @param seqStart
+   */
+  protected void verifyCut(SequenceI seq0, int from, int to,
+          final String msg, int seqStart)
+  {
+    List<SequenceFeature> sfs;
+    sfs = seq0.getSequenceFeatures();
+
+    Collections.sort(sfs, BY_DESCRIPTION);
+
+    /*
+     * confirm the number of features has reduced by the
+     * number of features within the cut region i.e. by
+     * func(length of cut); exception is a cut at start or end of sequence, 
+     * which retains the original coordinates, dataset sequence 
+     * and all its features
+     */
+    boolean datasetRetained = from == 0 || to == 4;
+    if (datasetRetained)
+    {
+      // dataset and all features retained
+      assertEquals(msg, func(5), sfs.size());
+    }
+    else if (to - from == 4)
+    {
+      // all columns were cut
+      assertTrue(sfs.isEmpty());
+    }
+    else
+    {
+      // failure in checkFeatureRelocation is more informative!
+      assertEquals(msg + "wrong number of features left", func(5)
+              - func(to - from + 1), sfs.size());
+    }
+
+    /*
+     * inspect individual features
+     */
+    for (SequenceFeature sf : sfs)
+    {
+      verifyFeatureRelocation(sf, from + 1, to + 1, !datasetRetained,
+              seqStart);
+    }
+  }
+
+  /**
+   * Check that after Undo, every feature has start/end that match its original
+   * "start" and "end" properties
+   * 
+   * @param from
+   * @param to
+   * @param sfs
+   */
+  protected void verifyUndo(int from, int to, List<SequenceFeature> sfs)
+  {
+    for (SequenceFeature sf : sfs)
+    {
+      final int oldFrom = ((Integer) sf.getValue("from")).intValue();
+      final int oldTo = ((Integer) sf.getValue("to")).intValue();
+      String msg = String.format(
+              "Undo cut of [%d-%d], feature at [%d-%d] ", from + 1, to + 1,
+              oldFrom, oldTo);
+      assertEquals(msg + "start", oldFrom, sf.getBegin());
+      assertEquals(msg + "end", oldTo, sf.getEnd());
+    }
+  }
+
+  /**
    * Helper method to check a feature has been correctly relocated after a cut
    * 
    * @param sf
    * @param from
-   *          start of cut (first residue cut)
+   *          start of cut (first residue cut 1..)
    * @param to
-   *          end of cut (last residue cut)
+   *          end of cut (last residue cut 1..)
+   * @param newDataset
+   * @param seqStart
    */
-  private void checkFeatureRelocation(SequenceFeature sf, int from, int to)
+  private void verifyFeatureRelocation(SequenceFeature sf, int from, int to,
+ boolean newDataset, int seqStart)
   {
     // TODO handle the gapped sequence case as well
     int cutSize = to - from + 1;
-    int oldFrom = ((Integer) sf.getValue("from")).intValue();
-    int oldTo = ((Integer) sf.getValue("to")).intValue();
+    final int oldFrom = ((Integer) sf.getValue("from")).intValue();
+    final int oldTo = ((Integer) sf.getValue("to")).intValue();
+    final int oldFromPosition = oldFrom - seqStart + 1; // 1..
+    final int oldToPosition = oldTo - seqStart + 1; // 1..
 
     String msg = String.format(
             "Feature %s relocated to %d-%d after cut of %d-%d",
             sf.getDescription(), sf.getBegin(), sf.getEnd(), from, to);
-    if (oldTo < from)
+    if (!newDataset)
+    {
+      // dataset retained with all features unchanged
+      assertEquals("0: " + msg, oldFrom, sf.getBegin());
+      assertEquals("0: " + msg, oldTo, sf.getEnd());
+    }
+    else if (oldToPosition < from)
     {
       // before cut region so unchanged
       assertEquals("1: " + msg, oldFrom, sf.getBegin());
       assertEquals("2: " + msg, oldTo, sf.getEnd());
     }
-    else if (oldFrom > to)
+    else if (oldFromPosition > to)
     {
       // follows cut region - shift by size of cut
-      assertEquals("3: " + msg, oldFrom - cutSize, sf.getBegin());
-      assertEquals("4: " + msg, oldTo - cutSize, sf.getEnd());
+      assertEquals("3: " + msg, newDataset ? oldFrom - cutSize : oldFrom,
+              sf.getBegin());
+      assertEquals("4: " + msg, newDataset ? oldTo - cutSize : oldTo,
+              sf.getEnd());
     }
-    else if (oldFrom < from && oldTo > to)
+    else if (oldFromPosition < from && oldToPosition > to)
     {
       // feature encloses cut region - shrink it right
       assertEquals("5: " + msg, oldFrom, sf.getBegin());
       assertEquals("6: " + msg, oldTo - cutSize, sf.getEnd());
     }
-    else if (oldFrom < from)
+    else if (oldFromPosition < from)
     {
       // feature overlaps left side of cut region - truncated right
-      assertEquals("7: " + msg, from - 1, sf.getEnd());
+      assertEquals("7: " + msg, from - 1 + seqStart - 1, sf.getEnd());
     }
-    else if (oldTo > to)
+    else if (oldToPosition > to)
     {
       // feature overlaps right side of cut region - truncated left
-      assertEquals("8: " + msg, from, sf.getBegin());
-      assertEquals("9: " + msg, from + oldTo - to - 1, sf.getEnd());
+      assertEquals("8: " + msg, newDataset ? from + seqStart - 1 : to + 1,
+              sf.getBegin());
+      assertEquals("9: " + msg, newDataset ? from + oldTo - to - 1 : oldTo,
+              sf.getEnd());
     }
     else
     {
@@ -844,30 +1132,32 @@ public class EditCommandTest
    * Test a cut action's relocation of sequence features
    */
   @Test(groups = { "Functional" })
-  public void testCut_gappedWithFeatures()
+  public void testCut_withFeatures5prime()
   {
+    SequenceI seq0 = new Sequence("seq/8-11", "A-BCC");
+    seq0.createDatasetSequence();
+    assertEquals(8, seq0.getStart());
+    seq0.addSequenceFeature(new SequenceFeature("", "", 10, 11, 0f,
+            null));
+    SequenceI[] seqsArray = new SequenceI[] { seq0 };
+    AlignmentI alignment = new Alignment(seqsArray);
+
     /*
-     * create sequence features before, after and overlapping
-     * a cut of columns/residues 4-7
+     * cut columns of A-B; same dataset sequence is retained, aligned sequence
+     * start becomes 10
      */
-    SequenceI seq0 = new Sequence("seq", "A-BCC");
-    seq0.addSequenceFeature(new SequenceFeature("", "", 3, 4, 0f,
-            null));
-    AlignmentI alignment = new Alignment(new SequenceI[] { seq0 });
-    // cut columns of A-B
-    Edit ec = testee.new Edit(Action.CUT, seqs, 0, 3, alignment); // cols 0-3
-                                                                  // base 0
+    Edit ec = testee.new Edit(Action.CUT, seqsArray, 0, 3, alignment);
     EditCommand.cut(ec, new AlignmentI[] { alignment });
   
     /*
-     * feature on CC(3-4) should now be on CC(1-2)
+     * feature on CC(10-11) should still be on CC(10-11)
      */
+    assertSame(seq0, alignment.getSequenceAt(0));
+    assertEquals(10, seq0.getStart());
     List<SequenceFeature> sfs = seq0.getSequenceFeatures();
     assertEquals(1, sfs.size());
     SequenceFeature sf = sfs.get(0);
-    assertEquals(1, sf.getBegin());
-    assertEquals(2, sf.getEnd());
-
-    // TODO add further cases including Undo - see JAL-2541
+    assertEquals(10, sf.getBegin());
+    assertEquals(11, sf.getEnd());
   }
 }
index 79bb2bb..9629b6f 100644 (file)
@@ -290,6 +290,61 @@ public class SequenceTest
     assertEquals(0, sq.findIndex(2));
   }
 
+  @Test(groups = { "Functional" })
+  public void testFindPositions()
+  {
+    SequenceI sq = new Sequence("test/8-13", "-ABC---DE-F--");
+
+    /*
+     * invalid inputs
+     */
+    assertNull(sq.findPositions(6, 5));
+    assertNull(sq.findPositions(0, 5));
+    assertNull(sq.findPositions(-1, 5));
+
+    /*
+     * all gapped ranges
+     */
+    assertNull(sq.findPositions(1, 1)); // 1-based columns
+    assertNull(sq.findPositions(5, 5));
+    assertNull(sq.findPositions(5, 6));
+    assertNull(sq.findPositions(5, 7));
+
+    /*
+     * all ungapped ranges
+     */
+    assertEquals(new Range(8, 8), sq.findPositions(2, 2)); // A
+    assertEquals(new Range(8, 9), sq.findPositions(2, 3)); // AB
+    assertEquals(new Range(8, 10), sq.findPositions(2, 4)); // ABC
+    assertEquals(new Range(9, 10), sq.findPositions(3, 4)); // BC
+
+    /*
+     * gap to ungapped range
+     */
+    assertEquals(new Range(8, 10), sq.findPositions(1, 4)); // ABC
+    assertEquals(new Range(11, 12), sq.findPositions(6, 9)); // DE
+
+    /*
+     * ungapped to gapped range
+     */
+    assertEquals(new Range(10, 10), sq.findPositions(4, 5)); // C
+    assertEquals(new Range(9, 13), sq.findPositions(3, 11)); // BCDEF
+
+    /*
+     * ungapped to ungapped enclosing gaps
+     */
+    assertEquals(new Range(10, 11), sq.findPositions(4, 8)); // CD
+    assertEquals(new Range(8, 13), sq.findPositions(2, 11)); // ABCDEF
+
+    /*
+     * gapped to gapped enclosing ungapped
+     */
+    assertEquals(new Range(8, 10), sq.findPositions(1, 5)); // ABC
+    assertEquals(new Range(11, 12), sq.findPositions(5, 10)); // DE
+    assertEquals(new Range(8, 13), sq.findPositions(1, 13)); // the lot
+    assertEquals(new Range(8, 13), sq.findPositions(1, 99));
+  }
+
   /**
    * Tests for the method that returns a dataset sequence position (start..) for
    * an aligned column position (base 0).
@@ -465,8 +520,7 @@ public class SequenceTest
     assertEquals("test:Pos13:Col10:startCol3:endCol10:tok0",
             PA.getValue(sq, "cursor").toString());
     sq.sequenceChanged();
-    assertEquals(12, sq.findPosition(8));
-    cursor = (SequenceCursor) PA.getValue(sq, "cursor");
+    assertEquals(12, sq.findPosition(8)); // E12
     // sequenceChanged() invalidates cursor.lastResidueColumn
     cursor = (SequenceCursor) PA.getValue(sq, "cursor");
     assertEquals("test:Pos12:Col9:startCol3:endCol0:tok1",
@@ -505,6 +559,13 @@ public class SequenceTest
     assertEquals(6, sq.getEnd());
     assertNull(PA.getValue(sq, "datasetSequence"));
 
+    sq = new Sequence("test", "ABCDE");
+    sq.deleteChars(0, 3);
+    assertEquals("DE", sq.getSequenceAsString());
+    assertEquals(4, sq.getStart());
+    assertEquals(5, sq.getEnd());
+    assertNull(PA.getValue(sq, "datasetSequence"));
+
     /*
      * delete at end
      */
@@ -514,6 +575,21 @@ public class SequenceTest
     assertEquals(1, sq.getStart());
     assertEquals(4, sq.getEnd());
     assertNull(PA.getValue(sq, "datasetSequence"));
+
+    /*
+     * delete more positions than there are
+     */
+    sq = new Sequence("test/8-11", "ABCD");
+    sq.deleteChars(0, 99);
+    assertEquals("", sq.getSequenceAsString());
+    assertEquals(12, sq.getStart()); // = findPosition(99) ?!?
+    assertEquals(11, sq.getEnd());
+
+    sq = new Sequence("test/8-11", "----");
+    sq.deleteChars(0, 99); // ArrayIndexOutOfBoundsException <= 2.10.2
+    assertEquals("", sq.getSequenceAsString());
+    assertEquals(8, sq.getStart());
+    assertEquals(11, sq.getEnd());
   }
 
   @Test(groups = { "Functional" })
@@ -1614,6 +1690,10 @@ public class SequenceTest
     // cursor should now be at [D 6]
     cursor = (SequenceCursor) PA.getValue(sq, "cursor");
     assertEquals(new SequenceCursor(sq, 11, 6, ++token), cursor);
+    assertEquals(0, cursor.lastColumnPosition); // not yet found
+    assertEquals(13, sq.findPosition(8)); // E13
+    cursor = (SequenceCursor) PA.getValue(sq, "cursor");
+    assertEquals(9, cursor.lastColumnPosition); // found
 
     /*
      * deleteChars should invalidate the cached cursor
@@ -1693,61 +1773,6 @@ public class SequenceTest
   }
 
   @Test(groups = { "Functional" })
-  public void testFindPositions()
-  {
-    SequenceI sq = new Sequence("test/8-13", "-ABC---DE-F--");
-
-    /*
-     * invalid inputs
-     */
-    assertNull(sq.findPositions(6, 5));
-    assertNull(sq.findPositions(0, 5));
-    assertNull(sq.findPositions(-1, 5));
-
-    /*
-     * all gapped ranges
-     */
-    assertNull(sq.findPositions(1, 1)); // 1-based columns
-    assertNull(sq.findPositions(5, 5));
-    assertNull(sq.findPositions(5, 6));
-    assertNull(sq.findPositions(5, 7));
-
-    /*
-     * all ungapped ranges
-     */
-    assertEquals(new Range(8, 8), sq.findPositions(2, 2)); // A
-    assertEquals(new Range(8, 9), sq.findPositions(2, 3)); // AB
-    assertEquals(new Range(8, 10), sq.findPositions(2, 4)); // ABC
-    assertEquals(new Range(9, 10), sq.findPositions(3, 4)); // BC
-
-    /*
-     * gap to ungapped range
-     */
-    assertEquals(new Range(8, 10), sq.findPositions(1, 4)); // ABC
-    assertEquals(new Range(11, 12), sq.findPositions(6, 9)); // DE
-
-    /*
-     * ungapped to gapped range
-     */
-    assertEquals(new Range(10, 10), sq.findPositions(4, 5)); // C
-    assertEquals(new Range(9, 13), sq.findPositions(3, 11)); // BCDEF
-
-    /*
-     * ungapped to ungapped enclosing gaps
-     */
-    assertEquals(new Range(10, 11), sq.findPositions(4, 8)); // CD
-    assertEquals(new Range(8, 13), sq.findPositions(2, 11)); // ABCDEF
-
-    /*
-     * gapped to gapped enclosing ungapped
-     */
-    assertEquals(new Range(8, 10), sq.findPositions(1, 5)); // ABC
-    assertEquals(new Range(11, 12), sq.findPositions(5, 10)); // DE
-    assertEquals(new Range(8, 13), sq.findPositions(1, 13)); // the lot
-    assertEquals(new Range(8, 13), sq.findPositions(1, 99));
-  }
-
-  @Test(groups = { "Functional" })
   public void testGapBitset()
   {
     SequenceI sq = new Sequence("test/8-13", "-ABC---DE-F--");
index db21c2f..6e7dd02 100644 (file)
@@ -2,6 +2,7 @@ package jalview.datamodel.features;
 
 import static org.testng.Assert.assertEquals;
 import static org.testng.Assert.assertFalse;
+import static org.testng.Assert.assertSame;
 import static org.testng.Assert.assertTrue;
 
 import jalview.datamodel.SequenceFeature;
@@ -774,7 +775,7 @@ public class FeatureStoreTest
   public void testShiftFeatures()
   {
     FeatureStore fs = new FeatureStore();
-    assertFalse(fs.shiftFeatures(1));
+    assertFalse(fs.shiftFeatures(0, 1)); // nothing to do
 
     SequenceFeature sf1 = new SequenceFeature("Cath", "", 2, 5, 0f, null);
     fs.addFeature(sf1);
@@ -790,9 +791,9 @@ public class FeatureStoreTest
     fs.addFeature(sf4);
 
     /*
-     * shift features right by 5
+     * shift all features right by 5
      */
-    assertTrue(fs.shiftFeatures(5));
+    assertTrue(fs.shiftFeatures(0, 5));
 
     // non-positional features untouched:
     List<SequenceFeature> nonPos = fs.getNonPositionalFeatures();
@@ -818,7 +819,7 @@ public class FeatureStoreTest
      * feature at [7-10] should be removed
      * feature at [13-19] should become [1-4] 
      */
-    assertTrue(fs.shiftFeatures(-15));
+    assertTrue(fs.shiftFeatures(0, -15));
     pos = fs.getPositionalFeatures();
     assertEquals(pos.size(), 2);
     SequenceFeatures.sortFeatures(pos, true);
@@ -826,6 +827,32 @@ public class FeatureStoreTest
     assertEquals(pos.get(0).getEnd(), 4);
     assertEquals(pos.get(1).getBegin(), 13);
     assertEquals(pos.get(1).getEnd(), 22);
+
+    /*
+     * shift right by 4 from position 2 onwards
+     * feature at [1-4] unchanged, feature at [13-22] shifts
+     */
+    assertTrue(fs.shiftFeatures(2, 4));
+    pos = fs.getPositionalFeatures();
+    assertEquals(pos.size(), 2);
+    SequenceFeatures.sortFeatures(pos, true);
+    assertEquals(pos.get(0).getBegin(), 1);
+    assertEquals(pos.get(0).getEnd(), 4);
+    assertEquals(pos.get(1).getBegin(), 17);
+    assertEquals(pos.get(1).getEnd(), 26);
+
+    /*
+     * shift right by 4 from position 18 onwards
+     * should be no change
+     */
+    SequenceFeature f1 = pos.get(0);
+    SequenceFeature f2 = pos.get(1);
+    assertFalse(fs.shiftFeatures(18, 4)); // no update
+    pos = fs.getPositionalFeatures();
+    assertEquals(pos.size(), 2);
+    SequenceFeatures.sortFeatures(pos, true);
+    assertSame(pos.get(0), f1);
+    assertSame(pos.get(1), f2);
   }
 
   @Test(groups = "Functional")
index 32987b0..29e76bb 100644 (file)
@@ -1161,7 +1161,7 @@ public class SequenceFeaturesTest
   public void testShiftFeatures()
   {
     SequenceFeatures store = new SequenceFeatures();
-    assertFalse(store.shiftFeatures(1));
+    assertFalse(store.shiftFeatures(0, 1));
 
     SequenceFeature sf1 = new SequenceFeature("Cath", "", 2, 5, 0f, null);
     store.add(sf1);
@@ -1179,7 +1179,7 @@ public class SequenceFeaturesTest
     /*
      * shift features right by 5
      */
-    assertTrue(store.shiftFeatures(5));
+    assertTrue(store.shiftFeatures(0, 5));
   
     // non-positional features untouched:
     List<SequenceFeature> nonPos = store.getNonPositionalFeatures();
@@ -1208,7 +1208,7 @@ public class SequenceFeaturesTest
      * feature at [7-10] should be removed
      * feature at [13-19] should become [1-4] 
      */
-    assertTrue(store.shiftFeatures(-15));
+    assertTrue(store.shiftFeatures(0, -15));
     pos = store.getPositionalFeatures();
     assertEquals(pos.size(), 2);
     SequenceFeatures.sortFeatures(pos, true);
@@ -1218,6 +1218,35 @@ public class SequenceFeaturesTest
     assertEquals(pos.get(1).getBegin(), 13);
     assertEquals(pos.get(1).getEnd(), 22);
     assertEquals(pos.get(1).getType(), "Disulfide bond");
+
+    /*
+     * shift right by 4 from column 2
+     * feature at [1-4] should be unchanged
+     * feature at [13-22] should become [17-26] 
+     */
+    assertTrue(store.shiftFeatures(2, 4));
+    pos = store.getPositionalFeatures();
+    assertEquals(pos.size(), 2);
+    SequenceFeatures.sortFeatures(pos, true);
+    assertEquals(pos.get(0).getBegin(), 1);
+    assertEquals(pos.get(0).getEnd(), 4);
+    assertEquals(pos.get(0).getType(), "Metal");
+    assertEquals(pos.get(1).getBegin(), 17);
+    assertEquals(pos.get(1).getEnd(), 26);
+    assertEquals(pos.get(1).getType(), "Disulfide bond");
+
+    /*
+     * shift right from column 18
+     * should be no updates
+     */
+    SequenceFeature f1 = pos.get(0);
+    SequenceFeature f2 = pos.get(1);
+    assertFalse(store.shiftFeatures(18, 6));
+    pos = store.getPositionalFeatures();
+    assertEquals(pos.size(), 2);
+    SequenceFeatures.sortFeatures(pos, true);
+    assertSame(pos.get(0), f1);
+    assertSame(pos.get(1), f2);
   }
 
   @Test(groups = "Functional")
@@ -1232,4 +1261,18 @@ public class SequenceFeaturesTest
     assertTrue(store.isOntologyTerm("junk", new String[] {}));
     assertTrue(store.isOntologyTerm("junk", (String[]) null));
   }
+
+  @Test(groups = "Functional")
+  public void testDeleteAll()
+  {
+    SequenceFeaturesI store = new SequenceFeatures();
+    assertFalse(store.hasFeatures());
+    store.deleteAll();
+    assertFalse(store.hasFeatures());
+    store.add(new SequenceFeature("Cath", "Desc", 12, 20, 0f, "Group"));
+    store.add(new SequenceFeature("Pfam", "Desc", 6, 12, 2f, "Group2"));
+    assertTrue(store.hasFeatures());
+    store.deleteAll();
+    assertFalse(store.hasFeatures());
+  }
 }
index 28c5cf0..69634a9 100644 (file)
@@ -44,12 +44,12 @@ public class TestHtsContigDb
   @Test(groups = "Functional")
   public final void testGetSequenceProxy() throws Exception
   {
-    String pathname = "test/jalview/ext/htsjdk/pgmb.fasta";
+    String pathname = "test/jalview/ext/htsjdk/pgmB.fasta";
     HtsContigDb db = new HtsContigDb("ADB", new File(pathname));
-    
+
     assertTrue(db.isValid());
     assertTrue(db.isIndexed()); // htsjdk opens the .fai file
-    
+
     SequenceI sq = db.getSequenceProxy("Deminut");
     assertNotNull(sq);
     assertEquals(sq.getLength(), 606);
@@ -60,7 +60,7 @@ public class TestHtsContigDb
     sq = db.getSequenceProxy("PPL_06716");
     assertNotNull(sq);
     assertEquals(sq.getLength(), 602);
-    
+
     // dict = db.getDictionary(f, truncate))
   }
 
@@ -73,7 +73,7 @@ public class TestHtsContigDb
     expectedExceptions = java.lang.IllegalArgumentException.class)
   public final void testGetSequenceProxy_indexed()
   {
-    String pathname = "test/jalview/ext/htsjdk/pgmb.fasta.fai";
+    String pathname = "test/jalview/ext/htsjdk/pgmB.fasta.fai";
     new HtsContigDb("ADB", new File(pathname));
     fail("Expected exception opening .fai file");
   }
@@ -92,17 +92,19 @@ public class TestHtsContigDb
   @Test(groups = "Functional")
   public void testCreateFastaSequenceIndex() throws IOException
   {
-    File fasta = new File("test/jalview/ext/htsjdk/pgmb.fasta");
-    
+    File fasta = new File("test/jalview/ext/htsjdk/pgmB.fasta");
+
     /*
      * create .fai with no overwrite fails if it exists
      */
-    try {
+    try
+    {
       HtsContigDb.createFastaSequenceIndex(fasta.toPath(), false);
       fail("Expected exception");
     } catch (IOException e)
     {
-      // expected
+      // we expect an IO Exception because the pgmB.fasta.fai exists, since it
+      // was checked it in.
     }
 
     /*
index f5e637c..bcad464 100644 (file)
@@ -62,9 +62,9 @@ public class JmolParserTest
    * 1GAQ has been reduced to alpha carbons only
    * 1QCF is the full PDB file including headers, HETATM etc
    */
-  String[] testFile = new String[] { "./examples/1GAQ.txt",
+  String[] testFile = new String[] { "./examples/1gaq.txt",
       "./test/jalview/ext/jmol/1xyz.pdb",
-      "./test/jalview/ext/jmol/1qcf.pdb" };
+      "./test/jalview/ext/jmol/1QCF.pdb" };
 
   //@formatter:off
   // a modified and very cut-down extract of 4UJ4
@@ -130,17 +130,17 @@ public class JmolParserTest
       JmolParser jtest = new JmolParser(pdbStr, DataSourceType.FILE);
       Vector<SequenceI> seqs = jtest.getSeqs(), mcseqs = mctest.getSeqs();
 
-      assertTrue(
-              "No sequences extracted from testfile\n"
-                      + (jtest.hasWarningMessage() ? jtest.getWarningMessage()
-                              : "(No warnings raised)"), seqs != null
-                      && seqs.size() > 0);
+      assertTrue("No sequences extracted from testfile\n"
+              + (jtest.hasWarningMessage() ? jtest.getWarningMessage()
+                      : "(No warnings raised)"),
+              seqs != null && seqs.size() > 0);
       for (SequenceI sq : seqs)
       {
-        assertEquals("JMol didn't process " + pdbStr
-                + " to the same sequence as MCView",
-                sq.getSequenceAsString(), mcseqs.remove(0)
-                        .getSequenceAsString());
+        assertEquals(
+                "JMol didn't process " + pdbStr
+                        + " to the same sequence as MCView",
+                sq.getSequenceAsString(),
+                mcseqs.remove(0).getSequenceAsString());
         AlignmentI al = new Alignment(new SequenceI[] { sq });
         validateSecStrRows(al);
       }
@@ -175,13 +175,15 @@ public class JmolParserTest
 
   private void checkFirstAAIsAssoc(SequenceI sq)
   {
-    assertTrue("No secondary structure assigned for protein sequence for "
-            + sq.getName(),
+    assertTrue(
+            "No secondary structure assigned for protein sequence for "
+                    + sq.getName(),
             sq.getAnnotation() != null && sq.getAnnotation().length >= 1
                     && sq.getAnnotation()[0].hasIcons);
     assertTrue(
             "Secondary structure not associated for sequence "
-                    + sq.getName(), sq.getAnnotation()[0].sequenceRef == sq);
+                    + sq.getName(),
+            sq.getAnnotation()[0].sequenceRef == sq);
   }
 
   /**
@@ -194,7 +196,8 @@ public class JmolParserTest
   {
     PDBfile mctest = new PDBfile(false, false, false,
             pastePDBDataWithChainBreak, DataSourceType.PASTE);
-    JmolParser jtest = new JmolParser(pastePDBDataWithChainBreak, DataSourceType.PASTE);
+    JmolParser jtest = new JmolParser(pastePDBDataWithChainBreak,
+            DataSourceType.PASTE);
     Vector<SequenceI> seqs = jtest.getSeqs();
     Vector<SequenceI> mcseqs = mctest.getSeqs();
 
@@ -216,8 +219,7 @@ public class JmolParserTest
   {
     PDBfile mctest = new PDBfile(false, false, false, pdbWithAltLoc,
             DataSourceType.PASTE);
-    JmolParser jtest = new JmolParser(pdbWithAltLoc,
-            DataSourceType.PASTE);
+    JmolParser jtest = new JmolParser(pdbWithAltLoc, DataSourceType.PASTE);
     Vector<SequenceI> seqs = jtest.getSeqs();
     Vector<SequenceI> mcseqs = mctest.getSeqs();
 
index bdda48d..f13a877 100644 (file)
@@ -20,6 +20,7 @@
  */
 package jalview.gui;
 
+import static org.junit.Assert.assertNotEquals;
 import static org.testng.Assert.assertEquals;
 import static org.testng.Assert.assertFalse;
 import static org.testng.Assert.assertNotSame;
@@ -599,4 +600,26 @@ public class AlignFrameTest
     sp.valueChanged(22);
     assertEquals(av2.getResidueShading().getConservationInc(), 22);
   }
+
+  /**
+   * Verify that making a New View preserves the dataset reference for the
+   * alignment. Otherwise, see a 'duplicate jar entry' reference when trying to
+   * save alignments with multiple views, and codon mappings will not be shared
+   * across all panels in a split frame.
+   * 
+   * @see Jalview2xmlTests#testStoreAndRecoverColourThresholds()
+   */
+  @Test(groups = "Functional")
+  public void testNewView_dsRefPreserved()
+  {
+    AlignViewport av = af.getViewport();
+    AlignmentI al = av.getAlignment();
+    AlignmentI original_ds = al.getDataset();
+    af.newView_actionPerformed(null);
+    assertNotEquals("New view didn't select the a new panel", av,
+            af.getViewport());
+    org.testng.Assert.assertEquals(original_ds,
+            af.getViewport().getAlignment().getDataset(),
+            "Dataset was not preserved in new view");
+  }
 }
diff --git a/test/jalview/gui/CalculationChooserTest.java b/test/jalview/gui/CalculationChooserTest.java
new file mode 100644 (file)
index 0000000..6c2e777
--- /dev/null
@@ -0,0 +1,98 @@
+package jalview.gui;
+
+import static org.testng.Assert.assertEquals;
+import static org.testng.Assert.assertSame;
+
+import jalview.analysis.scoremodels.ScoreModels;
+import jalview.api.analysis.ScoreModelI;
+import jalview.bin.Cache;
+
+import java.util.List;
+
+import org.testng.annotations.BeforeClass;
+import org.testng.annotations.Test;
+
+public class CalculationChooserTest
+{
+  @BeforeClass(alwaysRun = true)
+  public void setUp()
+  {
+    // read-only Jalview properties
+    Cache.loadProperties("test/jalview/io/testProps.jvprops");
+    Cache.applicationProperties.setProperty("BLOSUM62_PCA_FOR_NUCLEOTIDE",
+            Boolean.FALSE.toString());
+  }
+
+  @Test(groups = "Functional")
+  public void testGetApplicableScoreModels()
+  {
+    ScoreModels models = ScoreModels.getInstance();
+    ScoreModelI blosum62 = models.getBlosum62();
+    ScoreModelI pam250 = models.getPam250();
+    ScoreModelI dna = models.getDefaultModel(false);
+
+    /*
+     * peptide models for PCA
+     */
+    List<ScoreModelI> filtered = CalculationChooser
+            .getApplicableScoreModels(false, true);
+    assertEquals(filtered.size(), 4);
+    assertSame(filtered.get(0), blosum62);
+    assertSame(filtered.get(1), pam250);
+    assertEquals(filtered.get(2).getName(), "PID");
+    assertEquals(filtered.get(3).getName(), "Sequence Feature Similarity");
+
+    /*
+     * peptide models for Tree are the same
+     */
+    filtered = CalculationChooser.getApplicableScoreModels(false, false);
+    assertEquals(filtered.size(), 4);
+    assertSame(filtered.get(0), blosum62);
+    assertSame(filtered.get(1), pam250);
+    assertEquals(filtered.get(2).getName(), "PID");
+    assertEquals(filtered.get(3).getName(), "Sequence Feature Similarity");
+
+    /*
+     * nucleotide models for PCA
+     */
+    filtered = CalculationChooser.getApplicableScoreModels(true, true);
+    assertEquals(filtered.size(), 3);
+    assertSame(filtered.get(0), dna);
+    assertEquals(filtered.get(1).getName(), "PID");
+    assertEquals(filtered.get(2).getName(), "Sequence Feature Similarity");
+
+    /*
+     * nucleotide models for Tree are the same
+     */
+    filtered = CalculationChooser.getApplicableScoreModels(true, false);
+    assertEquals(filtered.size(), 3);
+    assertSame(filtered.get(0), dna);
+    assertEquals(filtered.get(1).getName(), "PID");
+    assertEquals(filtered.get(2).getName(), "Sequence Feature Similarity");
+
+    /*
+     * enable inclusion of BLOSUM62 for nucleotide PCA (JAL-2962)
+     */
+    Cache.applicationProperties.setProperty("BLOSUM62_PCA_FOR_NUCLEOTIDE",
+            Boolean.TRUE.toString());
+
+    /*
+     * nucleotide models for Tree are unchanged
+     */
+    filtered = CalculationChooser.getApplicableScoreModels(true, false);
+    assertEquals(filtered.size(), 3);
+    assertSame(filtered.get(0), dna);
+    assertEquals(filtered.get(1).getName(), "PID");
+    assertEquals(filtered.get(2).getName(), "Sequence Feature Similarity");
+
+    /*
+     * nucleotide models for PCA add BLOSUM62 as last option
+     */
+    filtered = CalculationChooser.getApplicableScoreModels(true, true);
+    assertEquals(filtered.size(), 4);
+    assertSame(filtered.get(0), dna);
+    assertEquals(filtered.get(1).getName(), "PID");
+    assertEquals(filtered.get(2).getName(), "Sequence Feature Similarity");
+    assertSame(filtered.get(3), blosum62);
+  }
+}
index e93bfac..9b21274 100644 (file)
@@ -1,6 +1,7 @@
 package jalview.gui;
 
 import static org.testng.Assert.assertEquals;
+import static org.testng.Assert.assertNotNull;
 import static org.testng.Assert.assertTrue;
 
 import jalview.analysis.AlignmentGenerator;
@@ -11,6 +12,7 @@ import jalview.datamodel.SequenceGroup;
 import jalview.io.DataSourceType;
 import jalview.io.FileLoader;
 
+import java.awt.event.MouseEvent;
 import java.io.File;
 import java.io.IOException;
 import java.io.PrintStream;
@@ -18,6 +20,8 @@ import java.io.PrintStream;
 import org.testng.annotations.BeforeClass;
 import org.testng.annotations.Test;
 
+import junit.extensions.PA;
+
 public class FreeUpMemoryTest
 {
   private static final int ONE_MB = 1000 * 1000;
@@ -30,16 +34,12 @@ public class FreeUpMemoryTest
   {
     Jalview.main(new String[] { "-nonews", "-props",
         "test/jalview/testProps.jvprops" });
-    Cache.applicationProperties.setProperty("SHOW_ANNOTATIONS",
-            Boolean.TRUE.toString());
-    Cache.applicationProperties.setProperty("SHOW_QUALITY",
-            Boolean.TRUE.toString());
-    Cache.applicationProperties.setProperty("SHOW_CONSERVATION",
-            Boolean.TRUE.toString());
-    Cache.applicationProperties.setProperty("SHOW_OCCUPANCY",
-            Boolean.TRUE.toString());
-    Cache.applicationProperties.setProperty("SHOW_IDENTITY",
-            Boolean.TRUE.toString());
+    String True = Boolean.TRUE.toString();
+    Cache.applicationProperties.setProperty("SHOW_ANNOTATIONS", True);
+    Cache.applicationProperties.setProperty("SHOW_QUALITY", True);
+    Cache.applicationProperties.setProperty("SHOW_CONSERVATION", True);
+    Cache.applicationProperties.setProperty("SHOW_OCCUPANCY", True);
+    Cache.applicationProperties.setProperty("SHOW_IDENTITY", True);
   }
 
   /**
@@ -84,18 +84,19 @@ public class FreeUpMemoryTest
   protected void checkUsedMemory(long expectedMax)
   {
     /*
-     * request garbage collection and wait briefly for it to run;
+     * request garbage collection and wait for it to run;
      * NB there is no guarantee when, or whether, it will do so
+     * wait time depends on JRE/processor, generous allowance here  
      */
     System.gc();
-    waitFor(100);
+    waitFor(1500);
 
     /*
      * a second gc() call should not be necessary - but it is!
      * the test passes with it, and fails without it
      */
     System.gc();
-    waitFor(100);
+    waitFor(1500);
 
     /*
      * check used memory is 'reasonably low'
@@ -142,6 +143,20 @@ public class FreeUpMemoryTest
     }
 
     /*
+     * open an Overview window
+     */
+    af.overviewMenuItem_actionPerformed(null);
+    assertNotNull(af.alignPanel.overviewPanel);
+
+    /*
+     * exercise the pop-up menu in the Overview Panel (JAL-2864)
+     */
+    Object[] args = new Object[] {
+        new MouseEvent(af, 0, 0, 0, 0, 0, 1, true) };
+    PA.invokeMethod(af.alignPanel.overviewPanel,
+            "showPopupMenu(java.awt.event.MouseEvent)", args);
+
+    /*
      * set a selection group - potential memory leak if it retains
      * a reference to the alignment
      */
diff --git a/test/jalview/gui/ScalePanelTest.java b/test/jalview/gui/ScalePanelTest.java
new file mode 100644 (file)
index 0000000..91b541c
--- /dev/null
@@ -0,0 +1,58 @@
+package jalview.gui;
+
+import static org.testng.Assert.assertTrue;
+
+import jalview.datamodel.Alignment;
+import jalview.datamodel.AlignmentI;
+import jalview.datamodel.Sequence;
+import jalview.datamodel.SequenceGroup;
+import jalview.datamodel.SequenceI;
+
+import java.awt.event.MouseEvent;
+
+import org.testng.annotations.BeforeClass;
+import org.testng.annotations.Test;
+
+public class ScalePanelTest
+{
+  @BeforeClass(alwaysRun = true)
+  public void setUpJvOptionPane()
+  {
+    JvOptionPane.setInteractiveMode(false);
+    JvOptionPane.setMockResponse(JvOptionPane.CANCEL_OPTION);
+  }
+
+  @Test(groups = "Functional")
+  public void testPreventNegativeStartColumn()
+  {
+    SequenceI seq1 = new Sequence("Seq1", "MATRESS");
+    SequenceI seq2 = new Sequence("Seq2", "MADNESS");
+    AlignmentI al = new Alignment(new SequenceI[] { seq1, seq2 });
+    
+    AlignFrame alignFrame = new AlignFrame(al, al.getWidth(),
+            al.getHeight());
+    ScalePanel scalePanel = new ScalePanel(
+            alignFrame.getViewport(), alignFrame.alignPanel
+    );
+    
+    MouseEvent mouse = new MouseEvent(
+            scalePanel, 0, 1, 0, 4, 0, 1, false
+    );
+    scalePanel.mousePressed(mouse);
+    scalePanel.mouseDragged(mouse);
+
+    // simulate dragging selection leftwards beyond the sequences giving
+    // negative X
+    mouse = new MouseEvent(scalePanel, 0, 1, 0, -30, 0, 1, false);
+
+    scalePanel.mouseReleased(mouse);
+
+    SequenceGroup sg = scalePanel.av.getSelectionGroup();
+    int startCol = sg.getStartRes();
+
+    assertTrue(startCol >= 0);
+
+
+  }
+
+}
index 97ded5a..2cde593 100644 (file)
@@ -188,9 +188,23 @@ public class MatrixTest
       }
     }
     Matrix m1 = new Matrix(in);
+
     Matrix m2 = (Matrix) m1.copy();
     assertNotSame(m1, m2);
     assertTrue(matrixEquals(m1, m2));
+    assertNull(m2.d);
+    assertNull(m2.e);
+
+    /*
+     * now add d and e vectors and recopy
+     */
+    m1.d = Arrays.copyOf(in[2], in[2].length);
+    m1.e = Arrays.copyOf(in[4], in[4].length);
+    m2 = (Matrix) m1.copy();
+    assertNotSame(m2.d, m1.d);
+    assertNotSame(m2.e, m1.e);
+    assertEquals(m2.d, m1.d);
+    assertEquals(m2.e, m1.e);
   }
 
   /**
@@ -356,7 +370,7 @@ public class MatrixTest
     assertMatricesMatch(m1, m2);
   }
 
-  private void assertMatricesMatch(MatrixI m1, MatrixI m2)
+  public static void assertMatricesMatch(MatrixI m1, MatrixI m2)
   {
     if (m1.height() != m2.height())
     {
@@ -378,8 +392,10 @@ public class MatrixTest
         }
       }
     }
-    ArrayAsserts.assertArrayEquals(m1.getD(), m2.getD(), 0.00001d);
-    ArrayAsserts.assertArrayEquals(m1.getE(), m2.getE(), 0.00001d);
+    ArrayAsserts.assertArrayEquals("D vector", m1.getD(), m2.getD(),
+            0.00001d);
+    ArrayAsserts.assertArrayEquals("E vector", m1.getE(), m2.getE(),
+            0.00001d);
   }
 
   @Test(groups = "Functional")
diff --git a/test/jalview/math/RotatableMatrixTest.java b/test/jalview/math/RotatableMatrixTest.java
new file mode 100644 (file)
index 0000000..06982d5
--- /dev/null
@@ -0,0 +1,157 @@
+package jalview.math;
+
+import static org.testng.Assert.assertEquals;
+
+import jalview.math.RotatableMatrix.Axis;
+
+import org.testng.annotations.BeforeMethod;
+import org.testng.annotations.Test;
+
+public class RotatableMatrixTest
+{
+  private RotatableMatrix rm;
+
+  @BeforeMethod(alwaysRun = true)
+  public void setUp()
+  {
+    rm = new RotatableMatrix();
+
+    /*
+     * 0.5 1.0 1.5
+     * 1.0 2.0 3.0
+     * 1.5 3.0 4.5
+     */
+    for (int i = 1; i <= 3; i++)
+    {
+      for (int j = 1; j <= 3; j++)
+      {
+        rm.setValue(i - 1, j - 1, i * j / 2f);
+      }
+    }
+  }
+
+  @Test(groups = "Functional")
+  public void testPreMultiply()
+  {
+    float[][] pre = new float[3][3];
+    int i = 1;
+    for (int j = 0; j < 3; j++)
+    {
+      for (int k = 0; k < 3; k++)
+      {
+        pre[j][k] = i++;
+      }
+    }
+
+    rm.preMultiply(pre);
+
+    /*
+     * check rm[i, j] is now the product of the i'th row of pre
+     * and the j'th column of (original) rm
+     */
+    for (int j = 0; j < 3; j++)
+    {
+      for (int k = 0; k < 3; k++)
+      {
+        float expected = 0f;
+        for (int l = 0; l < 3; l++)
+        {
+          float rm_l_k = (l + 1) * (k + 1) / 2f;
+          expected += pre[j][l] * rm_l_k;
+        }
+        assertEquals(rm.getValue(j, k), expected,
+                String.format("[%d, %d]", j, k));
+      }
+    }
+  }
+
+  @Test(groups = "Functional")
+  public void testVectorMultiply()
+  {
+    float[] result = rm.vectorMultiply(new float[] { 2f, 3f, 4.5f });
+
+    // vector times first column of matrix
+    assertEquals(result[0], 2f * 0.5f + 3f * 1f + 4.5f * 1.5f);
+
+    // vector times second column of matrix
+    assertEquals(result[1], 2f * 1.0f + 3f * 2f + 4.5f * 3f);
+
+    // vector times third column of matrix
+    assertEquals(result[2], 2f * 1.5f + 3f * 3f + 4.5f * 4.5f);
+  }
+
+  @Test(groups = "Functional")
+  public void testGetRotation()
+  {
+    float theta = 60f;
+    double cosTheta = Math.cos((theta * Math.PI / 180f));
+    double sinTheta = Math.sin((theta * Math.PI / 180f));
+
+    /*
+     * sanity check that sin(60) = sqrt(3) / 2, cos(60) = 1/2
+     */
+    double delta = 0.0001d;
+    assertEquals(cosTheta, 0.5f, delta);
+    assertEquals(sinTheta, Math.sqrt(3d) / 2d, delta);
+
+    /*
+     * so far so good, now verify rotations
+     * @see https://en.wikipedia.org/wiki/Rotation_matrix#Basic_rotations
+     */
+
+    /*
+     * 60 degrees about X axis should be
+     *  1   0   0 
+     *  0  cos -sin
+     *  0  sin cos
+     *  but code applies the negative of this
+     *  nb cos(-x) = cos(x), sin(-x) = -sin(x)
+     */
+    float[][] rot = RotatableMatrix.getRotation(theta, Axis.X);
+    assertEquals(rot[0][0], 1f, delta);
+    assertEquals(rot[0][1], 0f, delta);
+    assertEquals(rot[0][2], 0f, delta);
+    assertEquals(rot[1][0], 0f, delta);
+    assertEquals(rot[1][1], cosTheta, delta);
+    assertEquals(rot[1][2], sinTheta, delta);
+    assertEquals(rot[2][0], 0f, delta);
+    assertEquals(rot[2][1], -sinTheta, delta);
+    assertEquals(rot[2][2], cosTheta, delta);
+
+    /*
+     * 60 degrees about Y axis should be
+     *   cos 0 sin
+     *    0  1  0
+     *  -sin 0 cos
+     *  but code applies the negative of this
+     */
+    rot = RotatableMatrix.getRotation(theta, Axis.Y);
+    assertEquals(rot[0][0], cosTheta, delta);
+    assertEquals(rot[0][1], 0f, delta);
+    assertEquals(rot[0][2], -sinTheta, delta);
+    assertEquals(rot[1][0], 0f, delta);
+    assertEquals(rot[1][1], 1f, delta);
+    assertEquals(rot[1][2], 0f, delta);
+    assertEquals(rot[2][0], sinTheta, delta);
+    assertEquals(rot[2][1], 0f, delta);
+    assertEquals(rot[2][2], cosTheta, delta);
+
+    /*
+     * 60 degrees about Z axis should be
+     *  cos -sin 0
+     *  sin  cos 0
+     *   0    0  1
+     * - and it is!
+     */
+    rot = RotatableMatrix.getRotation(theta, Axis.Z);
+    assertEquals(rot[0][0], cosTheta, delta);
+    assertEquals(rot[0][1], -sinTheta, delta);
+    assertEquals(rot[0][2], 0f, delta);
+    assertEquals(rot[1][0], sinTheta, delta);
+    assertEquals(rot[1][1], cosTheta, delta);
+    assertEquals(rot[1][2], 0f, delta);
+    assertEquals(rot[2][0], 0f, delta);
+    assertEquals(rot[2][1], 0f, delta);
+    assertEquals(rot[2][2], 1f, delta);
+  }
+}
index f0fc3fd..3f4ed71 100644 (file)
@@ -27,6 +27,7 @@ import static org.testng.Assert.assertNull;
 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,6 +50,7 @@ import jalview.gui.AlignmentPanel;
 import jalview.gui.Desktop;
 import jalview.gui.FeatureRenderer;
 import jalview.gui.JvOptionPane;
+import jalview.gui.PCAPanel;
 import jalview.gui.PopupMenu;
 import jalview.gui.SliderPanel;
 import jalview.io.DataSourceType;
@@ -77,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;
@@ -1038,4 +1042,130 @@ public class Jalview2xmlTests extends Jalview2xmlBase
     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");
+  }
 }
index bc74d8a..885cb71 100644 (file)
@@ -100,24 +100,27 @@ public class ViewStyleTest
   private boolean copyConstructorIgnores(Field field)
   {
     /*
-     * just instrumentation added by test coverage while testing
+     * ignore instrumentation added by jacoco for test coverage
      */
-    String type = field.getClass().toString();
-    if (type.toString().contains("com_atlassian_clover"))
+    if (field.isSynthetic())
     {
-      // instrumentation added for test coverage - ignore
       return true;
     }
+    if (field.getType().toString().contains("com_atlassian_clover"))
+    {
+      return true;
+    }
+
     return false;
   }
-
+  
   /**
-   * Change the value of one field in a ViewStyle object
-   * 
-   * @param vs
-   * @param field
-   * @throws IllegalAccessException
-   */
+  * Change the value of one field in a ViewStyle object
+  * 
+  * @param vs
+  * @param field
+  * @throws IllegalAccessException
+  */
   protected void changeValue(ViewStyle vs, Field field)
           throws IllegalAccessException
   {
index e38064e..54f4e48 100644 (file)
@@ -1,6 +1,8 @@
 Checkstyle for Jalview
 ----------------------
 
+See
+https://issues.jalview.org/browse/JAL-1854
 http://checkstyle.sourceforge.net/
 GNU LGPL
 
@@ -9,8 +11,16 @@ To get the Eclipse Checkstyle plugin
        - Help | Eclipse Marketplace
        - search for checkstyle
        - install eclipse-cs checkstyle plugin
-The current version is 6.19.1 (August 2016).
 
+Change Log
+----------
+See http://checkstyle.sourceforge.net/releasenotes.html
+Aug 2016       Initial version used is 6.19.1
+Dec 2018       Updated to 8.12.0 (latest on Eclipse Marketplace, 8.15 is latest release)
+                       SuppressionCommentFilter relocated (changed in 8.1)
+                       FileContentsHolder removed (changed in 8.2)
+                       Updates to import-control.xml for code changes (htsjdk, stackoverflowusers)
+                       
 Config
 ------
 
@@ -37,6 +47,7 @@ How to use checkstyle
        Option 2: on demand on selected code
                - right-click on a class or package and Checkstyle | Check code with checkstyle
                - (or Clear Checkstyle violations to remove checkstyle warnings)
+               - recommended to use this as a QA step when changing or reviewing code
 
 Checkstyle rules
 ----------------
@@ -64,11 +75,11 @@ Suppressing findings
 Tips
 ----
        Sometimes checkstyle needs a kick before it will refresh its findings.
-       A whitespace edit in checkstyle.xml usually does this. There may be better ways.
+       Click the 'refresh' icon at top right in Eclipse | Preferences | Checkstyle.
        
        Invalid configuration files may result in checkstyle failing with an error reported
        in the Eclipse log file. 
-       Help | Installation Details | Configuration takes you to a screen with a 
+       Eclipse | About | Installation Details | Configuration takes you to a screen with a 
        'View Error Log' button.
        
        Sometimes checkstyle can fail silently. Try 'touching' (editing) config files, failing
index 122b8d0..29a3047 100644 (file)
@@ -26,6 +26,7 @@
     <suppress checks="[a-zA-Z0-9]*" files="[\\/]ext[\\/]edu*"/>
     <suppress checks="[a-zA-Z0-9]*" files="[\\/]ext[\\/]vamsas*"/>
     <suppress checks="[a-zA-Z0-9]*" files="[\\/]org[\\/]jibble*"/>
+    <suppress checks="[a-zA-Z0-9]*" files="[\\/]org[\\/]stackoverflowusers*"/>
     <suppress checks="[a-zA-Z0-9]*" files="[\\/]uk[\\/]ac*"/>
     
     <!-- 
index 85ac8e6..17946f7 100644 (file)
        </module>
 
        <!-- 
-               Allow suppression of rules by comments, e.g.:
-               // CHECKSTYLE.OFF: ParameterNumber
-               ..method declaration
-               // CHECKSTYLE.ON: ParameterNumber
-       -->
-       <module name="SuppressionCommentFilter">
-               <property name="offCommentFormat" value="CHECKSTYLE.OFF\: ([\w\|]+)"/>
-               <property name="onCommentFormat" value="CHECKSTYLE.ON\: ([\w\|]+)"/>
-               <property name="checkFormat" value="$1"/>
-       </module>
-
-       <!-- 
                Check language bundles have the same keys and no duplicates
                (ensure Checkstyle is configured to scan non-source files)
         -->
                <property name="tabWidth" value="4"/>
 
                <!-- 
-                       Enables parsing of suppressions comments
-                       see http://checkstyle.sourceforge.net/config_filters.html#SuppressionCommentFilter 
+                       Allow suppression of rules by comments, e.g.:
+                       // CHECKSTYLE.OFF: ParameterNumber
+                       ..method declaration
+                       // CHECKSTYLE.ON: ParameterNumber
                -->
-               <module name="FileContentsHolder"/>
+               <module name="SuppressionCommentFilter">
+                       <property name="offCommentFormat" value="CHECKSTYLE.OFF\: ([\w\|]+)"/>
+                       <property name="onCommentFormat" value="CHECKSTYLE.ON\: ([\w\|]+)"/>
+                       <property name="checkFormat" value="$1"/>
+               </module>
 
        <!-- ****************************** -->
        <!--         NAMING STANDARDS       -->
index c47aaec..478966f 100644 (file)
@@ -94,6 +94,7 @@
                <allow pkg="compbio.metadata" class="jalview.gui.WsJobParameters"/>
                <allow pkg="fr.orsay.lri.varna" class="jalview.gui.AppVarna"/>
                <allow pkg="fr.orsay.lri.varna" class="jalview.gui.AppVarnaBinding"/>
+               <allow pkg="org.stackoverflowusers.file" class="jalview.gui.Desktop"/>
                <allow pkg="uk.ac.vamsas" class="jalview.gui.VamsasApplication"/>
            </subpackage>
                
                <allow pkg="uk.ac.vamsas"/>
                <allow pkg="fr.orsay.lri.varna"/>
                <allow pkg="MCview"/>
+                       <subpackage name="vcf">
+                       <allow pkg="htsjdk\.*" regex="true"/>
+                       </subpackage>       
                </subpackage>       
                                
                <subpackage name="javascript">