From: jprocter
Date: Fri, 9 Feb 2007 18:02:18 +0000 (+0000)
Subject: This commit was manufactured by cvs2svn to create tag 'Release_2_1_1'.
X-Git-Tag: Release_2_1_1
X-Git-Url: http://source.jalview.org/gitweb/?a=commitdiff_plain;h=e059f46e77f5106185c5ebd6be7c5c31c2fbd230;p=jalview.git
This commit was manufactured by cvs2svn to create tag 'Release_2_1_1'.
Sprout from master 2006-09-12 10:01:52 UTC andrew 'Copy consensus'
Cherrypick from master 2007-02-09 18:02:17 UTC jprocter 'running jalview from the command line.':
doc/AddingGroovySupport.html
help/html/align.jpg
help/html/colourSchemes/textcolour.gif
help/html/colourSchemes/textcolour.html
help/html/features/amendfeature.gif
help/html/features/clarguments.html
help/html/features/codingfeatures.html
help/html/features/commandline.html
help/html/features/creatinFeatures.html
help/html/features/crnewfeature.gif
help/html/features/das.gif
help/html/features/editingFeatures.html
help/html/features/multipleViews.html
help/html/features/newkeystrokes.html
help/html/features/seqmappings.html
help/html/menus/alwformat.html
help/html/menus/alwselect.html
lib/vamsas-client.jar
src/jalview/analysis/Finder.java
src/jalview/appletgui/EditNameDialog.java
src/jalview/commands/ChangeCaseCommand.java
src/jalview/commands/CommandI.java
src/jalview/commands/EditCommand.java
src/jalview/commands/OrderCommand.java
src/jalview/commands/RemoveGapColCommand.java
src/jalview/commands/RemoveGapsCommand.java
src/jalview/commands/TrimRegionCommand.java
src/jalview/gui/EditNameDialog.java
src/jalview/gui/TextColourChooser.java
src/jalview/gui/UserQuestionnaireCheck.java
src/jalview/gui/VamsasClient.java
src/jalview/io/AMSAFile.java
src/jalview/io/VamsasDatastore.java
src/jalview/schemes/ScoreMatrix.java
src/jalview/util/MapList.java
src/jalview/ws/JPredThread.java
---
diff --git a/doc/AddingGroovySupport.html b/doc/AddingGroovySupport.html
new file mode 100644
index 0000000..6726612
--- /dev/null
+++ b/doc/AddingGroovySupport.html
@@ -0,0 +1,122 @@
+
+Adding Groovy Support to Jalview
+
+
+
+Adding Groovy Support to Jalview
+
+
+There is currently no scripting language
+extension within Jalview, in part because a
+scripting API has not been developed.
+
+It is, however, really easy to embed scripting
+engines within Jalview. We haven't done it
+with the Bean Scripting Framework, but the
+code snippets below show you how to get going
+with groovy.
+
+Modifications
+
+For each class below, add the following objects and methods to their definitions.
+
+-
+jalview.jbgui.GDesktop
+
+..
+protected JMenuItem groovyShell = new JMenuItem();
+..
+jbInit() {
+..
+groovyShell.setText("Groovy Shell...");
+groovyShell.addActionListener(new ActionListener()
+{
+ public void actionPerformed(ActionEvent e) {
+ groovyShell_actionPerformed(e);
+ }
+});
+..
+}
+..
+protected void groovyShell_actionPerformed(ActionEvent e)
+{
+}
+..
+
+- jalview.gui.Desktop
+
+..
+/**
+ * Accessor method to quickly get all the AlignmentFrames
+ * loaded.
+ */
+protected AlignFrame[] getAlignframes() {
+ JInternalFrame[] frames = Desktop.desktop.getAllFrames();
+
+ if (frames == null)
+ {
+ return null;
+ }
+ Vector avp=new Vector();
+ try
+ {
+ //REVERSE ORDER
+ for (int i = frames.length - 1; i > -1; i--)
+ {
+ if (frames[i] instanceof AlignFrame)
+ {
+ AlignFrame af = (AlignFrame) frames[i];
+ avp.addElement(af);
+ }
+ }
+ }
+ catch (Exception ex)
+ {
+ ex.printStackTrace();
+ }
+ if (avp.size()==0)
+ {
+ return null;
+ }
+ AlignFrame afs[] = new AlignFrame[avp.size()];
+ for (int i=0,j=avp.size(); i<j; i++) {
+ afs[i] = (AlignFrame) avp.elementAt(i);
+ }
+ avp.clear();
+ return afs;
+}
+
+/**
+ * Add Groovy Support to Jalview
+ */
+public void groovyShell_actionPerformed(ActionEvent e) {
+ Console gc = new Console();
+ gc.setVariable("Jalview", this);
+ gc.run();
+}
+..
+
+
+
+
+Finally, compile and run with the groovy-all-*.jar (get the jar
+from the embedded directory within the groovy distribution).
+Then, you should be able to open the Groovy shell
+window from the Desktop's Tools menu. To check things are working,
+try a simple test script :
+
+
+ print Jalview.getAlignframes()[0].getTitle();
+
+Executing this will print the title of the first alignment loaded into Jalview.
+
+TODO
+
+Using Java class methods from Groovy is straightforward, but currently, there isn't a set of easy to use methods for the jalview objects. A Jalview Scripting API needs to be developed to make this easier.
+Making it easier
+jalview.bin.JalviewScript could be a top level jalview instance of a script execution thread, creating and maintaining the context for scripts operating on the jalview datamodel and interfacing with the Jalview GUI.
+
+
+
+
diff --git a/help/html/align.jpg b/help/html/align.jpg
new file mode 100644
index 0000000..451ccaa
Binary files /dev/null and b/help/html/align.jpg differ
diff --git a/help/html/colourSchemes/textcolour.gif b/help/html/colourSchemes/textcolour.gif
new file mode 100644
index 0000000..a659156
Binary files /dev/null and b/help/html/colourSchemes/textcolour.gif differ
diff --git a/help/html/colourSchemes/textcolour.html b/help/html/colourSchemes/textcolour.html
new file mode 100644
index 0000000..f40116a
--- /dev/null
+++ b/help/html/colourSchemes/textcolour.html
@@ -0,0 +1,20 @@
+
+
+Background Dependent Text Colour
+
+
+Background Dependent Text Colour
+The Colour→Text Colour menu entry opens
+the "Adjust Foreground Text Colour Threshold"
+dialog box, allowing the colour of symbols rendered on dark or light
+backgrounds to be set for the current selection or the whole alignment.
+
+
+The dialog box contains a slider, and two colour icons showing
+the text colour for dark backgrounds (left hand end of slider), and
+light backgrounds (right hand end of slider). Drag the slider to change
+the threshold for transitioning between dark and light background
+colours, and select either of the colour boxes to open a colour chooser
+to select a different text colour.
+
+
diff --git a/help/html/features/amendfeature.gif b/help/html/features/amendfeature.gif
new file mode 100644
index 0000000..39cc53a
Binary files /dev/null and b/help/html/features/amendfeature.gif differ
diff --git a/help/html/features/clarguments.html b/help/html/features/clarguments.html
new file mode 100644
index 0000000..45dfab5
--- /dev/null
+++ b/help/html/features/clarguments.html
@@ -0,0 +1,82 @@
+
+Jalview Command Line Arguments
+
+
+ The Jalview Executable's Command Line
+ Arguments
+ See running Jalview from the command
+ line for more information.
+
+
+ -nodisplay |
+ Run Jalview without User Interface. |
+
+
+
+ -props FILE |
+ Use the given Jalview properties file instead
+ of users default. |
+
+
+ -features FILE |
+
+ Use the given file to add sequence features to an alignment.
+ See Features
+ File (Known as Groups file prior to 2.08) description.
+
+ |
+
+
+ -annotations FILE |
+ Add precalculated annotations to the alignment. See Annotation
+ File description. |
+
+
+ -fasta FILE |
+
+ Create alignment file FILE in Fasta format. |
+
+
+ -clustal FILE |
+ Create alignment file FILE in Clustal format. |
+
+
+ -msf FILE |
+
+ Create alignment file FILE in MSF format. |
+
+
+ -pileup FILE |
+ Create alignment file FILE in Pileup format. |
+
+
+ -pir FILE |
+
+ Create alignment file FILE in PIR format. |
+
+
+ -blc FILE |
+ Create alignment file FILE in BLC format. |
+
+
+ -jalview FILE |
+
+ Create alignment file FILE in Jalview format. |
+
+
+ -png FILE |
+ Create PNG image FILE from alignment. |
+
+
+ -imgMap FILE |
+
+ Create HTML file FILE with image map of PNG
+ image. |
+
+
+ -eps FILE |
+ Create EPS file FILE from alignment. |
+
+
+
+
diff --git a/help/html/features/codingfeatures.html b/help/html/features/codingfeatures.html
new file mode 100644
index 0000000..a828545
--- /dev/null
+++ b/help/html/features/codingfeatures.html
@@ -0,0 +1,16 @@
+
+
+DNA Sequence Coding Region Definition
+
+
+DNA Sequence Coding Region Definition
+Jalview includes the standard DNA codon translation table in
+order to be able to dynamically translate cDNA to its expressed
+protein sequence. DNA Sequence Coding Regions are sequence
+features that can be defined on any DNA sequence in order to
+mark stretches of cDNA that will be concatenated to form the
+series of codons that are translated by the "
+Calculate→Translate cDNA" menu function.
+
+
+
\ No newline at end of file
diff --git a/help/html/features/commandline.html b/help/html/features/commandline.html
new file mode 100644
index 0000000..fadddce
--- /dev/null
+++ b/help/html/features/commandline.html
@@ -0,0 +1,35 @@
+
+Running Jalview from the command line
+
+ Running Jalview from the command line
+ Jalview is most easily run from the command line if you have built
+ it from source, or via the 'Jalview' executable created from the
+ InstallAnywhere jalview installation. Both of these mechanisms allow
+ true command line execution of jalview - allowing you to provide
+ additional options.
+The Java Webstart version of
+ jalview can be executed from the command line using something like
+ :
+
javaws http://www.jalview.org/webstart/jalview.jnlp -open
+ yourFileName
+ But, this is not guaranteed to work on all versions of webstart on all
+ operating systems, and doesn't let you execute Jalview with any
+ additional parameters.
+ Running jalview from the InstallAnywhere
+ installation
+ If you install with InstallAnywhere you can use several more commands.
+ However, if you call the application with the link provided by InstallAnywhere
+ any output from the application will be sent to output.txt, not standard
+ out.
+ The jalview application also requires a number of additional
+ libraries on the class path. The command line below adds the Jalview
+ installation's 'lib' directory to the list of directories that are
+ searched for jars to be added to the classpath:
+java -Djava.ext.dirs=$INSTALL_DIR$/lib -cp $INSTALL_DIR$/jalview.jar jalview.bin.Jalview -open [FILE]
+ Use '-help' to get more information on the command line arguments that Jalview
+ accepts.
+
+
+
+
diff --git a/help/html/features/creatinFeatures.html b/help/html/features/creatinFeatures.html
new file mode 100644
index 0000000..0ebb52f
--- /dev/null
+++ b/help/html/features/creatinFeatures.html
@@ -0,0 +1,38 @@
+
+
+Creating Sequence Features
+
+
+Creating Sequence Features
+Jalview can create sequence features from the matches of a regular expression search, or from the currently
+selected area via the "selection→Create
+sequence feature" entry in the selection area popup menu. In both
+cases, the Create Features dialog box will then be
+opened:
+
+Select or enter the attributes for the features being created,
+and then press OK to create the new features.
+Each attribute is described below:
+
+ - Sequence Feature Name
+
Either give the new features a new name or use the menu to
+ re-use an existing feature name.
+
+ - Feature group
+
Enter a new group name, or re-use an existing group from the
+ pull-down menu.
+
+ - Feature Colour
+
Keep the existing colour for this feature's name and group, or
+ select the colour box to open a colour chooser to pick a different one.
+
+ - Description
+
Enter a description for all the features being created. Each
+ feature defined on a sequence may have its own description that will be
+ displayed in the tooltip for the feature in that region.
+
+
+Sequence Feature Creation was introduced in Jalview Version 2.2
+
+
\ No newline at end of file
diff --git a/help/html/features/crnewfeature.gif b/help/html/features/crnewfeature.gif
new file mode 100644
index 0000000..5aa6edb
Binary files /dev/null and b/help/html/features/crnewfeature.gif differ
diff --git a/help/html/features/das.gif b/help/html/features/das.gif
new file mode 100644
index 0000000..1f884cb
Binary files /dev/null and b/help/html/features/das.gif differ
diff --git a/help/html/features/editingFeatures.html b/help/html/features/editingFeatures.html
new file mode 100644
index 0000000..ff4d5ca
--- /dev/null
+++ b/help/html/features/editingFeatures.html
@@ -0,0 +1,26 @@
+
+
+Amending or Deleting Sequence Features
+
+
+Amending or Deleting Sequence Features
+Double clicking a position in the alignment with one or more
+displayed sequence features opens the "Amend/Delete
+Features" dialog box.
+
+The dialog box only allows one of the features at the
+double-clicked position to be edited or deleted at a time, and it will
+also be highlighted in black in the alignment window.
+Choose which feature is to be modified by selecting it from the Sequence
+Feature Name pull down
+menu. In addition to the Name, group, colour and description attributes
+described for the new feature dialog
+box, a feature's start and end position can be changed either by
+entering a new position directly or by using the adjacent up and down
+buttons.
+Select Amend to update the feature, Delete
+to remove the selected feature, or Cancel to leave the
+feature unchanged.
+Sequence feature editing was implemented in Jalview 2.2
+
+
diff --git a/help/html/features/multipleViews.html b/help/html/features/multipleViews.html
new file mode 100644
index 0000000..da811d4
--- /dev/null
+++ b/help/html/features/multipleViews.html
@@ -0,0 +1,58 @@
+
+
+Multiple Alignment Views
+
+
+Multiple Alignment Views
+Multiple alignment views allows the same alignment to be viewed
+independently in many different ways simultaneously. Each view is an
+independent visualization of the same alignment, so each may have a
+different ordering, colouring, row and column hiding and seuqence
+feature and annotation display setting, but alignment, feature and
+annotation edits are common to all, since this affects the underlying
+data.
+Create a new view using the "View→New
+View" menu item, or by pressing Control+T. A newly
+created view will be identical to the view it was created from, but any
+changes to the way the alignment is coloured or displayed will only
+affect the new view.
+A particular view may focus on some specific aspect of an
+alignment - for example, hiding all but the region of an alignment
+containing a particular domain. Right-clicking a view's
+tab opens the View Name dialog box, allowing it to be renamed to
+something more meaningful.
+Viewing Multiple Views Simultaneously
+Multiple views of an alignment are, by default, gathered together
+as tabs within a single alignment window. They can be viewed
+simultanously by pressing X (or via "View→Expand")
+to expand each view into its own linked alignment window. Expanded views
+are gathered back into into a single tabbed alignment window by pressing
+G, or by selecting "View→Gather").
+
+Hidden Sequence Representatives and Multiple
+Views
+There are some unexpected interactions between hidden sequence
+representatives and their display in multiple views. See the
+corresponding entry in the documentation
+for hidden regions.
+Structure and Analysis Viewers and Multiple
+Views
+A tree calculated on a particular view, or loaded onto it, is by
+default associated with just that view. However, the Tree Viewer's "View→Associate
+leaves" submenu allows a tree's view association to be changed to
+to any or all other views.
+The results of a PCA
+calculation on a particular view may also be associated with other
+views, using the PCA Viewer's "View→Associate
+Nodes" submenu.
+Currently, a PDB Structure Viewer
+opened on a structure associated with a sequence in a particular view
+will only be associated with the seuqence as displayed in that view.
+This will be resolved in a future release
+
Multiple Views were introduced in Jalview 2.2
+
+
diff --git a/help/html/features/newkeystrokes.html b/help/html/features/newkeystrokes.html
new file mode 100644
index 0000000..12ea967
--- /dev/null
+++ b/help/html/features/newkeystrokes.html
@@ -0,0 +1,33 @@
+
+New Key Strokes and Menus
+
+New Key Strokes and Menus
+Many new keyboard shortcuts have been
+added in Jalview 2.2 to make editing, selecting and navigating an
+alignment even easier. The selection commands in the Edit
+menu, and the alignment formatting controls within the View
+menu have also been moved into their own respective Select
+and Format menus.
+Some of the more important new keystrokes are shown below :
+
+ - Page Up and Page Down
+ scrolls through the alignment view.
+ - Control I inverts the currently selected
+ sequence set, and Control Alt I will invert the
+ currently selected set of columns.
+
- Control V will paste the contents of the
+ clipboard to the current alignment window, and Control
+ Shift V pastes the data to a new window.
+ - Control O opens the file browser for loading
+ a new alignment or Jalview archive.
+ - Control S saves the alignment with the
+ current filename and format, and Control Shift S opens
+ the Save As... dialog box.
+ - Control T creates a new alignment view, and Control
+ W closes the current view, or if none remain, then the whole alignment.
+ - Control E will remove gapped columns in the alignment.
+ - Control D opens the Remove Redundancy dialog box.
+
+
+
+
diff --git a/help/html/features/seqmappings.html b/help/html/features/seqmappings.html
new file mode 100644
index 0000000..46fcd59
--- /dev/null
+++ b/help/html/features/seqmappings.html
@@ -0,0 +1,22 @@
+
+
+Mapping Between Different Sequences
+
+
+Mapping Between Different Sequences
+A new feature in Jalview 2.8 is the ability to map
+between sequences in different domains, based on alignment,
+or by the use of explicit mappings provided by databases.
+
+The most familiar mapping is the one used to identify
+the coordinates corresponding to a displayed sequence when
+viewing a PDB file associated with a sequence (see
+"Viewing PDB Files"
+for more information.
+The newest form of mapping supported by Jalview is the
+correspondence between DNA and protein sequences. This mapping
+can be imported directly from EMBL and EMBLCDS database records
+retrieved by the Sequence Fetcher,
+or by the definition of coding regions.
+
+
\ No newline at end of file
diff --git a/help/html/menus/alwformat.html b/help/html/menus/alwformat.html
new file mode 100644
index 0000000..d7224b3
--- /dev/null
+++ b/help/html/menus/alwformat.html
@@ -0,0 +1,56 @@
+
+
+Alignment Window Format Menu
+
+ - Font...
+ Opens the "Choose Font" dialog box, in order to change the font
+ of the display and enable or disable 'smooth fonts' (anti-aliasing) for faster
+ alignment rendering.
+ - Wrap
+ When ticked, the alignment display is "wrapped" to the width of the alignment
+ window. This is useful if your alignment has only a few sequences to view
+ its full width at once.
+ Additional options for display of sequence numbering and scales are also visible
+ in wrapped layout mode:
+
+ - Scale Left
+ Show the sequence position for the first aligned residue in each row
+ in the left column of the alignment.
+ - Scale Right
+ Show the sequence position for the last aligned residue in each row
+ in the right-most column of the alignment.
+
+
+ - Scale Above
+ Show the alignment column position scale.
+ - Show Sequence Limits
+ If this box is selected the sequence name will have the start
+ and end position of the sequence appended to the name, in the format NAME/START-END
+ - Right Align Sequence ID
+ If this box is selected then the sequence names displayed in
+ the sequence label area will be aligned against the left-hand edge of the
+ alignment display, rather than the left-hand edge of the alignment window.
+ - Show Hidden Markers
+ When this box is selected, positions in the alignment where rows
+ and columns are hidden will be marked by blue arrows.
+ - Boxes
+ If this is selected the background of a residue will be coloured using the
+ selected background colour. Useful if used in conjunction with "Colour
+ Text."
+ - Text
+ If this is selected the residues will be displayed using the
+ standard 1 character amino acid alphabet.
+ - Colour Text
+ If this is selected the residues will be coloured according to
+ the background colour associated with that residue. The colour is slightly
+ darker than background so the amino acid symbol remains visible.
+ - Show Gaps
+ When this is selected, gap characters will be displayed as "."
+ or "-". If unselected, then gap characters will appear as blank
+ spaces.
+ You may set the default gap character in preferences.
+
+
+
diff --git a/help/html/menus/alwselect.html b/help/html/menus/alwselect.html
new file mode 100644
index 0000000..34438cd
--- /dev/null
+++ b/help/html/menus/alwselect.html
@@ -0,0 +1,29 @@
+
+
+Alignment Window Select Menu
+
+
+ - Find... (Control F)
+ Opens the Find dialog box to search for residues, sequence name or residue
+ position within the alignment and create new sequence features from the queries.
+
+ - Select All (Control A)
+ Selects all the sequences and residues in the alignment.
+ Use <CTRL> and A (<APPLE> and A on a MacOSX) to select all.
+ - Deselect All (Escape)
+ Removes the current selection box (red dashed box) from the
+ alignment window. All selected sequences, residues and marked columns
+ will be deselected.
+ Use <ESCAPE> to deselect all.
+ - Invert Sequence Selection (Control I)
+ Any sequence ids currently not selected will replace the
+ current selection.
+ - Invert Column Selection (Control Alt I)
+ Any columns currently not selected will replace the current
+ column selection.
+ - Undefine Groups (Control U)
+ The alignment will be reset with no defined groups.
+ WARNING: This cannot be undone.
+
+
+
diff --git a/lib/vamsas-client.jar b/lib/vamsas-client.jar
new file mode 100644
index 0000000..e0c7d95
Binary files /dev/null and b/lib/vamsas-client.jar differ
diff --git a/src/jalview/analysis/Finder.java b/src/jalview/analysis/Finder.java
new file mode 100644
index 0000000..2fa09aa
--- /dev/null
+++ b/src/jalview/analysis/Finder.java
@@ -0,0 +1,308 @@
+package jalview.analysis;
+
+import java.util.*;
+
+import jalview.datamodel.*;
+
+public class Finder
+{
+ /**
+ * Implements the search algorithms for the Find dialog box.
+ */
+ SearchResults searchResults;
+ AlignmentI alignment;
+ jalview.datamodel.SequenceGroup selection = null;
+ Vector idMatch = null;
+ boolean caseSensitive = false;
+ boolean findAll = false;
+ com.stevesoft.pat.Regex regex = null;
+ /**
+ * hold's last-searched position between calles to find(false)
+ */
+ int seqIndex = 0, resIndex = 0;
+ public Finder(AlignmentI alignment, SequenceGroup selection)
+ {
+ this.alignment = alignment;
+ this.selection = selection;
+ }
+
+ public Finder(AlignmentI alignment, SequenceGroup selectionGroup,
+ int seqIndex, int resIndex)
+ {
+ this(alignment, selectionGroup);
+ this.seqIndex = seqIndex;
+ this.resIndex = resIndex;
+ }
+
+ public boolean find(String searchString)
+ {
+ boolean hasResults = false;
+ if (!caseSensitive)
+ {
+ searchString = searchString.toUpperCase();
+ }
+ regex = new com.stevesoft.pat.Regex(searchString);
+ searchResults = new SearchResults();
+ idMatch = new Vector();
+ Sequence seq;
+ String item = null;
+ boolean found = false;
+
+ ////// is the searchString a residue number?
+ try
+ {
+ int res = Integer.parseInt(searchString);
+ found = true;
+ if (selection == null || selection.getSize() < 1)
+ {
+ seq = (Sequence) alignment.getSequenceAt(0);
+ }
+ else
+ {
+ seq = (Sequence) (selection.getSequenceAt(0));
+ }
+
+ searchResults.addResult(seq, res, res);
+ hasResults = true;
+ }
+ catch (NumberFormatException ex)
+ {
+ }
+
+ ///////////////////////////////////////////////
+
+ int end = alignment.getHeight();
+
+ if (selection != null)
+ {
+ if ( (selection.getSize() < 1) ||
+ ( (selection.getEndRes() - selection.getStartRes()) < 2))
+ {
+ selection = null;
+ }
+ }
+
+ while (!found && (seqIndex < end))
+ {
+ seq = (Sequence) alignment.getSequenceAt(seqIndex);
+
+ if ( (selection != null) && !selection.getSequences(null).contains(seq))
+ {
+ seqIndex++;
+ resIndex = 0;
+
+ continue;
+ }
+
+ item = seq.getSequenceAsString();
+ // JBPNote - check if this toUpper which is present in the application implementation makes a difference
+ //if(!caseSensitive)
+ // item = item.toUpperCase();
+
+ if ( (selection != null) &&
+ (selection.getEndRes() < alignment.getWidth() - 1))
+ {
+ item = item.substring(0, selection.getEndRes() + 1);
+ }
+
+ ///Shall we ignore gaps???? - JBPNote: Add Flag for forcing this or not
+ StringBuffer noGapsSB = new StringBuffer();
+ int insertCount = 0;
+ Vector spaces = new Vector();
+
+ for (int j = 0; j < item.length(); j++)
+ {
+ if (!jalview.util.Comparison.isGap(item.charAt(j)))
+ {
+ noGapsSB.append(item.charAt(j));
+ spaces.addElement(new Integer(insertCount));
+ }
+ else
+ {
+ insertCount++;
+ }
+ }
+
+ String noGaps = noGapsSB.toString();
+
+ for (int r = resIndex; r < noGaps.length(); r++)
+ {
+
+ if (regex.searchFrom(noGaps, r))
+ {
+ resIndex = regex.matchedFrom();
+
+ if ( (selection != null) &&
+ ( (resIndex +
+ Integer.parseInt(spaces.elementAt(resIndex).toString())) <
+ selection.getStartRes()))
+ {
+ continue;
+ }
+
+ int sres = seq.findPosition(resIndex +
+ Integer.parseInt(spaces.elementAt(
+ resIndex)
+ .toString()));
+ int eres = seq.findPosition(regex.matchedTo() - 1 +
+ Integer.parseInt(spaces.elementAt(regex.
+ matchedTo() -
+ 1).toString()));
+
+ searchResults.addResult(seq, sres, eres);
+ hasResults = true;
+ if (!findAll)
+ {
+ // thats enough, break and display the result
+ found = true;
+ resIndex++;
+
+ break;
+ }
+
+ r = resIndex;
+ }
+ else
+ {
+ break;
+ }
+ }
+
+ if (!found)
+ {
+ seqIndex++;
+ resIndex = 0;
+ }
+ }
+
+ for (int id = 0; id < alignment.getHeight(); id++)
+ {
+ if (regex.search(alignment.getSequenceAt(id).getName()))
+ {
+ idMatch.addElement(alignment.getSequenceAt(id));
+ hasResults = true;
+ }
+ }
+ return hasResults;
+ }
+
+ /**
+ * @return the alignment
+ */
+ public AlignmentI getAlignment()
+ {
+ return alignment;
+ }
+
+ /**
+ * @param alignment the alignment to set
+ */
+ public void setAlignment(AlignmentI alignment)
+ {
+ this.alignment = alignment;
+ }
+
+ /**
+ * @return the caseSensitive
+ */
+ public boolean isCaseSensitive()
+ {
+ return caseSensitive;
+ }
+
+ /**
+ * @param caseSensitive the caseSensitive to set
+ */
+ public void setCaseSensitive(boolean caseSensitive)
+ {
+ this.caseSensitive = caseSensitive;
+ }
+
+ /**
+ * @return the findAll
+ */
+ public boolean isFindAll()
+ {
+ return findAll;
+ }
+
+ /**
+ * @param findAll the findAll to set
+ */
+ public void setFindAll(boolean findAll)
+ {
+ this.findAll = findAll;
+ }
+
+ /**
+ * @return the selection
+ */
+ public jalview.datamodel.SequenceGroup getSelection()
+ {
+ return selection;
+ }
+
+ /**
+ * @param selection the selection to set
+ */
+ public void setSelection(jalview.datamodel.SequenceGroup selection)
+ {
+ this.selection = selection;
+ }
+
+ /**
+ * @return the idMatch
+ */
+ public Vector getIdMatch()
+ {
+ return idMatch;
+ }
+
+ /**
+ * @return the regex
+ */
+ public com.stevesoft.pat.Regex getRegex()
+ {
+ return regex;
+ }
+
+ /**
+ * @return the searchResults
+ */
+ public SearchResults getSearchResults()
+ {
+ return searchResults;
+ }
+
+ /**
+ * @return the resIndex
+ */
+ public int getResIndex()
+ {
+ return resIndex;
+ }
+
+ /**
+ * @param resIndex the resIndex to set
+ */
+ public void setResIndex(int resIndex)
+ {
+ this.resIndex = resIndex;
+ }
+
+ /**
+ * @return the seqIndex
+ */
+ public int getSeqIndex()
+ {
+ return seqIndex;
+ }
+
+ /**
+ * @param seqIndex the seqIndex to set
+ */
+ public void setSeqIndex(int seqIndex)
+ {
+ this.seqIndex = seqIndex;
+ }
+}
diff --git a/src/jalview/appletgui/EditNameDialog.java b/src/jalview/appletgui/EditNameDialog.java
new file mode 100644
index 0000000..3e197f0
--- /dev/null
+++ b/src/jalview/appletgui/EditNameDialog.java
@@ -0,0 +1,111 @@
+/*
+ * Jalview - A Sequence Alignment Editor and Viewer
+ * Copyright (C) 2007 AM Waterhouse, J Procter, G Barton, M Clamp, S Searle
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+package jalview.appletgui;
+
+import java.awt.*;
+import java.awt.event.*;
+
+public class EditNameDialog
+ extends Dialog implements ActionListener
+{
+ TextField id, description;
+ Button ok = new Button("Accept");
+ Button cancel = new Button("Cancel");
+ boolean accept = false;
+
+ public String getName()
+ {
+ return id.getText();
+ }
+
+ public String getDescription()
+ {
+ if (description.getText().length() < 1)
+ {
+ return null;
+ }
+ else
+ {
+ return description.getText();
+ }
+ }
+
+ public EditNameDialog(String name,
+ String desc,
+ String label1,
+ String label2,
+ AlignmentPanel ap,
+ String title)
+ {
+ super(ap.alignFrame, title, true);
+
+ id = new TextField(name, 40);
+ description = new TextField(desc, 40);
+ Panel panel = new Panel(new BorderLayout());
+ Panel panel2 = new Panel(new BorderLayout());
+ Label label = new Label(label1);
+ label.setFont(new Font("Monospaced", Font.PLAIN, 12));
+ panel2.add(label, BorderLayout.WEST);
+ panel2.add(id, BorderLayout.CENTER);
+ panel.add(panel2, BorderLayout.NORTH);
+ panel2 = new Panel(new BorderLayout());
+ label = new Label(label2);
+ label.setFont(new Font("Monospaced", Font.PLAIN, 12));
+ panel2.add(label, BorderLayout.WEST);
+ panel2.add(description, BorderLayout.CENTER);
+ panel.add(panel2, BorderLayout.CENTER);
+
+ panel2 = new Panel(new FlowLayout());
+
+ panel2.add(ok);
+ panel2.add(cancel);
+ ok.addActionListener(this);
+ cancel.addActionListener(this);
+
+ panel.add(panel2, BorderLayout.SOUTH);
+
+ add(panel, BorderLayout.NORTH);
+
+ int width = 500, height = 100;
+
+ pack();
+
+ height += getInsets().top + getInsets().bottom;
+
+ setBounds(ap.alignFrame.getBounds().x
+ + (ap.alignFrame.getSize().width - width) / 2,
+ ap.alignFrame.getBounds().y
+ + (ap.alignFrame.getSize().height - height) / 2,
+ width, height);
+
+ show();
+
+ }
+
+ public void actionPerformed(ActionEvent evt)
+ {
+ if (evt.getSource() == ok)
+ {
+ accept = true;
+ }
+
+ setVisible(false);
+ }
+}
diff --git a/src/jalview/commands/ChangeCaseCommand.java b/src/jalview/commands/ChangeCaseCommand.java
new file mode 100644
index 0000000..d34552d
--- /dev/null
+++ b/src/jalview/commands/ChangeCaseCommand.java
@@ -0,0 +1,133 @@
+/*
+ * Jalview - A Sequence Alignment Editor and Viewer
+ * Copyright (C) 2007 AM Waterhouse, J Procter, G Barton, M Clamp, S Searle
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+package jalview.commands;
+
+import jalview.datamodel.*;
+
+public class ChangeCaseCommand
+ implements CommandI
+{
+ String description;
+ public static int TO_LOWER = 0;
+ public static int TO_UPPER = 1;
+ public static int TOGGLE_CASE = 2;
+ int caseChange = -1;
+ SequenceI[] seqs;
+ int[][] regions;
+ public ChangeCaseCommand(String description,
+ SequenceI[] seqs,
+ int[][] regions,
+ int caseChange)
+ {
+ this.description = description;
+ this.seqs = seqs;
+ this.regions = regions;
+ this.caseChange = caseChange;
+ doCommand();
+ }
+
+ public String getDescription()
+ {
+ return description;
+ }
+
+ public int getSize()
+ {
+ return 1;
+ }
+
+ public void doCommand()
+ {
+ changeCase(true);
+ }
+
+ public void undoCommand()
+ {
+ changeCase(false);
+ }
+
+ void changeCase(boolean doCommand)
+ {
+ String sequence;
+ int start, end;
+ char nextChar;
+ for (int r = 0; r < regions.length; r++)
+ {
+ start = regions[r][0];
+ for (int s = 0; s < seqs.length; s++)
+ {
+ sequence = seqs[s].getSequenceAsString();
+ StringBuffer newSeq = new StringBuffer();
+
+ if (regions[r][1] > sequence.length())
+ {
+ end = sequence.length();
+ }
+ else
+ {
+ end = regions[r][1];
+ }
+
+ if (start > 0)
+ {
+ newSeq.append(sequence.substring(0, start));
+ }
+
+ if ( (caseChange == TO_UPPER && doCommand)
+ || (caseChange == TO_LOWER && !doCommand))
+ {
+ newSeq.append(sequence.substring(start, end).toUpperCase());
+ }
+
+ else if ( (caseChange == TO_LOWER && doCommand)
+ || (caseChange == TO_UPPER && !doCommand))
+ {
+ newSeq.append(sequence.substring(start, end).toLowerCase());
+ }
+
+ else //TOGGLE CASE
+ {
+ for (int c = start; c < end; c++)
+ {
+ nextChar = sequence.charAt(c);
+ if ('a' <= nextChar && nextChar <= 'z')
+ {
+ // TO UPPERCASE !!!
+ nextChar -= ('a' - 'A');
+ }
+ else if ('A' <= nextChar && nextChar <= 'Z')
+ {
+ // TO LOWERCASE !!!
+ nextChar += ('a' - 'A');
+ }
+ newSeq.append(nextChar);
+ }
+ }
+
+ if (end < sequence.length())
+ {
+ newSeq.append(sequence.substring(end));
+ }
+
+ seqs[s].setSequence(newSeq.toString());
+ }
+ }
+ }
+
+}
diff --git a/src/jalview/commands/CommandI.java b/src/jalview/commands/CommandI.java
new file mode 100644
index 0000000..d97a6bb
--- /dev/null
+++ b/src/jalview/commands/CommandI.java
@@ -0,0 +1,30 @@
+/*
+ * Jalview - A Sequence Alignment Editor and Viewer
+ * Copyright (C) 2007 AM Waterhouse, J Procter, G Barton, M Clamp, S Searle
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+package jalview.commands;
+
+public interface CommandI
+{
+ public void doCommand();
+
+ public void undoCommand();
+
+ public String getDescription();
+
+ public int getSize();
+}
diff --git a/src/jalview/commands/EditCommand.java b/src/jalview/commands/EditCommand.java
new file mode 100644
index 0000000..d0a2e03
--- /dev/null
+++ b/src/jalview/commands/EditCommand.java
@@ -0,0 +1,650 @@
+/*
+ * Jalview - A Sequence Alignment Editor and Viewer
+ * Copyright (C) 2007 AM Waterhouse, J Procter, G Barton, M Clamp, S Searle
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+package jalview.commands;
+
+import java.util.*;
+
+import jalview.datamodel.*;
+
+/**
+ *
+ * Title: EditCommmand
+ *
+ * Description: Essential information for performing
+ * undo and redo for cut/paste insert/delete gap
+ * which can be stored in the HistoryList
+ *
+ * Copyright: Copyright (c) 2006
+ *
+ * Company: Dundee University
+ *
+ * @author not attributable
+ * @version 1.0
+ */
+public class EditCommand
+ implements CommandI
+{
+ public static final int INSERT_GAP = 0;
+ public static final int DELETE_GAP = 1;
+ public static final int CUT = 2;
+ public static final int PASTE = 3;
+
+ Edit[] edits;
+
+ String description;
+
+ public EditCommand()
+ {}
+
+ public EditCommand(String description)
+ {
+ this.description = description;
+ }
+
+ public EditCommand(String description,
+ int command,
+ SequenceI[] seqs,
+ int position,
+ int number,
+ AlignmentI al)
+ {
+ this.description = description;
+ if (command == CUT || command == PASTE)
+ {
+ edits = new Edit[]
+ {
+ new Edit(command, seqs, position, number, al)};
+ }
+
+ performEdit(0);
+ }
+
+ final public String getDescription()
+ {
+ return description;
+ }
+
+ public int getSize()
+ {
+ return edits == null ? 0 : edits.length;
+ }
+
+ final public AlignmentI getAlignment()
+ {
+ return edits[0].al;
+ }
+
+ final public void appendEdit(int command,
+ SequenceI[] seqs,
+ int position,
+ int number,
+ AlignmentI al,
+ boolean performEdit)
+ {
+ Edit edit = new Edit(command, seqs, position, number, al.getGapCharacter());
+ if (al.getHeight() == seqs.length)
+ {
+ edit.al = al;
+ edit.fullAlignmentHeight = true;
+ }
+
+ if (edits != null)
+ {
+ Edit[] temp = new Edit[edits.length + 1];
+ System.arraycopy(edits, 0, temp, 0, edits.length);
+ edits = temp;
+ edits[edits.length - 1] = edit;
+ }
+ else
+ {
+ edits = new Edit[]
+ {
+ edit};
+ }
+
+ if (performEdit)
+ {
+ performEdit(edits.length - 1);
+ }
+ }
+
+ final void performEdit(int commandIndex)
+ {
+ int eSize = edits.length;
+ for (int e = commandIndex; e < eSize; e++)
+ {
+ if (edits[e].command == INSERT_GAP)
+ {
+ insertGap(edits[e]);
+ }
+ else if (edits[e].command == DELETE_GAP)
+ {
+ deleteGap(edits[e]);
+ }
+ else if (edits[e].command == CUT)
+ {
+ cut(edits[e]);
+ }
+ else if (edits[e].command == PASTE)
+ {
+ paste(edits[e]);
+ }
+ }
+ }
+
+ final public void doCommand()
+ {
+ performEdit(0);
+ }
+
+ final public void undoCommand()
+ {
+ int e = 0, eSize = edits.length;
+ for (e = eSize - 1; e > -1; e--)
+ {
+ if (edits[e].command == INSERT_GAP)
+ {
+ deleteGap(edits[e]);
+ }
+ else if (edits[e].command == DELETE_GAP)
+ {
+ insertGap(edits[e]);
+ }
+ else if (edits[e].command == CUT)
+ {
+ paste(edits[e]);
+ }
+ else if (edits[e].command == PASTE)
+ {
+ cut(edits[e]);
+ }
+ }
+ }
+
+ final void insertGap(Edit command)
+ {
+ for (int s = 0; s < command.seqs.length; s++)
+ {
+ command.seqs[s].insertCharAt(command.position,
+ command.number,
+ command.gapChar);
+ }
+
+ adjustAnnotations(command, true);
+ }
+
+ final void deleteGap(Edit command)
+ {
+ for (int s = 0; s < command.seqs.length; s++)
+ {
+ command.seqs[s].deleteChars(command.position,
+ command.position + command.number);
+ }
+
+ adjustAnnotations(command, false);
+ }
+
+ void cut(Edit command)
+ {
+ command.string = new char[command.seqs.length][];
+
+ for (int i = 0; i < command.seqs.length; i++)
+ {
+ if (command.seqs[i].getLength() > command.position)
+ {
+ command.string[i] = command.seqs[i].getSequence(command.position,
+ command.position + command.number);
+
+ if (command.seqs[i].getDatasetSequence() != null
+ || command.seqs[i].getSequenceFeatures() != null)
+ {
+ for (int s = command.position; s < command.position + command.number;
+ s++)
+ {
+ if (jalview.schemes.ResidueProperties
+ .aaIndex[command.seqs[i].getCharAt(s)] != 23)
+ {
+ adjustFeatures(command, i,
+ command.seqs[i].findPosition(command.position),
+ command.seqs[i].findPosition(command.position +
+ command.number),
+ false);
+ break;
+ }
+ }
+ }
+ command.seqs[i].deleteChars(command.position,
+ command.position + command.number);
+ }
+
+ if (command.seqs[i].getLength() < 1)
+ {
+ command.al.deleteSequence(command.seqs[i]);
+ }
+ }
+
+ adjustAnnotations(command, false);
+ }
+
+ void paste(Edit command)
+ {
+ StringBuffer tmp;
+ boolean newDSNeeded;
+ int start = 0, end = 0;
+
+ for (int i = 0; i < command.seqs.length; i++)
+ {
+ newDSNeeded = false;
+ if (command.seqs[i].getLength() < 1)
+ {
+ // ie this sequence was deleted, we need to
+ // read it to the alignment
+ if (command.alIndex[i] < command.al.getHeight())
+ {
+ command.al.getSequences().insertElementAt(command.seqs[i],
+ command.alIndex[i]);
+ }
+ else
+ {
+ command.al.addSequence(command.seqs[i]);
+ }
+ }
+ tmp = new StringBuffer();
+ tmp.append(command.seqs[i].getSequence());
+
+ 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)
+ {
+ tmp.append(command.gapChar);
+ length--;
+ }
+ }
+ 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)
+ {
+ newDSNeeded = true;
+ start = command.seqs[i].findPosition(command.position);
+ end = command.seqs[i].findPosition(command.position +
+ command.number);
+ break;
+ }
+ }
+ command.string[i] = null;
+ }
+
+ command.seqs[i].setSequence(tmp.toString());
+
+ if (newDSNeeded)
+ {
+ if (command.seqs[i].getDatasetSequence() != null)
+ {
+ Sequence 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());
+ command.seqs[i].setDatasetSequence(ds);
+ }
+
+ adjustFeatures(command, i, start, end, true);
+ }
+ }
+
+ adjustAnnotations(command, true);
+
+ command.string = null;
+ }
+
+ final void adjustAnnotations(Edit command, boolean insert)
+ {
+
+ AlignmentAnnotation[] annotations = null;
+
+ if (command.fullAlignmentHeight)
+ {
+ annotations = command.al.getAlignmentAnnotation();
+ }
+ else
+ {
+ int aSize = 0;
+ AlignmentAnnotation[] tmp;
+ for (int s = 0; s < command.seqs.length; s++)
+ {
+ if (command.seqs[s].getAnnotation() == null)
+ {
+ continue;
+ }
+
+ if (aSize == 0)
+ {
+ annotations = command.seqs[s].getAnnotation();
+ }
+ else
+ {
+ tmp = new AlignmentAnnotation
+ [aSize + command.seqs[s].getAnnotation().length];
+
+ System.arraycopy(annotations, 0, tmp, 0, aSize);
+
+ System.arraycopy(command.seqs[s].getAnnotation(),
+ 0, tmp, aSize,
+ command.seqs[s].getAnnotation().length);
+
+ annotations = tmp;
+ }
+
+ aSize = annotations.length;
+ }
+ }
+
+ if (annotations == null)
+ {
+ return;
+ }
+
+ if (!insert)
+ {
+ command.deletedAnnotations = new Hashtable();
+ }
+
+ int aSize;
+ Annotation[] temp;
+ for (int a = 0; a < annotations.length; a++)
+ {
+ if (annotations[a].autoCalculated)
+ {
+ continue;
+ }
+
+ int tSize = 0;
+
+ aSize = annotations[a].annotations.length;
+ if (insert)
+ {
+ temp = new Annotation[aSize + command.number];
+ }
+ else
+ {
+ if (command.position < aSize)
+ {
+ if (command.position + command.number > aSize)
+ {
+ tSize = aSize;
+ }
+ else
+ {
+ tSize = aSize - command.number + command.position;
+ }
+ }
+ else
+ {
+ tSize = aSize;
+ }
+
+ if (tSize < 0)
+ {
+ tSize = aSize;
+ }
+ temp = new Annotation[tSize];
+
+ }
+
+ if (insert)
+ {
+ if (command.position < annotations[a].annotations.length)
+ {
+ System.arraycopy(annotations[a].annotations,
+ 0, temp, 0, command.position);
+
+ if (command.deletedAnnotations != null
+ &&
+ command.deletedAnnotations.containsKey(annotations[a].
+ annotationId))
+ {
+ Annotation[] restore = (Annotation[])
+ command.deletedAnnotations.get(annotations[a].annotationId);
+
+ System.arraycopy(restore,
+ 0,
+ temp,
+ command.position,
+ command.number);
+
+ }
+
+ System.arraycopy(annotations[a].annotations,
+ command.position, temp,
+ command.position + command.number,
+ aSize - command.position);
+ }
+ else
+ {
+ if (command.deletedAnnotations != null
+ &&
+ command.deletedAnnotations.containsKey(annotations[a].
+ annotationId))
+ {
+ Annotation[] restore = (Annotation[])
+ command.deletedAnnotations.get(annotations[a].annotationId);
+
+ temp = new Annotation[annotations[a].annotations.length +
+ restore.length];
+ System.arraycopy(annotations[a].annotations,
+ 0, temp, 0,
+ annotations[a].annotations.length);
+ System.arraycopy(restore, 0, temp,
+ annotations[a].annotations.length, restore.length);
+ }
+ else
+ {
+ temp = annotations[a].annotations;
+ }
+ }
+ }
+ else
+ {
+ if (tSize != aSize || command.position < 2)
+ {
+ System.arraycopy(annotations[a].annotations,
+ 0, temp, 0, command.position);
+
+ Annotation[] deleted = new Annotation[command.number];
+ System.arraycopy(annotations[a].annotations,
+ command.position, deleted, 0, command.number);
+
+ command.deletedAnnotations.put(annotations[a].annotationId,
+ deleted);
+
+ System.arraycopy(annotations[a].annotations,
+ command.position + command.number,
+ temp, command.position,
+ aSize - command.position - command.number);
+ }
+ else
+ {
+ int dSize = aSize - command.position;
+
+ if (dSize > 0)
+ {
+ Annotation[] deleted = new Annotation[command.number];
+ System.arraycopy(annotations[a].annotations,
+ command.position, deleted, 0, dSize);
+
+ command.deletedAnnotations.put(annotations[a].annotationId,
+ deleted);
+
+ tSize = Math.min(annotations[a].annotations.length,
+ command.position);
+ temp = new Annotation[tSize];
+ System.arraycopy(annotations[a].annotations,
+ 0, temp, 0, tSize);
+ }
+ else
+ {
+ temp = annotations[a].annotations;
+ }
+ }
+ }
+
+ annotations[a].annotations = temp;
+ }
+ }
+
+ final void adjustFeatures(Edit command, int index, int i, int j,
+ boolean insert)
+ {
+ SequenceI seq = command.seqs[index];
+ SequenceI sequence = seq.getDatasetSequence();
+ if (sequence == null)
+ {
+ sequence = seq;
+ }
+
+ if (insert)
+ {
+ if (command.editedFeatures != null
+ && command.editedFeatures.containsKey(seq))
+ {
+ sequence.setSequenceFeatures(
+ (SequenceFeature[]) command.editedFeatures.get(seq)
+ );
+ }
+
+ return;
+ }
+
+ SequenceFeature[] sf = sequence.getSequenceFeatures();
+
+ if (sf == null)
+ {
+ return;
+ }
+
+ SequenceFeature[] oldsf = new SequenceFeature[sf.length];
+
+ int cSize = j - i;
+
+ for (int s = 0; s < sf.length; s++)
+ {
+ SequenceFeature copy = new SequenceFeature(sf[s]);
+
+ oldsf[s] = copy;
+
+ if (sf[s].getEnd() < i)
+ {
+ continue;
+ }
+
+ if (sf[s].getBegin() > j)
+ {
+ sf[s].setBegin(copy.getBegin() - cSize);
+ sf[s].setEnd(copy.getEnd() - cSize);
+ continue;
+ }
+
+ if (sf[s].getBegin() >= i)
+ {
+ sf[s].setBegin(i);
+ }
+
+ if (sf[s].getEnd() < j)
+ {
+ sf[s].setEnd(j - 1);
+ }
+
+ sf[s].setEnd(sf[s].getEnd() - (cSize));
+
+ if (sf[s].getBegin() > sf[s].getEnd())
+ {
+ sequence.deleteFeature(sf[s]);
+ }
+ }
+
+ if (command.editedFeatures == null)
+ {
+ command.editedFeatures = new Hashtable();
+ }
+
+ command.editedFeatures.put(seq, oldsf);
+
+ }
+
+ class Edit
+ {
+ boolean fullAlignmentHeight = false;
+ Hashtable deletedAnnotations;
+ Hashtable editedFeatures;
+ AlignmentI al;
+ int command;
+ char[][] string;
+ SequenceI[] seqs;
+ int[] alIndex;
+ int position, number;
+ char gapChar;
+
+ Edit(int command,
+ SequenceI[] seqs,
+ int position,
+ int number,
+ char gapChar)
+ {
+ this.command = command;
+ this.seqs = seqs;
+ this.position = position;
+ this.number = number;
+ this.gapChar = gapChar;
+ }
+
+ Edit(int command,
+ SequenceI[] seqs,
+ int position,
+ int number,
+ AlignmentI al)
+ {
+ this.gapChar = al.getGapCharacter();
+ this.command = command;
+ this.seqs = seqs;
+ this.position = position;
+ this.number = number;
+ this.al = al;
+
+ alIndex = new int[seqs.length];
+ for (int i = 0; i < seqs.length; i++)
+ {
+ alIndex[i] = al.findIndex(seqs[i]);
+ }
+
+ fullAlignmentHeight = (al.getHeight() == seqs.length);
+ }
+ }
+
+}
diff --git a/src/jalview/commands/OrderCommand.java b/src/jalview/commands/OrderCommand.java
new file mode 100644
index 0000000..57097c0
--- /dev/null
+++ b/src/jalview/commands/OrderCommand.java
@@ -0,0 +1,62 @@
+/*
+ * Jalview - A Sequence Alignment Editor and Viewer
+ * Copyright (C) 2007 AM Waterhouse, J Procter, G Barton, M Clamp, S Searle
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+package jalview.commands;
+
+import jalview.analysis.*;
+import jalview.datamodel.*;
+
+public class OrderCommand
+ implements CommandI
+{
+ String description;
+ SequenceI[] seqs;
+ SequenceI[] seqs2;
+ AlignmentI al;
+
+ public OrderCommand(String description,
+ SequenceI[] seqs,
+ AlignmentI al)
+ {
+ this.description = description;
+ this.seqs = seqs;
+ this.seqs2 = al.getSequencesArray();
+ this.al = al;
+ doCommand();
+ }
+
+ public String getDescription()
+ {
+ return description;
+ }
+
+ public int getSize()
+ {
+ return 1;
+ }
+
+ public void doCommand()
+ {
+ AlignmentSorter.setOrder(al, seqs2);
+ }
+
+ public void undoCommand()
+ {
+ AlignmentSorter.setOrder(al, seqs);
+ }
+}
diff --git a/src/jalview/commands/RemoveGapColCommand.java b/src/jalview/commands/RemoveGapColCommand.java
new file mode 100644
index 0000000..1e9b832
--- /dev/null
+++ b/src/jalview/commands/RemoveGapColCommand.java
@@ -0,0 +1,106 @@
+package jalview.commands;
+
+/*
+ * Jalview - A Sequence Alignment Editor and Viewer
+ * Copyright (C) 2007 AM Waterhouse, J Procter, G Barton, M Clamp, S Searle
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+import jalview.datamodel.*;
+
+public class RemoveGapColCommand
+ extends EditCommand
+{
+ int columnsDeleted;
+ public RemoveGapColCommand(String description,
+ SequenceI[] seqs,
+ int start, int end, AlignmentI al)
+ {
+ this.description = description;
+
+ int j, jSize = seqs.length;
+
+ int startCol = -1, endCol = -1;
+ columnsDeleted = 0;
+
+ edits = new Edit[0];
+
+ boolean delete = true;
+ for (int i = start; i <= end; i++)
+ {
+ delete = true;
+
+ for (j = 0; j < jSize; j++)
+ {
+ if (seqs[j].getLength() > i)
+ {
+ if (!jalview.util.Comparison.isGap(seqs[j].getCharAt(i)))
+ {
+ if (delete)
+ {
+ endCol = i;
+ }
+
+ delete = false;
+ break;
+ }
+ }
+ }
+
+ if (delete && startCol == -1)
+ {
+ startCol = i;
+ }
+
+ if (!delete && startCol > -1)
+ {
+ this.appendEdit(DELETE_GAP, seqs,
+ startCol - columnsDeleted,
+ endCol - startCol,
+ al,
+ false);
+
+ columnsDeleted += (endCol - startCol);
+ startCol = -1;
+ endCol = -1;
+ }
+ }
+
+ if (delete && startCol > -1)
+ {
+ //This is for empty columns at the
+ //end of the alignment
+
+ this.appendEdit(DELETE_GAP, seqs,
+ startCol - columnsDeleted,
+ end - startCol + 1,
+ al,
+ false);
+
+ columnsDeleted += (end - startCol + 1);
+ }
+
+ performEdit(0);
+ }
+
+ public int getSize()
+ {
+ //We're interested in the number of columns deleted,
+ //Not the number of sequence edits.
+ return columnsDeleted;
+ }
+
+}
diff --git a/src/jalview/commands/RemoveGapsCommand.java b/src/jalview/commands/RemoveGapsCommand.java
new file mode 100644
index 0000000..ccc8008
--- /dev/null
+++ b/src/jalview/commands/RemoveGapsCommand.java
@@ -0,0 +1,120 @@
+package jalview.commands;
+
+/*
+ * Jalview - A Sequence Alignment Editor and Viewer
+ * Copyright (C) 2007 AM Waterhouse, J Procter, G Barton, M Clamp, S Searle
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+import jalview.datamodel.*;
+
+public class RemoveGapsCommand
+ extends EditCommand
+{
+ public RemoveGapsCommand(String description,
+ SequenceI[] seqs, AlignmentI al)
+ {
+ this.description = description;
+ int width = 0;
+ for (int i = 0; i < seqs.length; i++)
+ {
+ if (seqs[i].getLength() > width)
+ {
+ width = seqs[i].getLength();
+ }
+ }
+
+ findGaps(seqs, 0, width, al);
+ }
+
+ public RemoveGapsCommand(String description,
+ SequenceI[] seqs,
+ int start, int end, AlignmentI al)
+ {
+ this.description = description;
+ findGaps(seqs, start, end, al);
+ }
+
+ void findGaps(SequenceI[] seqs, int start, int end, AlignmentI al)
+ {
+
+ int startCol = -1, endCol = -1;
+ int deletedCols = 0;
+
+ int j, jSize;
+
+ edits = new Edit[0];
+
+ boolean delete = true;
+ char[] sequence;
+
+ for (int s = 0; s < seqs.length; s++)
+ {
+ deletedCols = 0;
+ startCol = -1;
+ endCol = -1;
+ sequence = seqs[s].getSequence(start, end + 1);
+
+ jSize = sequence.length;
+ for (j = 0; j < jSize; j++)
+ {
+ delete = true;
+
+ if (!jalview.util.Comparison.isGap(sequence[j]))
+ {
+ if (delete)
+ {
+ endCol = j;
+ }
+
+ delete = false;
+ }
+
+ if (delete && startCol == -1)
+ {
+ startCol = j;
+ }
+
+ if (!delete && startCol > -1)
+ {
+ this.appendEdit(DELETE_GAP, new SequenceI[]
+ {seqs[s]},
+ start + startCol - deletedCols,
+ endCol - startCol,
+ al,
+ false);
+
+ deletedCols += (endCol - startCol);
+ startCol = -1;
+ endCol = -1;
+ }
+ }
+ if (delete && startCol > -1)
+ {
+ this.appendEdit(DELETE_GAP, new SequenceI[]
+ {seqs[s]},
+ start + startCol - deletedCols,
+ jSize - startCol,
+ al,
+ false);
+ }
+
+ }
+
+ performEdit(0);
+ }
+
+}
diff --git a/src/jalview/commands/TrimRegionCommand.java b/src/jalview/commands/TrimRegionCommand.java
new file mode 100644
index 0000000..4c1dea0
--- /dev/null
+++ b/src/jalview/commands/TrimRegionCommand.java
@@ -0,0 +1,178 @@
+/*
+ * Jalview - A Sequence Alignment Editor and Viewer
+ * Copyright (C) 2007 AM Waterhouse, J Procter, G Barton, M Clamp, S Searle
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+package jalview.commands;
+
+import java.util.*;
+
+import jalview.datamodel.*;
+import jalview.util.*;
+
+public class TrimRegionCommand
+ extends EditCommand
+{
+ public static String TRIM_LEFT = "TrimLeft";
+ public static String TRIM_RIGHT = "TrimRight";
+
+ public ColumnSelection colSel = null;
+
+ int[] start;
+
+ ShiftList shiftList;
+
+ SequenceGroup selectionGroup;
+
+ Vector deletedHiddenColumns;
+
+ int columnsDeleted;
+
+ public TrimRegionCommand(String description,
+ String command,
+ SequenceI[] seqs,
+ int column,
+ AlignmentI al,
+ ColumnSelection colSel,
+ SequenceGroup selectedRegion)
+ {
+ this.description = description;
+ this.selectionGroup = selectedRegion;
+ this.colSel = colSel;
+ if (command.equalsIgnoreCase(TRIM_LEFT))
+ {
+ if (column == 0)
+ {
+ return;
+ }
+
+ columnsDeleted = column;
+
+ edits = new Edit[]
+ {
+ new Edit(CUT, seqs, 0, column, al)};
+ }
+ else if (command.equalsIgnoreCase(TRIM_RIGHT))
+ {
+ int width = al.getWidth() - column - 1;
+ if (width < 2)
+ {
+ return;
+ }
+
+ columnsDeleted = width - 1;
+
+ edits = new Edit[]
+ {
+ new Edit(CUT, seqs, column + 1, width, al)};
+ }
+
+ //We need to keep a record of the sequence start
+ //in order to restore the state after a redo
+ int i, isize = edits[0].seqs.length;
+ start = new int[isize];
+ for (i = 0; i < isize; i++)
+ {
+ start[i] = edits[0].seqs[i].getStart();
+ }
+
+ performEdit(0);
+ }
+
+ void cut(Edit command)
+ {
+ int column, j, jSize = command.seqs.length;
+ for (j = 0; j < jSize; j++)
+ {
+ if (command.position == 0)
+ {
+ //This is a TRIM_LEFT command
+ column = command.seqs[j].findPosition(command.number);
+ command.seqs[j].setStart(column);
+ }
+ else
+ {
+ //This is a TRIM_RIGHT command
+ column = command.seqs[j].findPosition(command.position) - 1;
+ command.seqs[j].setEnd(column);
+ }
+ }
+
+ super.cut(command);
+
+ if (command.position == 0)
+ {
+ deletedHiddenColumns = colSel.compensateForEdit(0, command.number);
+ if (selectionGroup != null)
+ {
+ selectionGroup.adjustForRemoveLeft(command.number);
+ }
+ }
+ else
+ {
+ deletedHiddenColumns = colSel.compensateForEdit(command.position,
+ command.number);
+ if (selectionGroup != null)
+ {
+ selectionGroup.adjustForRemoveRight(command.position);
+ }
+ }
+ }
+
+ void paste(Edit command)
+ {
+ super.paste(command);
+ int column, j, jSize = command.seqs.length;
+ for (j = 0; j < jSize; j++)
+ {
+ if (command.position == 0)
+ {
+ command.seqs[j].setStart(start[j]);
+ }
+ else
+ {
+ column = command.seqs[j]
+ .findPosition(command.number + command.position) - 1;
+ command.seqs[j].setEnd(column);
+ }
+ }
+
+ if (command.position == 0)
+ {
+ colSel.compensateForEdit(0, -command.number);
+ if (selectionGroup != null)
+ {
+ selectionGroup.adjustForRemoveLeft( -command.number);
+ }
+ }
+
+ if (deletedHiddenColumns != null)
+ {
+ int[] region;
+ for (int i = 0; i < deletedHiddenColumns.size(); i++)
+ {
+ region = (int[]) deletedHiddenColumns.elementAt(i);
+ colSel.hideColumns(region[0], region[1]);
+ }
+ }
+ }
+
+ public int getSize()
+ {
+ return columnsDeleted;
+ }
+
+}
diff --git a/src/jalview/gui/EditNameDialog.java b/src/jalview/gui/EditNameDialog.java
new file mode 100644
index 0000000..b6cc5a5
--- /dev/null
+++ b/src/jalview/gui/EditNameDialog.java
@@ -0,0 +1,80 @@
+/*
+ * Jalview - A Sequence Alignment Editor and Viewer
+ * Copyright (C) 2007 AM Waterhouse, J Procter, G Barton, M Clamp, S Searle
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+package jalview.gui;
+
+import java.awt.*;
+import javax.swing.*;
+
+public class EditNameDialog
+{
+ JTextField id, description;
+ JButton ok = new JButton("Accept");
+ JButton cancel = new JButton("Cancel");
+ boolean accept = false;
+
+ public String getName()
+ {
+ return id.getText();
+ }
+
+ public String getDescription()
+ {
+ if (description.getText().length() < 1)
+ {
+ return null;
+ }
+ else
+ {
+ return description.getText();
+ }
+ }
+
+ public EditNameDialog(String name,
+ String desc,
+ String label1,
+ String label2,
+ String title)
+ {
+ JLabel idlabel = new JLabel(label1);
+ JLabel desclabel = new JLabel(label2);
+ idlabel.setFont(new Font("Courier", Font.PLAIN, 12));
+ desclabel.setFont(new Font("Courier", Font.PLAIN, 12));
+ id = new JTextField(name, 40);
+ description = new JTextField(desc, 40);
+ JPanel panel = new JPanel(new BorderLayout());
+ JPanel panel2 = new JPanel(new BorderLayout());
+ panel2.add(idlabel, BorderLayout.WEST);
+ panel2.add(id, BorderLayout.CENTER);
+ panel.add(panel2, BorderLayout.NORTH);
+ panel2 = new JPanel(new BorderLayout());
+ panel2.add(desclabel, BorderLayout.WEST);
+ panel2.add(description, BorderLayout.CENTER);
+ panel.add(panel2, BorderLayout.SOUTH);
+
+ int reply = JOptionPane.showInternalConfirmDialog(Desktop.desktop,
+ panel, title,
+ JOptionPane.OK_CANCEL_OPTION);
+
+ if (reply == JOptionPane.OK_OPTION)
+ {
+ accept = true;
+ }
+ }
+}
diff --git a/src/jalview/gui/TextColourChooser.java b/src/jalview/gui/TextColourChooser.java
new file mode 100644
index 0000000..504e1d5
--- /dev/null
+++ b/src/jalview/gui/TextColourChooser.java
@@ -0,0 +1,213 @@
+/*
+ * Jalview - A Sequence Alignment Editor and Viewer
+ * Copyright (C) 2007 AM Waterhouse, J Procter, G Barton, M Clamp, S Searle
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+package jalview.gui;
+
+import java.util.*;
+
+import java.awt.*;
+import java.awt.event.*;
+import javax.swing.*;
+import javax.swing.event.*;
+
+import jalview.datamodel.*;
+
+public class TextColourChooser
+{
+ AlignmentPanel ap;
+ SequenceGroup sg;
+
+ public void chooseColour(AlignmentPanel ap, SequenceGroup sg)
+ {
+ this.ap = ap;
+ this.sg = sg;
+
+ int original1, original2, originalThreshold;
+ if (sg == null)
+ {
+ original1 = ap.av.textColour.getRGB();
+ original2 = ap.av.textColour2.getRGB();
+ originalThreshold = ap.av.thresholdTextColour;
+ }
+ else
+ {
+ original1 = sg.textColour.getRGB();
+ original2 = sg.textColour2.getRGB();
+ originalThreshold = sg.thresholdTextColour;
+ }
+
+ final JSlider slider = new JSlider(0, 750, originalThreshold);
+ final JPanel col1 = new JPanel();
+ col1.setPreferredSize(new Dimension(40, 20));
+ col1.setBorder(BorderFactory.createEtchedBorder());
+ col1.setToolTipText("Dark Colour");
+ col1.setBackground(new Color(original1));
+ final JPanel col2 = new JPanel();
+ col2.setPreferredSize(new Dimension(40, 20));
+ col2.setBorder(BorderFactory.createEtchedBorder());
+ col2.setToolTipText("Light Colour");
+ col2.setBackground(new Color(original2));
+ final JPanel bigpanel = new JPanel(new BorderLayout());
+ JPanel panel = new JPanel();
+ bigpanel.add(panel, BorderLayout.CENTER);
+ bigpanel.add(new JLabel(
+ "Select a dark and light text colour, then set the threshold to"
+ + "
switch between colours, based on background colour"),
+ BorderLayout.NORTH);
+ panel.add(col1);
+ panel.add(slider);
+ panel.add(col2);
+
+ col1.addMouseListener(new MouseAdapter()
+ {
+ public void mousePressed(MouseEvent e)
+ {
+ Color col = JColorChooser.showDialog(bigpanel,
+ "Select Colour for Text",
+ col1.getBackground());
+ if (col != null)
+ {
+ colour1Changed(col);
+ col1.setBackground(col);
+ }
+ }
+ });
+
+ col2.addMouseListener(new MouseAdapter()
+ {
+ public void mousePressed(MouseEvent e)
+ {
+ Color col = JColorChooser.showDialog(bigpanel,
+ "Select Colour for Text",
+ col2.getBackground());
+ if (col != null)
+ {
+ colour2Changed(col);
+ col2.setBackground(col);
+ }
+ }
+ });
+
+ slider.addChangeListener(new ChangeListener()
+ {
+ public void stateChanged(ChangeEvent evt)
+ {
+ thresholdChanged(slider.getValue());
+ }
+ });
+
+ int reply = JOptionPane.showInternalOptionDialog(
+ ap,
+ bigpanel,
+ "Adjust Foreground Text Colour Threshold",
+ JOptionPane.OK_CANCEL_OPTION,
+ JOptionPane.QUESTION_MESSAGE,
+ null,
+ null, null);
+
+ if (reply == JOptionPane.CANCEL_OPTION)
+ {
+ if (sg == null)
+ {
+ ap.av.textColour = new Color(original1);
+ ap.av.textColour2 = new Color(original2);
+ ap.av.thresholdTextColour = originalThreshold;
+ }
+ else
+ {
+ sg.textColour = new Color(original1);
+ sg.textColour2 = new Color(original2);
+ sg.thresholdTextColour = originalThreshold;
+ }
+ }
+ }
+
+ void colour1Changed(Color col)
+ {
+ if (sg == null)
+ {
+ ap.av.textColour = col;
+ if (ap.av.colourAppliesToAllGroups)
+ {
+ setGroupTextColour();
+ }
+ }
+ else
+ {
+ sg.textColour = col;
+ }
+
+ ap.repaint();
+ }
+
+ void colour2Changed(Color col)
+ {
+ if (sg == null)
+ {
+ ap.av.textColour2 = col;
+ if (ap.av.colourAppliesToAllGroups)
+ {
+ setGroupTextColour();
+ }
+ }
+ else
+ {
+ sg.textColour2 = col;
+ }
+
+ ap.repaint();
+ }
+
+ void thresholdChanged(int value)
+ {
+ if (sg == null)
+ {
+ ap.av.thresholdTextColour = value;
+ if (ap.av.colourAppliesToAllGroups)
+ {
+ setGroupTextColour();
+ }
+ }
+ else
+ {
+ sg.thresholdTextColour = value;
+ }
+
+ ap.repaint();
+ }
+
+ void setGroupTextColour()
+ {
+ if (ap.av.alignment.getGroups() == null)
+ {
+ return;
+ }
+
+ Vector groups = ap.av.alignment.getGroups();
+
+ for (int i = 0; i < groups.size(); i++)
+ {
+ SequenceGroup sg = (SequenceGroup) groups.elementAt(i);
+ sg.textColour = ap.av.textColour;
+ sg.textColour2 = ap.av.textColour2;
+ sg.thresholdTextColour = ap.av.thresholdTextColour;
+ }
+ }
+
+}
diff --git a/src/jalview/gui/UserQuestionnaireCheck.java b/src/jalview/gui/UserQuestionnaireCheck.java
new file mode 100644
index 0000000..0accc9c
--- /dev/null
+++ b/src/jalview/gui/UserQuestionnaireCheck.java
@@ -0,0 +1,140 @@
+package jalview.gui;
+
+import java.io.*;
+import java.net.*;
+
+import javax.swing.*;
+
+public class UserQuestionnaireCheck
+ implements Runnable
+{
+ /**
+ * Implements the client side machinery for detecting a new questionnaire,
+ * checking if the user has responded to an existing one,
+ * and prompting the user for responding to a questionnaire.
+ * This is intended to work with the perl CGI scripts checkresponder.pl and
+ * questionnaire.pl
+ */
+ String url = null;
+ UserQuestionnaireCheck(String url)
+ {
+ if (url.indexOf("questionnaire.pl") == -1)
+ {
+ jalview.bin.Cache.log.error("'" + url +
+ "' is an Invalid URL for the checkForQuestionnaire() method.\n"
+ + "This argument is only for questionnaires derived from jalview's questionnaire.pl cgi interface.");
+ }
+ else
+ {
+ this.url = url;
+ }
+ }
+
+ String qid = null, rid = null;
+ private boolean checkresponse(URL qurl)
+ throws Exception
+ {
+ jalview.bin.Cache.log.debug("Checking Response for : " + qurl);
+ boolean prompt = false;
+ // see if we have already responsed to this questionnaire or get a new qid/rid pair
+ BufferedReader br = new BufferedReader(new InputStreamReader(qurl.
+ openStream()));
+ String qresp;
+ while ( (qresp = br.readLine()) != null)
+ {
+ if (qresp.indexOf("NOTYET:") == 0)
+ {
+ prompt = true; // not yet responded under that ID
+ }
+ else
+ {
+ if (qresp.indexOf("QUESTIONNAIRE:") == 0)
+ {
+ // QUESTIONNAIRE:qid:rid for the latest questionnaire.
+ int p = qresp.indexOf(':', 14);
+ if (p > -1)
+ {
+ rid = null;
+ qid = qresp.substring(14, p);
+ if (p < (qresp.length() - 1))
+ {
+ rid = qresp.substring(p + 1);
+ prompt = true; // this is a new qid/rid pair
+ }
+ }
+ }
+ }
+ }
+ return prompt;
+ }
+
+ public void run()
+ {
+ if (url == null)
+ {
+ return;
+ }
+ boolean prompt = false;
+ try
+ {
+ // First - check to see if wee have an old questionnaire/response id pair.
+ String lastq = jalview.bin.Cache.getProperty("QUESTIONNAIRE");
+ if (lastq == null)
+ {
+ prompt = checkresponse(new URL(url + (url.indexOf('?') > -1 ? "&" : "?") +
+ "checkresponse=1"));
+ }
+ else
+ {
+ String qurl = url + (url.indexOf('?') > -1 ? "&" : "?") +
+ "checkresponse=1";
+ // query the server with the old qid/id pair
+ String qqid = lastq.indexOf(':') > -1 ?
+ lastq.substring(0, lastq.indexOf(':')) : null;
+ if (qqid != null && qqid != "null" && qqid.length() > 0)
+ {
+ qurl += "&qid=" + qqid;
+ qid = qqid;
+ String qrid = lastq.substring(lastq.indexOf(':') + 1); // retrieve old rid
+ if (qrid != null && !qrid.equals("null"))
+ {
+ rid = qrid;
+ qurl += "&rid=" + qrid;
+ }
+ }
+ // see if we have already responsed to this questionnaire.
+ prompt = checkresponse(new URL(qurl));
+ }
+ if (qid != null && rid != null)
+ {
+ // Update our local property cache with latest qid and rid
+ jalview.bin.Cache.setProperty("QUESTIONNAIRE", qid + ":" + rid);
+ }
+ if (prompt)
+ {
+ String qurl = url + (url.indexOf('?') > -1 ? "&" : "?") + "qid=" + qid +
+ "&rid=" + rid;
+ jalview.bin.Cache.log.info("Prompting user for questionnaire at " +
+ qurl);
+ int reply = JOptionPane.showInternalConfirmDialog(Desktop.desktop,
+ "There is a new Questionnaire available." +
+ "Would you like to complete it now ?\n",
+ "Jalview User Survey",
+ JOptionPane.YES_NO_OPTION,
+ JOptionPane.QUESTION_MESSAGE);
+
+ if (reply == JOptionPane.YES_OPTION)
+ {
+ jalview.bin.Cache.log.debug("Opening " + qurl);
+ jalview.util.BrowserLauncher.openURL(qurl);
+ }
+ }
+ }
+ catch (Exception e)
+ {
+ jalview.bin.Cache.log.warn("When trying to access questionnaire URL " +
+ url, e);
+ }
+ }
+
+}
diff --git a/src/jalview/gui/VamsasClient.java b/src/jalview/gui/VamsasClient.java
new file mode 100755
index 0000000..7c37bd3
--- /dev/null
+++ b/src/jalview/gui/VamsasClient.java
@@ -0,0 +1,275 @@
+/**
+ *
+ */
+package jalview.gui;
+
+import java.io.File;
+import java.io.OutputStreamWriter;
+import java.io.PrintWriter;
+import java.util.Hashtable;
+import java.util.IdentityHashMap;
+import java.util.Vector;
+import java.util.jar.JarOutputStream;
+
+import javax.swing.JInternalFrame;
+
+import jalview.bin.Cache;
+import jalview.io.VamsasDatastore;
+
+import org.vamsas.client.UserHandle;
+import org.vamsas.client.simpleclient.FileWatcher;
+import org.vamsas.client.simpleclient.VamsasArchive;
+import org.vamsas.client.simpleclient.VamsasFile;
+import org.vamsas.objects.core.Entry;
+import org.vamsas.objects.core.VamsasDocument;
+import org.vamsas.test.simpleclient.ArchiveClient;
+import org.vamsas.test.simpleclient.ClientDoc;
+
+/**
+ * @author jimp
+ *
+ */
+public class VamsasClient
+ extends ArchiveClient
+{
+ // Cache.preferences for vamsas client session arena
+ // preferences for check for default session at startup.
+ // user and organisation stuff.
+ public VamsasClient(Desktop jdesktop,
+ File sessionPath)
+ {
+ super(System.getProperty("user.name"), System.getProperty("host.name"),
+ "jalview", "2.7",
+ sessionPath);
+ }
+
+ public void initial_update()
+ {
+ Cache.log.info("Jalview loading the Vamsas Session.");
+ // load in the vamsas archive for the first time
+ ClientDoc cdoc = this.getUpdateable();
+ updateJalview(cdoc);
+ JInternalFrame[] frames = Desktop.desktop.getAllFrames();
+
+ if (frames == null)
+ {
+ return;
+ }
+
+ try
+ {
+ //REVERSE ORDER
+ for (int i = frames.length - 1; i > -1; i--)
+ {
+ if (frames[i] instanceof AlignFrame)
+ {
+ AlignFrame af = (AlignFrame) frames[i];
+ af.alignPanel.alignmentChanged();
+ }
+ }
+ }
+ catch (Exception e)
+ {
+ Cache.log.warn(
+ "Exception whilst refreshing jalview windows after a vamsas document update.",
+ e);
+ }
+ doUpdate(cdoc);
+ cdoc.closeDoc();
+ }
+
+ /**
+ * this will close all windows currently in Jalview.
+ *
+
+ protected void closeWindows() {
+ JInternalFrame[] frames = Desktop.desktop.getAllFrames();
+
+ if (frames == null)
+ {
+ return;
+ }
+
+ try
+ {
+ for (int i = frames.length - 1; i > -1; i--) {
+ frames[i].dispose();
+ }
+ } catch (Exception e) {
+ Cache.log.error("Whilst closing windows",e);
+ }
+
+ }
+
+ public void get_update(VamsasArchive doc) {
+ // Close windows - load update.
+ Cache.log.info("Jalview updating from Vamsas Session.");
+ }
+ */
+ VamsasClientWatcher watcher = null;
+ public void push_update()
+ {
+ watchForChange = false;
+ try
+ {
+ Thread.sleep(WATCH_SLEEP);
+ }
+ catch (Exception e)
+ {
+
+ }
+ ;
+ ClientDoc cdoc = getUpdateable();
+ updateVamsasDocument(cdoc);
+ doUpdate(cdoc);
+ cdoc.closeDoc();
+ cdoc = null;
+ watchForChange = true;
+ if (watcher != null)
+ {
+ watcher.start();
+ }
+ // collect all uncached alignments and put them into the vamsas dataset.
+ // store them.
+ Cache.log.info("Jalview updating the Vamsas Session.");
+ }
+
+ public void end_session()
+ {
+ // stop any update/watcher thread.
+ watchForChange = false; // this makes any watch(long) loops return.
+ // we should also wait arount for this.WATCH_SLEEP to really make sure the watcher thread has stopped.
+ try
+ {
+ Thread.sleep(WATCH_SLEEP);
+ }
+ catch (Exception e)
+ {
+
+ }
+ ;
+ Cache.log.info("Jalview disconnecting from the Vamsas Session.");
+ }
+
+ public void updateJalview(ClientDoc cdoc)
+ {
+ ensureJvVamsas();
+ VamsasDatastore vds = new VamsasDatastore(cdoc, vobj2jv, jv2vobj,
+ baseProvEntry());
+ vds.updateToJalview();
+ }
+
+ private void ensureJvVamsas()
+ {
+ if (jv2vobj == null)
+ {
+ jv2vobj = new IdentityHashMap();
+ vobj2jv = new Hashtable();
+ }
+ }
+
+ /**
+ * jalview object binding to VorbaIds
+ */
+ IdentityHashMap jv2vobj = null;
+ Hashtable vobj2jv = null;
+ public void updateVamsasDocument(ClientDoc doc)
+ {
+ ensureJvVamsas();
+ VamsasDatastore vds = new VamsasDatastore(doc, vobj2jv, jv2vobj,
+ baseProvEntry());
+ // wander through frames
+ JInternalFrame[] frames = Desktop.desktop.getAllFrames();
+
+ if (frames == null)
+ {
+ return;
+ }
+
+ try
+ {
+ //REVERSE ORDER
+ for (int i = frames.length - 1; i > -1; i--)
+ {
+ if (frames[i] instanceof AlignFrame)
+ {
+ AlignFrame af = (AlignFrame) frames[i];
+
+ // update alignment and root from frame.
+ vds.storeVAMSAS(af.getViewport(), af.getTitle());
+ }
+ }
+ }
+ catch (Exception e)
+ {
+ Cache.log.error("Vamsas Document store exception", e);
+ }
+ }
+
+ private Entry baseProvEntry()
+ {
+ org.vamsas.objects.core.Entry pentry = new org.vamsas.objects.core.Entry();
+ pentry.setUser(this.getProvenanceUser());
+ pentry.setApp(this.getClientHandle().getClientName());
+ pentry.setDate(new org.exolab.castor.types.Date(new java.util.Date()));
+ pentry.setAction("created");
+ return pentry;
+ }
+
+ protected class VamsasClientWatcher
+ extends Thread
+ {
+ /* (non-Javadoc)
+ * @see java.lang.Thread#run()
+ */
+ VamsasClient client = null;
+ VamsasClientWatcher(VamsasClient client)
+ {
+ this.client = client;
+ }
+
+ boolean running = false;
+ public void run()
+ {
+ running = true;
+ while (client.watchForChange)
+ {
+ ClientDoc docio = client.watch(0);
+ if (docio != null)
+ {
+ client.disableGui(true);
+ Cache.log.debug("Updating jalview from changed vamsas document.");
+ client.updateJalview(docio);
+ Cache.log.debug("Finished updating from document change.");
+ docio.closeDoc();
+ docio = null;
+ client.disableGui(false);
+ }
+ }
+ running = false;
+
+ }
+
+ }
+
+ public void disableGui(boolean b)
+ {
+ Desktop.instance.setVamsasUpdate(b);
+ }
+
+ public void startWatcher()
+ {
+ if (watcher == null)
+ {
+ watcher = new VamsasClientWatcher(this);
+ }
+ Thread thr = new Thread()
+ {
+ public void run()
+ {
+ watcher.start();
+ }
+ };
+ thr.start();
+ }
+}
diff --git a/src/jalview/io/AMSAFile.java b/src/jalview/io/AMSAFile.java
new file mode 100644
index 0000000..1f3fca0
--- /dev/null
+++ b/src/jalview/io/AMSAFile.java
@@ -0,0 +1,96 @@
+/*
+ * Jalview - A Sequence Alignment Editor and Viewer
+ * Copyright (C) 2007 AM Waterhouse, J Procter, G Barton, M Clamp, S Searle
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+package jalview.io;
+
+import jalview.datamodel.*;
+
+public class AMSAFile
+ extends jalview.io.FastaFile
+{
+
+ AlignmentI al;
+ /**
+ * Creates a new AMSAFile object for output.
+ */
+ public AMSAFile(AlignmentI al)
+ {
+ this.al = al;
+ }
+
+ /**
+ * DOCUMENT ME!
+ *
+ * @return DOCUMENT ME!
+ */
+ public String print()
+ {
+ super.print(getSeqsAsArray());
+
+ AlignmentAnnotation aa;
+ if (al.getAlignmentAnnotation() != null)
+ {
+ for (int i = 0; i < al.getAlignmentAnnotation().length; i++)
+ {
+ aa = al.getAlignmentAnnotation()[i];
+ if (aa.autoCalculated || !aa.visible)
+ {
+ continue;
+ }
+
+ out.append(">#_" + aa.label);
+ if (aa.description != null)
+ {
+ out.append(" " + aa.description);
+ }
+
+ out.append("\n");
+
+ int nochunks = (aa.annotations.length / len) + 1;
+
+ for (int j = 0; j < nochunks; j++)
+ {
+ int start = j * len;
+ int end = start + len;
+ if (end > aa.annotations.length)
+ {
+ end = aa.annotations.length;
+ }
+
+ String ch;
+ for (int k = start; k < end; k++)
+ {
+ if (aa.annotations[k] == null)
+ {
+ ch = " ";
+ }
+ else
+ {
+ ch = aa.annotations[k].displayCharacter;
+ }
+
+ out.append(ch);
+
+ }
+ out.append("\n");
+ }
+ }
+ }
+ return out.toString();
+ }
+}
diff --git a/src/jalview/io/VamsasDatastore.java b/src/jalview/io/VamsasDatastore.java
new file mode 100755
index 0000000..f1cba4f
--- /dev/null
+++ b/src/jalview/io/VamsasDatastore.java
@@ -0,0 +1,1900 @@
+/*
+ * Jalview - A Sequence Alignment Editor and Viewer
+ * Copyright (C) 2005 AM Waterhouse, J Procter, G Barton, M Clamp, S Searle
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+package jalview.io;
+
+import jalview.bin.Cache;
+import jalview.datamodel.AlignmentAnnotation;
+import jalview.datamodel.AlignmentI;
+import jalview.datamodel.AlignmentView;
+import jalview.datamodel.DBRefEntry;
+import jalview.datamodel.SequenceFeature;
+import jalview.datamodel.SequenceI;
+import jalview.gui.AlignFrame;
+import jalview.gui.AlignViewport;
+import jalview.gui.Desktop;
+import jalview.gui.TreePanel;
+
+import java.util.HashMap;
+import java.util.Hashtable;
+import java.util.IdentityHashMap;
+import java.util.Vector;
+
+import org.vamsas.client.Vobject;
+import org.vamsas.client.VorbaId;
+import org.vamsas.objects.core.Alignment;
+import org.vamsas.objects.core.AlignmentSequence;
+import org.vamsas.objects.core.AlignmentSequenceAnnotation;
+import org.vamsas.objects.core.AnnotationElement;
+import org.vamsas.objects.core.DataSet;
+import org.vamsas.objects.core.DataSetAnnotations;
+import org.vamsas.objects.core.DbRef;
+import org.vamsas.objects.core.Entry;
+import org.vamsas.objects.core.Glyph;
+import org.vamsas.objects.core.Input;
+import org.vamsas.objects.core.Link;
+import org.vamsas.objects.core.Newick;
+import org.vamsas.objects.core.Param;
+import org.vamsas.objects.core.Property;
+import org.vamsas.objects.core.Provenance;
+import org.vamsas.objects.core.RangeAnnotation;
+import org.vamsas.objects.core.RangeType;
+import org.vamsas.objects.core.Seg;
+import org.vamsas.objects.core.Sequence;
+import org.vamsas.objects.core.Tree;
+import org.vamsas.objects.core.VAMSAS;
+import org.vamsas.test.simpleclient.ClientDoc;
+
+/*
+ *
+ * static {
+ * org.exolab.castor.util.LocalConfiguration.getInstance().getProperties().setProperty(
+ * "org.exolab.castor.serializer", "org.apache.xml.serialize.XMLSerilazizer"); }
+ *
+ */
+
+public class VamsasDatastore
+{
+ Entry provEntry = null;
+
+ // AlignViewport av;
+
+ org.exolab.castor.types.Date date = new org.exolab.castor.types.Date(
+ new java.util.Date());
+
+ ClientDoc cdoc;
+
+ Hashtable vobj2jv;
+
+ IdentityHashMap jv2vobj;
+
+ public VamsasDatastore(ClientDoc cdoc, Hashtable vobj2jv,
+ IdentityHashMap jv2vobj, Entry provEntry)
+ {
+ this.cdoc = cdoc;
+ this.vobj2jv = vobj2jv;
+ this.jv2vobj = jv2vobj;
+ this.provEntry = provEntry;
+ }
+
+ /*
+ * public void storeJalview(String file, AlignFrame af) { try { // 1. Load the
+ * mapping information from the file Mapping map = new
+ * Mapping(getClass().getClassLoader()); java.net.URL url =
+ * getClass().getResource("/jalview_mapping.xml"); map.loadMapping(url); // 2.
+ * Unmarshal the data // Unmarshaller unmar = new Unmarshaller();
+ * //unmar.setIgnoreExtraElements(true); //unmar.setMapping(map); // uni =
+ * (UniprotFile) unmar.unmarshal(new FileReader(file)); // 3. marshal the data
+ * with the total price back and print the XML in the console Marshaller
+ * marshaller = new Marshaller( new FileWriter(file) );
+ *
+ * marshaller.setMapping(map); marshaller.marshal(af); } catch (Exception e) {
+ * e.printStackTrace(); } }
+ *
+ *
+ */
+ /**
+ * @return the Vobject bound to Jalview datamodel object
+ */
+ protected Vobject getjv2vObj(Object jvobj)
+ {
+ if (jv2vobj.containsKey(jvobj))
+ {
+ return cdoc.getObject( (VorbaId) jv2vobj.get(jvobj));
+ }
+ return null;
+ }
+
+ /**
+ *
+ * @param vobj
+ * @return Jalview datamodel object bound to the vamsas document object
+ */
+ protected Object getvObj2jv(org.vamsas.client.Vobject vobj)
+ {
+ VorbaId id = vobj.getVorbaId();
+ if (id == null)
+ {
+ id = cdoc.registerObject(vobj);
+ Cache.log
+ .debug("Registering new object and returning null for getvObj2jv");
+ return null;
+ }
+ if (vobj2jv.containsKey(vobj.getVorbaId()))
+ {
+ return vobj2jv.get(vobj.getVorbaId());
+ }
+ return null;
+ }
+
+ protected void bindjvvobj(Object jvobj, org.vamsas.client.Vobject vobj)
+ {
+ VorbaId id = vobj.getVorbaId();
+ if (id == null)
+ {
+ id = cdoc.registerObject(vobj);
+ if (id == null || vobj.getVorbaId() == null)
+ {
+ Cache.log.error("Failed to get id for " +
+ (vobj.isRegisterable() ? "registerable" :
+ "unregisterable") + " object " + vobj);
+ }
+ }
+
+ if (vobj2jv.containsKey(vobj.getVorbaId()) &&
+ ! ( (VorbaId) vobj2jv.get(vobj.getVorbaId())).equals(jvobj))
+ {
+ Cache.log.debug("Warning? Overwriting existing vamsas id binding for " +
+ vobj.getVorbaId(),
+ new Exception("Overwriting vamsas id binding."));
+ }
+ else if (jv2vobj.containsKey(jvobj) &&
+ ! ( (VorbaId) jv2vobj.get(jvobj)).equals(vobj.getVorbaId()))
+ {
+ Cache.log.debug(
+ "Warning? Overwriting existing jalview object binding for " + jvobj,
+ new Exception("Overwriting jalview object binding."));
+ }
+ /* Cache.log.error("Attempt to make conflicting object binding! "+vobj+" id " +vobj.getVorbaId()+" already bound to "+getvObj2jv(vobj)+" and "+jvobj+" already bound to "+getjv2vObj(jvobj),new Exception("Excessive call to bindjvvobj"));
+ }*/
+ // we just update the hash's regardless!
+ vobj2jv.put(vobj.getVorbaId(), jvobj);
+ // JBPNote - better implementing a hybrid invertible hash.
+ jv2vobj.put(jvobj, vobj.getVorbaId());
+ }
+
+ /**
+ * put the alignment viewed by AlignViewport into cdoc.
+ *
+ * @param av alignViewport to be stored
+ * @param aFtitle title for alignment
+ */
+ public void storeVAMSAS(AlignViewport av, String aFtitle)
+ {
+ try
+ {
+ jalview.datamodel.AlignmentI jal = av.getAlignment();
+ boolean nw = false;
+ VAMSAS root = null; // will be resolved based on Dataset Parent.
+ // /////////////////////////////////////////
+ // SAVE THE DATASET
+ if (jal.getDataset() == null)
+ {
+ Cache.log.warn("Creating new dataset for an alignment.");
+ jal.setDataset(null);
+ }
+ DataSet dataset = (DataSet) getjv2vObj(jal.getDataset());
+ if (dataset == null)
+ {
+ root = cdoc.getVamsasRoots()[0]; // default vamsas root for modifying.
+ dataset = new DataSet();
+ root.addDataSet(dataset);
+ bindjvvobj(jal.getDataset(), dataset);
+ dataset.setProvenance(dummyProvenance());
+ dataset.getProvenance().addEntry(provEntry);
+ nw = true;
+ }
+ else
+ {
+ root = (VAMSAS) dataset.getV_parent();
+ }
+ // update dataset
+ Sequence sequence;
+ DbRef dbref;
+ // set new dataset and alignment sequences based on alignment Nucleotide
+ // flag.
+ // this *will* break when alignment contains both nucleotide and amino
+ // acid sequences.
+ String dict = jal.isNucleotide() ?
+ org.vamsas.objects.utils.SymbolDictionary.STANDARD_NA
+ : org.vamsas.objects.utils.SymbolDictionary.STANDARD_AA;
+ for (int i = 0; i < jal.getHeight(); i++)
+ {
+ SequenceI sq = jal.getSequenceAt(i).getDatasetSequence(); // only insert
+ // referenced
+ // sequences
+ // to dataset.
+ sequence = (Sequence) getjv2vObj(sq);
+ if (sequence == null)
+ {
+ sequence = new Sequence();
+ bindjvvobj(sq, sequence);
+ sq.setVamsasId(sequence.getVorbaId().getId());
+ sequence.setSequence(sq.getSequenceAsString());
+ sequence.setDictionary(dict);
+ sequence.setName(jal.getDataset().getSequenceAt(i).getName());
+ sequence.setStart(jal.getDataset().getSequenceAt(i).getStart());
+ sequence.setEnd(jal.getDataset().getSequenceAt(i).getEnd());
+ dataset.addSequence(sequence);
+ }
+ else
+ {
+ // verify principal attributes. and update any new
+ // features/references.
+ System.out.println("update dataset sequence object.");
+ }
+ if (sq.getSequenceFeatures() != null)
+ {
+ int sfSize = sq.getSequenceFeatures().length;
+
+ for (int sf = 0; sf < sfSize; sf++)
+ {
+ jalview.datamodel.SequenceFeature feature = (jalview.datamodel.
+ SequenceFeature) sq
+ .getSequenceFeatures()[sf];
+
+ DataSetAnnotations dsa = (DataSetAnnotations) getjv2vObj(feature);
+ if (dsa == null)
+ {
+ dsa = (DataSetAnnotations) getDSAnnotationFromJalview(
+ new DataSetAnnotations(), feature);
+ if (dsa.getProvenance() == null)
+ {
+ dsa.setProvenance(new Provenance());
+ }
+ addProvenance(dsa.getProvenance(), "created"); // JBPNote - need
+ // to update
+ dsa.setSeqRef(sequence);
+ bindjvvobj(feature, dsa);
+ dataset.addDataSetAnnotations(dsa);
+ }
+ else
+ {
+ // todo: verify and update dataset annotations for sequence
+ System.out.println("update dataset sequence annotations.");
+ }
+ }
+ }
+
+ if (sq.getDBRef() != null)
+ {
+ DBRefEntry[] entries = sq.getDBRef();
+ jalview.datamodel.DBRefEntry dbentry;
+ for (int db = 0; db < entries.length; db++)
+ {
+ dbentry = entries[db];
+ dbref = (DbRef) getjv2vObj(dbentry);
+ if (dbref == null)
+ {
+ dbref = new DbRef();
+ bindjvvobj(dbentry, dbref);
+ dbref.setAccessionId(dbentry.getAccessionId());
+ dbref.setSource(dbentry.getSource());
+ dbref.setVersion(dbentry.getVersion());
+ /*
+ * TODO: Maps are not yet supported by Jalview. Map vMap = new
+ * Map(); vMap.set dbref.addMap(vMap);
+ */
+ sequence.addDbRef(dbref);
+ }
+ else
+ {
+ // TODO: verify and update dbrefs in vamsas document
+ // there will be trouble when a dataset sequence is modified to
+ // contain more residues than were originally referenced - we must
+ // then make a number of dataset sequence entries
+ System.out
+ .println("update dataset sequence database references.");
+ }
+ }
+
+ }
+ }
+ // dataset.setProvenance(getVamsasProvenance(jal.getDataset().getProvenance()));
+ // ////////////////////////////////////////////
+
+ // ////////////////////////////////////////////
+ // Save the Alignments
+
+ Alignment alignment = (Alignment) getjv2vObj(av); // this is so we can get the alignviewport back
+ if (alignment == null)
+ {
+ alignment = new Alignment();
+ bindjvvobj(av, alignment);
+ if (alignment.getProvenance() == null)
+ {
+ alignment.setProvenance(new Provenance());
+ }
+ addProvenance(alignment.getProvenance(), "added"); // TODO: insert some
+ // sensible source
+ // here
+ dataset.addAlignment(alignment);
+ {
+ Property title = new Property();
+ title.setName("jalview:AlTitle");
+ title.setType("string");
+ title.setContent(aFtitle);
+ alignment.addProperty(title);
+ }
+ alignment.setGapChar(String.valueOf(av.getGapCharacter()));
+ AlignmentSequence alseq = null;
+ for (int i = 0; i < jal.getHeight(); i++)
+ {
+ alseq = new AlignmentSequence();
+ // TODO: VAMSAS: translate lowercase symbols to annotation ?
+ alseq.setSequence(jal.getSequenceAt(i).getSequenceAsString());
+ alseq.setName(jal.getSequenceAt(i).getName());
+ alseq.setStart(jal.getSequenceAt(i).getStart());
+ alseq.setEnd(jal.getSequenceAt(i).getEnd());
+ alseq.setRefid(getjv2vObj(jal.getSequenceAt(i).getDatasetSequence()));
+ alignment.addAlignmentSequence(alseq);
+ bindjvvobj(jal.getSequenceAt(i), alseq);
+ }
+ }
+ else
+ {
+ // todo: verify and update mutable alignment props.
+ if (alignment.getModifiable())
+ {
+ System.out.println("update alignment in document.");
+ }
+ else
+ {
+ System.out
+ .println("update edited alignment to new alignment in document.");
+ }
+ }
+ // ////////////////////////////////////////////
+ // SAVE Alignment Sequence Features
+ for (int i = 0, iSize = alignment.getAlignmentSequenceCount(); i < iSize;
+ i++)
+ {
+ AlignmentSequence valseq;
+ SequenceI alseq = (SequenceI) getvObj2jv(valseq = alignment
+ .getAlignmentSequence(i));
+ if (alseq != null && alseq.getSequenceFeatures() != null)
+ {
+ jalview.datamodel.SequenceFeature[] features = alseq
+ .getSequenceFeatures();
+ for (int f = 0; f < features.length; f++)
+ {
+ if (features[f] != null)
+ {
+ AlignmentSequenceAnnotation valseqf = (
+ AlignmentSequenceAnnotation) getjv2vObj(features[i]);
+ if (valseqf == null)
+ {
+
+ valseqf = (AlignmentSequenceAnnotation)
+ getDSAnnotationFromJalview(
+ new AlignmentSequenceAnnotation(), features[i]);
+ if (valseqf.getProvenance() == null)
+ {
+ valseqf.setProvenance(new Provenance());
+ }
+ addProvenance(valseqf.getProvenance(), "created"); // JBPNote -
+ // need to
+ // update
+ bindjvvobj(features[i], valseqf);
+ valseq.addAlignmentSequenceAnnotation(valseqf);
+ }
+ }
+
+ }
+ }
+ }
+
+ // ////////////////////////////////////////////
+ // SAVE ANNOTATIONS
+ if (jal.getAlignmentAnnotation() != null)
+ {
+ jalview.datamodel.AlignmentAnnotation[] aa = jal
+ .getAlignmentAnnotation();
+ java.util.HashMap AlSeqMaps = new HashMap(); // stores int maps from
+ // alignment columns to
+ // sequence positions.
+ for (int i = 0; i < aa.length; i++)
+ {
+ if (aa[i] == null || isJalviewOnly(aa[i]))
+ {
+ continue;
+ }
+ if (aa[i].sequenceRef != null)
+ {
+ org.vamsas.objects.core.AlignmentSequence alsref = (org.vamsas.
+ objects.core.AlignmentSequence) getjv2vObj(aa[i].sequenceRef);
+ org.vamsas.objects.core.AlignmentSequenceAnnotation an = (org.
+ vamsas.objects.core.AlignmentSequenceAnnotation) getjv2vObj(aa[
+ i]);
+ int[] gapMap = null;
+ if (AlSeqMaps.containsKey(aa[i].sequenceRef))
+ {
+ gapMap = (int[]) AlSeqMaps.get(aa[i].sequenceRef);
+ }
+ else
+ {
+ gapMap = new int[aa[i].sequenceRef.getLength()];
+ // map from alignment position to sequence position.
+ int[] sgapMap = aa[i].sequenceRef.gapMap();
+ for (int a = 0; a < sgapMap.length; a++)
+ {
+ gapMap[sgapMap[a]] = a;
+ }
+ }
+ if (an == null)
+ {
+ an = new org.vamsas.objects.core.AlignmentSequenceAnnotation();
+ Seg vSeg = new Seg();
+ vSeg.setStart(1);
+ vSeg.setInclusive(true);
+ vSeg.setEnd(gapMap.length);
+ an.addSeg(vSeg);
+ an.setType("jalview:SecondaryStructurePrediction"); // TODO: better fix this rough guess ;)
+ alsref.addAlignmentSequenceAnnotation(an);
+ bindjvvobj(aa[i], an);
+ // LATER: much of this is verbatim from the alignmentAnnotation
+ // method below. suggests refactoring to make rangeAnnotation the
+ // base class
+ an.setDescription(aa[i].description);
+ if (aa[i].graph > 0)
+ {
+ an.setGraph(true); // aa[i].graph);
+ }
+ else
+ {
+ an.setGraph(false);
+ }
+ an.setLabel(aa[i].label);
+ an.setProvenance(dummyProvenance()); // get provenance as user
+ // created, or jnet, or
+ // something else.
+ an.setGroup(Integer.toString(aa[i].graphGroup)); // // JBPNote -
+ // originally we
+ // were going to
+ // store
+ // graphGroup in
+ // the Jalview
+ // specific
+ // bits.
+ AnnotationElement ae;
+ for (int a = 0; a < aa[i].annotations.length; a++)
+ {
+ if (aa[i].annotations[a] == null)
+ {
+ continue;
+ }
+
+ ae = new AnnotationElement();
+ ae.setDescription(aa[i].annotations[a].description);
+ ae.addGlyph(new Glyph());
+ ae.getGlyph(0)
+ .setContent(aa[i].annotations[a].displayCharacter); // assume
+ // jax-b
+ // takes
+ // care
+ // of
+ // utf8
+ // translation
+ if (aa[i].graph !=
+ jalview.datamodel.AlignmentAnnotation.NO_GRAPH)
+ {
+ ae.addValue(aa[i].annotations[a].value);
+ }
+ ae.setPosition(gapMap[a] + 1); // position w.r.t. AlignmentSequence
+ // symbols
+ if (aa[i].annotations[a].secondaryStructure != ' ')
+ {
+ // we only write an annotation where it really exists.
+ Glyph ss = new Glyph();
+ ss
+ .setDict(org.vamsas.objects.utils.GlyphDictionary.
+ PROTEIN_SS_3STATE);
+ ss.setContent(String
+ .valueOf(aa[i].annotations[a].
+ secondaryStructure));
+ ae.addGlyph(ss);
+ }
+ an.addAnnotationElement(ae);
+ }
+ }
+ else
+ {
+ // update reference sequence Annotation
+ if (an.getModifiable())
+ {
+ // verify existing alignment sequence annotation is up to date
+ System.out.println("update alignment sequence annotation.");
+ }
+ else
+ {
+ // verify existing alignment sequence annotation is up to date
+ System.out
+ .println(
+ "make new alignment sequence annotation if modification has happened.");
+ }
+ }
+ }
+ else
+ {
+ // add Alignment Annotation
+ org.vamsas.objects.core.AlignmentAnnotation an = (org.vamsas.
+ objects.core.AlignmentAnnotation) getjv2vObj(aa[i]);
+ if (an == null)
+ {
+ an = new org.vamsas.objects.core.AlignmentAnnotation();
+ an.setType("jalview:AnnotationRow");
+ an.setDescription(aa[i].description);
+ alignment.addAlignmentAnnotation(an);
+ Seg vSeg = new Seg();
+ vSeg.setStart(1);
+ vSeg.setInclusive(true);
+ vSeg.setEnd(jal.getWidth());
+ an.addSeg(vSeg);
+ if (aa[i].graph > 0)
+ {
+ an.setGraph(true); // aa[i].graph);
+ }
+ an.setLabel(aa[i].label);
+ an.setProvenance(dummyProvenance());
+ if (aa[i].graph != aa[i].NO_GRAPH)
+ {
+ an.setGroup(Integer.toString(aa[i].graphGroup)); // // JBPNote -
+ // originally we
+ // were going to
+ // store
+ // graphGroup in
+ // the Jalview
+ // specific
+ // bits.
+ an.setGraph(true);
+ }
+ else
+ {
+ an.setGraph(false);
+ }
+ AnnotationElement ae;
+
+ for (int a = 0; a < aa[i].annotations.length; a++)
+ {
+ if ( (aa[i] == null) || (aa[i].annotations[a] == null))
+ {
+ continue;
+ }
+
+ ae = new AnnotationElement();
+ ae.setDescription(aa[i].annotations[a].description);
+ ae.addGlyph(new Glyph());
+ ae.getGlyph(0)
+ .setContent(aa[i].annotations[a].displayCharacter); // assume
+ // jax-b
+ // takes
+ // care
+ // of
+ // utf8
+ // translation
+ ae.addValue(aa[i].annotations[a].value);
+ ae.setPosition(a + 1);
+ if (aa[i].annotations[a].secondaryStructure != ' ')
+ {
+ Glyph ss = new Glyph();
+ ss
+ .setDict(org.vamsas.objects.utils.GlyphDictionary.
+ PROTEIN_SS_3STATE);
+ ss.setContent(String
+ .valueOf(aa[i].annotations[a].
+ secondaryStructure));
+ ae.addGlyph(ss);
+ }
+ an.addAnnotationElement(ae);
+ }
+ if (aa[i].editable)
+ {
+ //an.addProperty(newProperty("jalview:editable", null, "true"));
+ an.setModifiable(true);
+ }
+ if (aa[i].graph != jalview.datamodel.AlignmentAnnotation.NO_GRAPH)
+ {
+ an.setGraph(true);
+ an.setGroup(Integer.toString(aa[i].graphGroup));
+ an.addProperty(newProperty("jalview:graphType", null,
+ ( (aa[i].graph ==
+ jalview.datamodel.AlignmentAnnotation.
+ BAR_GRAPH) ? "BAR_GRAPH" :
+ "LINE_GRAPH")));
+
+ /** and on and on..
+ vProperty=new Property();
+ vProperty.setName("jalview:graphThreshhold");
+ vProperty.setContent(aa[i].threshold);
+ */
+
+ }
+ }
+ else
+ {
+ if (an.getModifiable())
+ {
+ // verify annotation - update (perhaps)
+ Cache.log.info(
+ "update alignment sequence annotation. not yet implemented.");
+ }
+ else
+ {
+ // verify annotation - update (perhaps)
+ Cache.log.info("updated alignment sequence annotation added.");
+ }
+ }
+ }
+ }
+ }
+ // /////////////////////////////////////////////////////
+
+ // //////////////////////////////////////////////
+ // /SAVE THE TREES
+ // /////////////////////////////////
+ // FIND ANY ASSOCIATED TREES
+ if (Desktop.desktop != null)
+ {
+ javax.swing.JInternalFrame[] frames = Desktop.desktop.getAllFrames();
+
+ for (int t = 0; t < frames.length; t++)
+ {
+ if (frames[t] instanceof TreePanel)
+ {
+ TreePanel tp = (TreePanel) frames[t];
+
+ if (tp.getAlignment() == jal)
+ {
+ Tree tree = (Tree) getjv2vObj(tp);
+ if (tree == null)
+ {
+ tree = new Tree();
+ bindjvvobj(tp, tree);
+ tree.setTitle(tp.getTitle());
+ Newick newick = new Newick();
+ // TODO: translate sequenceI to leaf mappings to vamsas
+ // references - see tree specification in schema.
+ newick.setContent(tp.getTree().toString());
+ newick.setTitle(tp.getTitle());
+ tree.addNewick(newick);
+ tree.setProvenance(makeTreeProvenance(jal, tp));
+ alignment.addTree(tree);
+ }
+ else
+ {
+ if (tree.getModifiable())
+ {
+ // verify any changes.
+ System.out.println("Update tree in document.");
+ }
+ else
+ {
+ System.out
+ .println("Add modified tree as new tree in document.");
+ }
+ }
+ }
+ }
+ }
+ }
+ // Store Jalview specific stuff in the Jalview appData
+ // not implemented in the SimpleDoc interface.
+ }
+
+ catch (Exception ex)
+ {
+ ex.printStackTrace();
+ }
+
+ }
+
+ private Property newProperty(String name, String type, String content)
+ {
+ Property vProperty = new Property();
+ vProperty.setName(name);
+ if (type != null)
+ {
+ vProperty.setType(type);
+ }
+ else
+ {
+ vProperty.setType("String");
+ }
+ vProperty.setContent(content);
+ return vProperty;
+ }
+
+ /**
+ * correctly create a RangeAnnotation from a jalview sequence feature
+ *
+ * @param dsa
+ * (typically DataSetAnnotations or AlignmentSequenceAnnotation)
+ * @param feature
+ * (the feature to be mapped from)
+ * @return
+ */
+ private RangeAnnotation getDSAnnotationFromJalview(RangeAnnotation dsa,
+ SequenceFeature feature)
+ {
+ dsa.setType(feature.getType());
+ Seg vSeg = new Seg();
+ vSeg.setStart(feature.getBegin());
+ vSeg.setEnd(feature.getEnd());
+ vSeg.setInclusive(true);
+ dsa.addSeg(vSeg);
+ dsa.setDescription(feature.getDescription());
+ dsa.setStatus(feature.getStatus());
+ if (feature.links != null && feature.links.size() > 0)
+ {
+ for (int i = 0, iSize = feature.links.size(); i < iSize; i++)
+ {
+ String link = (String) feature.links.elementAt(i);
+ int sep = link.indexOf('|');
+ if (sep > -1)
+ {
+ Link vLink = new Link();
+ if (sep > 0)
+ {
+ vLink.setContent(link.substring(0, sep - 1));
+ }
+ else
+ {
+ vLink.setContent("");
+ }
+ vLink.setHref(link.substring(sep + 1)); // TODO: validate href.
+ dsa.addLink(vLink);
+ }
+ }
+ }
+ dsa.setGroup(feature.getFeatureGroup());
+ return dsa;
+ }
+
+ /**
+ * correctly creates provenance for trees calculated on an alignment by
+ * jalview.
+ *
+ * @param jal
+ * @param tp
+ * @return
+ */
+ private Provenance makeTreeProvenance(AlignmentI jal, TreePanel tp)
+ {
+ Provenance prov = new Provenance();
+ prov.addEntry(new Entry());
+ prov.getEntry(0).setAction("imported " + tp.getTitle());
+ prov.getEntry(0).setUser(provEntry.getUser());
+ prov.getEntry(0).setApp(provEntry.getApp());
+ prov.getEntry(0).setDate(provEntry.getDate());
+ if (tp.getTree().hasOriginalSequenceData())
+ {
+ Input vInput = new Input();
+ // LATER: check to see if tree input data is contained in this alignment -
+ // or just correctly resolve the tree's seqData to the correct alignment in
+ // the document.
+ // vInput.setObjRef(getjv2vObj(jal));
+ vInput.setObjRef(getjv2vObj(tp.getViewPort()));
+ prov.getEntry(0).setAction("created " + tp.getTitle());
+ prov.getEntry(0).addInput(vInput);
+ vInput.setName("jalview:seqdist");
+ prov.getEntry(0).addParam(new Param());
+ prov.getEntry(0).getParam(0).setName("treeType");
+ prov.getEntry(0).getParam(0).setType("utf8");
+ prov.getEntry(0).getParam(0).setContent("NJ");
+
+ int ranges[] = tp.getTree().seqData.getVisibleContigs();
+ // VisibleContigs are with respect to alignment coordinates. Still need offsets
+ int start = tp.getTree().seqData.getAlignmentOrigin();
+ for (int r = 0; r < ranges.length; r += 2)
+ {
+ Seg visSeg = new Seg();
+ visSeg.setStart(1 + start + ranges[r]);
+ visSeg.setEnd(start + ranges[r + 1]);
+ visSeg.setInclusive(true);
+ vInput.addSeg(visSeg);
+ }
+ }
+ return prov;
+ }
+
+ /**
+ *
+ * @param tp
+ * @return Object[] { AlignmentView, AlignmentI - reference alignment for
+ * input }
+ */
+ private Object[] recoverInputData(Provenance tp)
+ {
+ for (int pe = 0; pe < tp.getEntryCount(); pe++)
+ {
+ if (tp.getEntry(pe).getInputCount() > 0)
+ {
+ if (tp.getEntry(pe).getInputCount() > 1)
+ {
+ Cache.log.warn("Ignoring additional input spec in provenance entry "
+ + tp.getEntry(pe).toString());
+ }
+ // LATER: deal sensibly with multiple inputs.
+ Input vInput = tp.getEntry(pe).getInput(0);
+ if (vInput.getObjRef() instanceof org.vamsas.objects.core.Alignment)
+ {
+ // recover an AlignmentView for the input data
+ AlignViewport javport = (AlignViewport) getvObj2jv( (org.vamsas.
+ client.Vobject) vInput
+ .getObjRef());
+ jalview.datamodel.AlignmentI jal = javport.getAlignment();
+ jalview.datamodel.CigarArray view = javport.getAlignment().
+ getCompactAlignment();
+ int from = 1, to = jal.getWidth();
+ int offset = 0; // deleteRange modifies its frame of reference
+ for (int r = 0, s = vInput.getSegCount(); r < s; r++)
+ {
+ Seg visSeg = vInput.getSeg(r);
+ int se[] = getSegRange(visSeg, true); // jalview doesn't do bidirection alignments yet.
+ if (to < se[1])
+ {
+ Cache.log.warn("Ignoring invalid segment in InputData spec.");
+ }
+ else
+ {
+ if (se[0] > from)
+ {
+ view.deleteRange(offset + from - 1, offset + se[0] - 2);
+ offset -= se[0] - from;
+ }
+ from = se[1] + 1;
+ }
+ }
+ if (from < to)
+ {
+ view.deleteRange(offset + from - 1, offset + to - 1); // final deletion - TODO: check off by
+ // one for to
+ }
+ return new Object[]
+ {
+ new AlignmentView(view), jal};
+ }
+ }
+ }
+ Cache.log.debug("Returning null for input data recovery from provenance.");
+ return null;
+ }
+
+ /**
+ * get start 0)
+ {
+ DbRef[] dbref = vdseq.getDbRef();
+ for (int db = 0; db < dbref.length; db++)
+ {
+ jalview.datamodel.DBRefEntry dbr = (jalview.datamodel.DBRefEntry)
+ getvObj2jv(dbref[db]);
+ if (dbr == null)
+ {
+ // add new dbref
+ dsseq.addDBRef(dbr = new jalview.datamodel.DBRefEntry
+ (
+ dbref[db].getSource().toString(),
+ dbref[db].getVersion().toString(),
+ dbref[db].getAccessionId().toString()));
+ bindjvvobj(dbr, dbref[db]);
+ }
+ }
+ }
+ }
+
+ if (newds)
+ {
+ SequenceI[] seqs = new SequenceI[dsseqs.size()];
+ for (i = 0, iSize = dsseqs.size(); i < iSize; i++)
+ {
+ seqs[i] = (SequenceI) dsseqs.elementAt(i);
+ dsseqs.setElementAt(null, i);
+ }
+ jdataset = new jalview.datamodel.Alignment(seqs);
+ Cache.log.debug("New vamsas dataset imported into jalview.");
+ bindjvvobj(jdataset, dataset);
+ }
+ // ////////
+ // add any new dataset sequence feature annotations
+ if (dataset.getDataSetAnnotations() != null)
+ {
+ for (int dsa = 0; dsa < dataset.getDataSetAnnotationsCount(); dsa++)
+ {
+ DataSetAnnotations dseta = dataset.getDataSetAnnotations(dsa);
+ SequenceI dsSeq = (SequenceI) getvObj2jv( (Vobject) dseta.getSeqRef());
+ if (dsSeq == null)
+ {
+ jalview.bin.Cache.log.warn(
+ "Couldn't resolve jalview sequenceI for dataset object reference " +
+ ( (Vobject) dataset.getDataSetAnnotations(dsa).getSeqRef()).
+ getVorbaId().getId());
+ }
+ else
+ {
+ if (dseta.getAnnotationElementCount() == 0)
+ {
+ jalview.datamodel.SequenceFeature sf = (jalview.datamodel.
+ SequenceFeature) getvObj2jv(dseta);
+ if (sf == null)
+ {
+ dsSeq.addSequenceFeature(sf = getJalviewSeqFeature(dseta));
+ bindjvvobj(sf, dseta);
+ }
+ }
+ else
+ {
+ // TODO: deal with alignmentAnnotation style annotation
+ // appearing on dataset sequences.
+ // JBPNote: we could just add them to all alignments but
+ // that may complicate cross references in the jalview
+ // datamodel
+ Cache.log.warn("Ignoring dataset annotation with annotationElements. Not yet supported in jalview.");
+ }
+ }
+ }
+ }
+
+ if (dataset.getAlignmentCount() > 0)
+ {
+ // LOAD ALIGNMENTS from DATASET
+
+ for (int al = 0, nal = dataset.getAlignmentCount(); al < nal; al++)
+ {
+ org.vamsas.objects.core.Alignment alignment = dataset.getAlignment(
+ al);
+ AlignViewport av = (AlignViewport) getvObj2jv(alignment);
+ jalview.datamodel.AlignmentI jal = null;
+ if (av != null)
+ {
+ jal = av.getAlignment();
+ }
+ iSize = alignment.getAlignmentSequenceCount();
+ boolean newal = (jal == null) ? true : false;
+ Vector newasAnnots = new Vector();
+ char gapChar = ' '; // default for new alignments read in from the document
+ if (jal != null)
+ {
+ dsseqs = jal.getSequences(); // for merge/update
+ gapChar = jal.getGapCharacter();
+ }
+ else
+ {
+ dsseqs = new Vector();
+ }
+ char valGapchar = alignment.getGapChar().charAt(0);
+ for (i = 0; i < iSize; i++)
+ {
+ AlignmentSequence valseq = alignment.getAlignmentSequence(i);
+ jalview.datamodel.SequenceI alseq = (SequenceI) getvObj2jv(valseq);
+ if (alseq != null)
+ {
+ //TODO: upperCase/LowerCase situation here ? do we allow it ?
+ //if (!alseq.getSequence().equals(valseq.getSequence())) {
+ // throw new Error("Broken! - mismatch of dataset sequence and jalview internal dataset sequence.");
+ if (Cache.log.isDebugEnabled())
+ {
+ Cache.log.debug("Updating apparently edited sequence " +
+ alseq.getName());
+ }
+ // this might go *horribly* wrong
+ alseq.setSequence(new String(valseq.getSequence()).replace(
+ valGapchar, gapChar));
+ jremain--;
+ }
+ else
+ {
+ alseq = new jalview.datamodel.Sequence(
+ valseq.getName(),
+ valseq.getSequence().replace(valGapchar, gapChar),
+ valseq.getStart(),
+ valseq.getEnd());
+
+ Vobject datsetseq = (Vobject) valseq.getRefid();
+ if (datsetseq != null)
+ {
+ alseq.setDatasetSequence( (SequenceI) getvObj2jv(datsetseq)); // exceptions if AlignemntSequence reference isn't a simple SequenceI
+ }
+ else
+ {
+ Cache.log.error(
+ "Invalid dataset sequence id (null) for alignment sequence " +
+ valseq.getVorbaId());
+ }
+ bindjvvobj(alseq, valseq);
+ alseq.setVamsasId(valseq.getVorbaId().getId());
+ dsseqs.add(alseq);
+ }
+ if (valseq.getAlignmentSequenceAnnotationCount() > 0)
+ {
+ AlignmentSequenceAnnotation[] vasannot = valseq.
+ getAlignmentSequenceAnnotation();
+ for (int a = 0; a < vasannot.length; a++)
+ {
+ jalview.datamodel.AlignmentAnnotation asa = (jalview.
+ datamodel.AlignmentAnnotation) getvObj2jv(vasannot[a]); // TODO: 1:many jalview alignment sequence annotations
+ if (asa == null)
+ {
+ int se[] = getBounds(vasannot[a]);
+ asa = getjAlignmentAnnotation(jal, vasannot[a]);
+ asa.sequenceRef = alseq;
+ asa.createSequenceMapping(alseq, alseq.getStart() + se[0], false); // TODO: verify that positions in alseqAnnotation correspond to ungapped residue positions.
+ bindjvvobj(asa, vasannot[a]);
+ newasAnnots.add(asa);
+ }
+ else
+ {
+ // update existing annotation - can do this in place
+ if (vasannot[a].getModifiable())
+ {
+ Cache.log.info(
+ "UNIMPLEMENTED: not recovering user modifiable sequence alignment annotation");
+ // TODO: should at least replace with new one - otherwise things will break
+ // basically do this:
+ // int se[] = getBounds(vasannot[a]);
+ // asa.update(getjAlignmentAnnotation(jal, vasannot[a])); // update from another annotation object in place.
+ // asa.createSequenceMapping(alseq, se[0], false);
+
+ }
+ }
+ }
+ }
+ }
+ if (jal == null)
+ {
+ SequenceI[] seqs = new SequenceI[dsseqs.size()];
+ for (i = 0, iSize = dsseqs.size(); i < iSize; i++)
+ {
+ seqs[i] = (SequenceI) dsseqs.elementAt(i);
+ dsseqs.setElementAt(null, i);
+ }
+ jal = new jalview.datamodel.Alignment(seqs);
+ Cache.log.debug("New vamsas alignment imported into jalview " +
+ alignment.getVorbaId().getId());
+ jal.setDataset(jdataset);
+ }
+ if (newasAnnots != null && newasAnnots.size() > 0)
+ {
+ // Add the new sequence annotations in to the alignment.
+ for (int an = 0, anSize = newasAnnots.size(); an < anSize; an++)
+ {
+ jal.addAnnotation( (AlignmentAnnotation) newasAnnots.elementAt(
+ an));
+ // TODO: check if anything has to be done - like calling adjustForAlignment or something.
+ newasAnnots.setElementAt(null, an);
+ }
+ newasAnnots = null;
+ }
+ // //////////////////////////////////////////
+ // //LOAD ANNOTATIONS FOR THE ALIGNMENT
+ // ////////////////////////////////////
+ if (alignment.getAlignmentAnnotationCount() > 0)
+ {
+ org.vamsas.objects.core.AlignmentAnnotation[] an = alignment.
+ getAlignmentAnnotation();
+
+ for (int j = 0; j < an.length; j++)
+ {
+ jalview.datamodel.AlignmentAnnotation jan = (jalview.datamodel.
+ AlignmentAnnotation) getvObj2jv(an[j]);
+ if (jan != null)
+ {
+ // update or stay the same.
+ // TODO: should at least replace with a new one - otherwise things will break
+ // basically do this:
+ // jan.update(getjAlignmentAnnotation(jal, an[a])); // update from another annotation object in place.
+
+ Cache.log.debug("update from vamsas alignment annotation to existing jalview alignment annotation.");
+ if (an[j].getModifiable())
+ {
+ // TODO: user defined annotation is totally mutable... - so load it up or throw away if locally edited.
+ Cache.log.info(
+ "NOT IMPLEMENTED - Recovering user-modifiable annotation - yet...");
+ }
+ // TODO: compare annotation element rows
+ // TODO: compare props.
+ }
+ else
+ {
+ jan = getjAlignmentAnnotation(jal, an[j]);
+ jal.addAnnotation(jan);
+ bindjvvobj(jan, an[j]);
+ }
+ }
+ }
+ AlignFrame alignFrame;
+ if (av == null)
+ {
+ Cache.log.debug("New alignframe for alignment " +
+ alignment.getVorbaId());
+ // ///////////////////////////////
+ // construct alignment view
+ alignFrame = new AlignFrame(jal, AlignFrame.DEFAULT_WIDTH,
+ AlignFrame.DEFAULT_HEIGHT);
+ av = alignFrame.getViewport();
+ String title = alignment.getProvenance().getEntry(alignment.
+ getProvenance().getEntryCount() - 1).getAction();
+ if (alignment.getPropertyCount() > 0)
+ {
+ for (int p = 0, pe = alignment.getPropertyCount(); p < pe; p++)
+ {
+ if (alignment.getProperty(p).getName().equals(
+ "jalview:AlTitle"))
+ {
+ title = alignment.getProperty(p).getContent();
+ }
+ }
+ }
+ // TODO: automatically create meaningful title for a vamsas alignment using its provenance.
+ jalview.gui.Desktop.addInternalFrame(alignFrame,
+ title + "(" + alignment.getVorbaId() + ")",
+ AlignFrame.DEFAULT_WIDTH,
+ AlignFrame.DEFAULT_HEIGHT);
+ bindjvvobj(av, alignment);
+ }
+ else
+ {
+ // find the alignFrame for jal.
+ // TODO: fix this so we retrieve the alignFrame handing av *directly*
+ alignFrame = getAlignFrameFor(av);
+ }
+ // LOAD TREES
+ // /////////////////////////////////////
+ if (alignment.getTreeCount() > 0)
+ {
+
+ for (int t = 0; t < alignment.getTreeCount(); t++)
+ {
+ Tree tree = alignment.getTree(t);
+ TreePanel tp = (TreePanel) getvObj2jv(tree);
+ if (tp != null)
+ {
+ Cache.log.info(
+ "Update from vamsas document to alignment associated tree not implemented yet.");
+ }
+ else
+ {
+ // make a new tree
+ Object[] idata = this.recoverInputData(tree.getProvenance());
+ try
+ {
+ AlignmentView inputData = null;
+ if (idata != null && idata[0] != null)
+ {
+ inputData = (AlignmentView) idata[0];
+ }
+ tp = alignFrame.ShowNewickTree(
+ new jalview.io.NewickFile(tree.getNewick(0).getContent()),
+ tree.getNewick(0).getTitle() + " (" + tree.getVorbaId() +
+ ")", inputData,
+ 600, 500,
+ t * 20 + 50, t * 20 + 50);
+ bindjvvobj(tp, tree);
+ }
+ catch (Exception e)
+ {
+ Cache.log.warn("Problems parsing treefile '" +
+ tree.getNewick(0).getContent() + "'", e);
+ }
+ }
+ }
+ }
+
+ }
+ }
+ }
+ }
+ }
+
+ // bitfields - should be a template in j1.5
+ private static int HASSECSTR = 0;
+ private static int HASVALS = 1;
+ private static int HASHPHOB = 2;
+ private static int HASDC = 3;
+ private static int HASDESCSTR = 4;
+ private static int HASTWOSTATE = 5; // not used yet.
+ /**
+ * parses the AnnotationElements - if they exist - into jalview.datamodel.Annotation[] rows
+ * Two annotation rows are made if there are distinct annotation for both at 'pos' and 'after pos' at any particular site.
+ * @param annotation
+ * @return { boolean[static int constants ], int[ae.length] - map to annotated object frame, jalview.datamodel.Annotation[], jalview.datamodel.Annotation[] (after)}
+ */
+ private Object[] parseRangeAnnotation(org.vamsas.objects.core.RangeAnnotation
+ annotation)
+ {
+ // set these attributes by looking in the annotation to decide what kind of alignment annotation rows will be made
+ // TODO: potentially we might make several annotation rows from one vamsas alignment annotation. the jv2Vobj binding mechanism
+ // may not quite cope with this (without binding an array of annotations to a vamsas alignment annotation)
+ // summary flags saying what we found over the set of annotation rows.
+ boolean[] AeContent = new boolean[]
+ {
+ false, false, false, false, false};
+ int[] rangeMap = getMapping(annotation);
+ jalview.datamodel.Annotation[][] anot = new jalview.datamodel.Annotation[][]
+ {
+ new jalview.datamodel.Annotation[rangeMap.length],
+ new jalview.datamodel.Annotation[rangeMap.length]
+ };
+ boolean mergeable = true; //false if 'after positions cant be placed on same annotation row as positions.
+
+ if (annotation.getAnnotationElementCount() > 0)
+ {
+ AnnotationElement ae[] = annotation.getAnnotationElement();
+ for (int aa = 0; aa < ae.length; aa++)
+ {
+ int pos = ae[aa].getPosition() - 1; // pos counts from 1 to (|seg.start-seg.end|+1)
+ if (pos >= 0 && pos < rangeMap.length)
+ {
+ int row = ae[aa].getAfter() ? 1 : 0;
+ if (anot[row][pos] != null)
+ {
+ // only time this should happen is if the After flag is set.
+ Cache.log.debug("Ignoring duplicate annotation site at " + pos);
+ continue;
+ }
+ if (anot[1 - row][pos] != null)
+ {
+ mergeable = false;
+ }
+ String desc = "";
+ if (ae[aa].getDescription() != null)
+ {
+ desc = ae[aa].getDescription();
+ if (desc.length() > 0)
+ {
+ // have imported valid description string
+ AeContent[HASDESCSTR] = true;
+ }
+ }
+ String dc = null; //ae[aa].getDisplayCharacter()==null ? "dc" : ae[aa].getDisplayCharacter();
+ String ss = null; //ae[aa].getSecondaryStructure()==null ? "ss" : ae[aa].getSecondaryStructure();
+ java.awt.Color colour = null;
+ if (ae[aa].getGlyphCount() > 0)
+ {
+ Glyph[] glyphs = ae[aa].getGlyph();
+ for (int g = 0; g < glyphs.length; g++)
+ {
+ if (glyphs[g].getDict().equals(org.vamsas.objects.utils.
+ GlyphDictionary.PROTEIN_SS_3STATE))
+ {
+ ss = glyphs[g].getContent();
+ AeContent[HASSECSTR] = true;
+ }
+ else if (glyphs[g].getDict().equals(org.vamsas.objects.utils.
+ GlyphDictionary.
+ PROTEIN_HD_HYDRO))
+ {
+ Cache.log.debug("ignoring hydrophobicity glyph marker.");
+ AeContent[HASHPHOB] = true;
+ char c = (dc = glyphs[g].getContent()).charAt(0);
+ // dc may get overwritten - but we still set the colour.
+ colour = new java.awt.Color(c == '+' ? 255 : 0,
+ c == '.' ? 255 : 0,
+ c == '-' ? 255 : 0);
+
+ }
+ else if (glyphs[g].getDict().equals(org.vamsas.objects.utils.
+ GlyphDictionary.DEFAULT))
+ {
+ dc = glyphs[g].getContent();
+ AeContent[HASDC] = true;
+ }
+ else
+ {
+ Cache.log.debug("Ignoring unknown glyph type " +
+ glyphs[g].getDict());
+ }
+ }
+ }
+ float val = 0;
+ if (ae[aa].getValueCount() > 0)
+ {
+ AeContent[HASVALS] = true;
+ if (ae[aa].getValueCount() > 1)
+ {
+ Cache.log.warn("ignoring additional " +
+ (ae[aa].getValueCount() - 1) +
+ "values in annotation element.");
+ }
+ val = ae[aa].getValue(0);
+ }
+ if (colour == null)
+ {
+ anot[row][pos] = new jalview.datamodel.Annotation( (dc != null) ?
+ dc : "", desc, (ss != null) ? ss.charAt(0) : ' ', val);
+ }
+ else
+ {
+ anot[row][pos] = new jalview.datamodel.Annotation( (dc != null) ?
+ dc : "", desc, (ss != null) ? ss.charAt(0) : ' ', val, colour);
+ }
+ }
+ else
+ {
+ Cache.log.warn("Ignoring out of bound annotation element " + aa +
+ " in " + annotation.getVorbaId().getId());
+ }
+ }
+ // decide on how many annotation rows are needed.
+ if (mergeable)
+ {
+ for (int i = 0; i < anot[0].length; i++)
+ {
+ if (anot[1][i] != null)
+ {
+ anot[0][i] = anot[1][i];
+ anot[0][i].description = anot[0][i].description + " (after)";
+ AeContent[HASDESCSTR] = true; // we have valid description string data
+ anot[1][i] = null;
+ }
+ }
+ anot[1] = null;
+ }
+ else
+ {
+ for (int i = 0; i < anot[0].length; i++)
+ {
+ anot[1][i].description = anot[1][i].description + " (after)";
+ }
+ }
+ return new Object[]
+ {
+ AeContent, rangeMap, anot[0], anot[1]};
+ }
+ else
+ {
+ // no annotations to parse. Just return an empty annotationElement[] array.
+ return new Object[]
+ {
+ AeContent, rangeMap, anot[0], anot[1]};
+ }
+ // return null;
+ }
+
+ /**
+ * @param jal the jalview alignment to which the annotation will be attached (ideally - freshly updated from corresponding vamsas alignment)
+ * @param annotation
+ * @return unbound jalview alignment annotation object.
+ */
+ private jalview.datamodel.AlignmentAnnotation getjAlignmentAnnotation(jalview.
+ datamodel.AlignmentI jal,
+ org.vamsas.objects.core.RangeAnnotation annotation)
+ {
+ jalview.datamodel.AlignmentAnnotation jan = null;
+ if (annotation == null)
+ {
+ return null;
+ }
+ // boolean hasSequenceRef=annotation.getClass().equals(org.vamsas.objects.core.AlignmentSequenceAnnotation.class);
+ //boolean hasProvenance=hasSequenceRef || (annotation.getClass().equals(org.vamsas.objects.core.AlignmentAnnotation.class));
+ /*int se[] = getBounds(annotation);
+ if (se==null)
+ se=new int[] {0,jal.getWidth()-1};
+ */
+ Object[] parsedRangeAnnotation = parseRangeAnnotation(annotation);
+ String a_label = annotation.getLabel();
+ String a_descr = annotation.getDescription();
+ if (a_label == null || a_label.length() == 0)
+ {
+ a_label = annotation.getType();
+ if (a_label.length() == 0)
+ {
+ a_label = "Unamed annotation";
+ }
+ }
+ if (a_descr == null || a_descr.length() == 0)
+ {
+ a_descr = "Annotation of type '" + annotation.getType() + "'";
+ }
+ if (parsedRangeAnnotation == null)
+ {
+ Cache.log.debug(
+ "Inserting empty annotation row elements for a whole-alignment annotation.");
+
+ }
+ else
+ {
+ if (parsedRangeAnnotation[3] != null)
+ {
+ Cache.log.warn("Ignoring 'After' annotation row in " +
+ annotation.getVorbaId());
+ }
+ jalview.datamodel.Annotation[] arow = (jalview.datamodel.Annotation[])
+ parsedRangeAnnotation[2];
+ boolean[] has = (boolean[]) parsedRangeAnnotation[0];
+ // VAMSAS: getGraph is only on derived annotation for alignments - in this way its 'odd' - there is already an existing TODO about removing this flag as being redundant
+ /*if ((annotation.getClass().equals(org.vamsas.objects.core.AlignmentAnnotation.class) && ((org.vamsas.objects.core.AlignmentAnnotation)annotation).getGraph())
+ || (hasSequenceRef=true && ((org.vamsas.objects.core.AlignmentSequenceAnnotation)annotation).getGraph())) {
+ */
+ if (has[HASVALS])
+ {
+ // make bounds and automatic description strings for jalview user's benefit (these shouldn't be written back to vamsas document)
+ boolean first = true;
+ float min = 0, max = 1;
+ int lastval = 0;
+ for (int i = 0; i < arow.length; i++)
+ {
+ if (arow[i] != null)
+ {
+ if (i - lastval > 1)
+ {
+ // do some interpolation *between* points
+ if (arow[lastval] != null)
+ {
+ float interval = arow[i].value - arow[lastval].value;
+ interval /= i - lastval;
+ float base = arow[lastval].value;
+ for (int ip = lastval + 1, np = 0; ip < i; np++, ip++)
+ {
+ arow[ip] = new jalview.datamodel.Annotation("", "", ' ',
+ interval * np + base);
+ // NB - Interpolated points don't get a tooltip and description.
+ }
+ }
+ }
+ lastval = i;
+ // check range - shouldn't we have a min and max property in the annotation object ?
+ if (first)
+ {
+ min = max = arow[i].value;
+ first = false;
+ }
+ else
+ {
+ if (arow[i].value < min)
+ {
+ min = arow[i].value;
+ }
+ else if (arow[i].value > max)
+ {
+ max = arow[i].value;
+ }
+ }
+ // make tooltip and display char value
+ if (!has[HASDESCSTR])
+ {
+ arow[i].description = arow[i].value + "";
+ }
+ if (!has[HASDC])
+ {
+ arow[i].displayCharacter = arow[i].value + "";
+ }
+ }
+ }
+ int type = jalview.datamodel.AlignmentAnnotation.LINE_GRAPH;
+ if (has[HASHPHOB])
+ {
+ type = jalview.datamodel.AlignmentAnnotation.BAR_GRAPH;
+ }
+ jan = new jalview.datamodel.AlignmentAnnotation(a_label, a_descr, arow,
+ min, max, type);
+ }
+ else
+ {
+ jan = new jalview.datamodel.AlignmentAnnotation(a_label, a_descr, arow);
+ jan.setThreshold(null);
+ }
+ if (annotation.getLinkCount() > 0)
+ {
+ Cache.log.warn("Ignoring " + annotation.getLinkCount() +
+ "links added to AlignmentAnnotation.");
+ }
+ if (annotation.getModifiable())
+ {
+ jan.editable = true;
+ }
+
+ if (annotation.getPropertyCount() > 0)
+ {
+ // look for special jalview properties
+ org.vamsas.objects.core.Property[] props = annotation.getProperty();
+ for (int p = 0; p < props.length; p++)
+ {
+ if (props[p].getName().equalsIgnoreCase("jalview:graphType"))
+ {
+ try
+ {
+ // probably a jalview annotation graph so recover the visualization hints.
+ jan.graph = jalview.datamodel.AlignmentAnnotation.
+ getGraphValueFromString(props[p].getContent());
+ }
+ catch (Exception e)
+ {
+ Cache.log.debug(
+ "Invalid graph type value in jalview:graphType property.");
+ }
+ try
+ {
+ if (annotation.getGroup() != null &&
+ annotation.getGroup().length() > 0)
+ {
+ jan.graphGroup = Integer.parseInt(annotation.getGroup());
+ }
+ }
+ catch (Exception e)
+ {
+ Cache.log.info("UNIMPLEMENTED : Couldn't parse non-integer group value for setting graphGroup correctly.");
+ }
+ }
+ }
+ }
+
+ return jan;
+
+ }
+
+ return null;
+ }
+
+ private SequenceFeature getJalviewSeqFeature(RangeAnnotation dseta)
+ {
+ int[] se = getBounds(dseta);
+ SequenceFeature sf = new jalview.datamodel.SequenceFeature(dseta.getType(),
+ dseta.getDescription(), dseta.getStatus(), se[0], se[1], dseta
+ .getGroup());
+ if (dseta.getLinkCount() > 0)
+ {
+ Link[] links = dseta.getLink();
+ for (int i = 0; i < links.length; i++)
+ {
+ sf.addLink(links[i].getContent() + "|" + links[i].getHref());
+ }
+ }
+ return sf;
+ }
+
+ /**
+ * get real bounds of a RangeType's specification. start and end are an
+ * inclusive range within which all segments and positions lie.
+ * TODO: refactor to vamsas utils
+ * @param dseta
+ * @return int[] { start, end}
+ */
+ private int[] getBounds(RangeType dseta)
+ {
+ if (dseta != null)
+ {
+ int[] se = null;
+ if (dseta.getSegCount() > 0 && dseta.getPosCount() > 0)
+ {
+ throw new Error("Invalid vamsas RangeType - cannot resolve both lists of Pos and Seg from choice!");
+ }
+ if (dseta.getSegCount() > 0)
+ {
+ se = getSegRange(dseta.getSeg(0), true);
+ for (int s = 1, sSize = dseta.getSegCount(); s < sSize; s++)
+ {
+ int nse[] = getSegRange(dseta.getSeg(s), true);
+ if (se[0] > nse[0])
+ {
+ se[0] = nse[0];
+ }
+ if (se[1] < nse[1])
+ {
+ se[1] = nse[1];
+ }
+ }
+ }
+ if (dseta.getPosCount() > 0)
+ {
+ // could do a polarity for pos range too. and pass back indication of discontinuities.
+ int pos = dseta.getPos(0).getI();
+ se = new int[]
+ {
+ pos, pos};
+ for (int p = 0, pSize = dseta.getPosCount(); p < pSize; p++)
+ {
+ pos = dseta.getPos(p).getI();
+ if (se[0] > pos)
+ {
+ se[0] = pos;
+ }
+ if (se[1] < pos)
+ {
+ se[1] = pos;
+ }
+ }
+ }
+ return se;
+ }
+ return null;
+ }
+
+ /**
+ * map from a rangeType's internal frame to the referenced object's coordinate frame.
+ * @param dseta
+ * @return int [] { ref(pos)...} for all pos in rangeType's frame.
+ */
+ private int[] getMapping(RangeType dseta)
+ {
+ Vector posList = new Vector();
+ if (dseta != null)
+ {
+ int[] se = null;
+ if (dseta.getSegCount() > 0 && dseta.getPosCount() > 0)
+ {
+ throw new Error("Invalid vamsas RangeType - cannot resolve both lists of Pos and Seg from choice!");
+ }
+ if (dseta.getSegCount() > 0)
+ {
+ for (int s = 0, sSize = dseta.getSegCount(); s < sSize; s++)
+ {
+ se = getSegRange(dseta.getSeg(s), false);
+ int se_end = se[1 - se[2]] + (se[2] == 0 ? 1 : -1);
+ for (int p = se[se[2]]; p != se_end; p += se[2] == 0 ? 1 : -1)
+ {
+ posList.add(new Integer(p));
+ }
+ }
+ }
+ else if (dseta.getPosCount() > 0)
+ {
+ int pos = dseta.getPos(0).getI();
+
+ for (int p = 0, pSize = dseta.getPosCount(); p < pSize; p++)
+ {
+ pos = dseta.getPos(p).getI();
+ posList.add(new Integer(pos));
+ }
+ }
+ }
+ if (posList != null && posList.size() > 0)
+ {
+ int[] range = new int[posList.size()];
+ for (int i = 0; i < range.length; i++)
+ {
+ range[i] = ( (Integer) posList.elementAt(i)).intValue();
+ }
+ posList.clear();
+ return range;
+ }
+ return null;
+ }
+
+ /* not needed now.
+ * Provenance getVamsasProvenance(jalview.datamodel.Provenance jprov) {
+ jalview.datamodel.ProvenanceEntry[] entries = null;
+ // TODO: fix App and Action here.
+ Provenance prov = new Provenance();
+ org.exolab.castor.types.Date date = new org.exolab.castor.types.Date(
+ new java.util.Date());
+ Entry provEntry;
+
+ if (jprov != null)
+ {
+ entries = jprov.getEntries();
+ for (int i = 0; i < entries.length; i++)
+ {
+ provEntry = new Entry();
+ try
+ {
+ date = new org.exolab.castor.types.Date(entries[i].getDate());
+ } catch (Exception ex)
+ {
+ ex.printStackTrace();
+
+ date = new org.exolab.castor.types.Date(entries[i].getDate());
+ }
+ provEntry.setDate(date);
+ provEntry.setUser(entries[i].getUser());
+ provEntry.setAction(entries[i].getAction());
+ prov.addEntry(provEntry);
+ }
+ }
+ else
+ {
+ provEntry = new Entry();
+ provEntry.setDate(date);
+ provEntry.setUser(System.getProperty("user.name")); // TODO: ext string
+ provEntry.setApp("JVAPP"); // TODO: ext string
+ provEntry.setAction(action);
+ prov.addEntry(provEntry);
+ }
+
+ return prov;
+ }
+ */
+ jalview.datamodel.Provenance getJalviewProvenance(Provenance prov)
+ {
+ // TODO: fix App and Action entries and check use of provenance in jalview.
+ jalview.datamodel.Provenance jprov = new jalview.datamodel.Provenance();
+ for (int i = 0; i < prov.getEntryCount(); i++)
+ {
+ jprov.addEntry(prov.getEntry(i).getUser(), prov.getEntry(i).getAction(),
+ prov.getEntry(i).getDate().toDate(),
+ prov.getEntry(i).getId());
+ }
+
+ return jprov;
+ }
+
+ /**
+ *
+ * @return default initial provenance list for a Jalview created vamsas
+ * object.
+ */
+ Provenance dummyProvenance()
+ {
+ return dummyProvenance(null);
+ }
+
+ Entry dummyPEntry(String action)
+ {
+ Entry entry = new Entry();
+ entry.setApp(this.provEntry.getApp());
+ if (action != null)
+ {
+ entry.setAction(action);
+ }
+ else
+ {
+ entry.setAction("created.");
+ }
+ entry.setDate(new org.exolab.castor.types.Date(new java.util.Date()));
+ entry.setUser(this.provEntry.getUser());
+ return entry;
+ }
+
+ Provenance dummyProvenance(String action)
+ {
+ Provenance prov = new Provenance();
+ prov.addEntry(dummyPEntry(action));
+ return prov;
+ }
+
+ void addProvenance(Provenance p, String action)
+ {
+ p.addEntry(dummyPEntry(action));
+ }
+
+}
diff --git a/src/jalview/schemes/ScoreMatrix.java b/src/jalview/schemes/ScoreMatrix.java
new file mode 100644
index 0000000..69a0922
--- /dev/null
+++ b/src/jalview/schemes/ScoreMatrix.java
@@ -0,0 +1,67 @@
+package jalview.schemes;
+
+public class ScoreMatrix
+{
+ String name;
+ /**
+ * reference to integer score matrix
+ */
+ int[][] matrix;
+ /**
+ * 0 for Protein Score matrix. 1 for dna score matrix
+ */
+ int type;
+ ScoreMatrix(String name, int[][] matrix, int type)
+ {
+ this.matrix = matrix;
+ this.type = type;
+ }
+
+ public boolean isDNA()
+ {
+ return type == 1;
+ }
+
+ public boolean isProtein()
+ {
+ return type == 0;
+ }
+
+ public int[][] getMatrix()
+ {
+ return matrix;
+ }
+
+ /**
+ *
+ * @param A1
+ * @param A2
+ * @return score for substituting first char in A1 with first char in A2
+ */
+ public int getPairwiseScore(String A1, String A2)
+ {
+ return getPairwiseScore(A1.charAt(0), A2.charAt(0));
+ }
+
+ public int getPairwiseScore(char c, char d)
+ {
+ int pog = 0;
+
+ try
+ {
+ int a = (type == 0) ? ResidueProperties.aaIndex[c] :
+ ResidueProperties.nucleotideIndex[c];
+ int b = (type == 0) ? ResidueProperties.aaIndex[d] :
+ ResidueProperties.nucleotideIndex[d];
+
+ pog = matrix[a][b];
+ }
+ catch (Exception e)
+ {
+ //System.out.println("Unknown residue in " + A1 + " " + A2);
+ }
+
+ return pog;
+ }
+
+}
diff --git a/src/jalview/util/MapList.java b/src/jalview/util/MapList.java
new file mode 100644
index 0000000..215ece9
--- /dev/null
+++ b/src/jalview/util/MapList.java
@@ -0,0 +1,395 @@
+/*
+ * Jalview - A Sequence Alignment Editor and Viewer
+ * Copyright (C) 2007 AM Waterhouse, J Procter, G Barton, M Clamp, S Searle
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+package jalview.util;
+
+import java.util.*;
+
+/**
+ * MapList
+ * Simple way of bijectively mapping a non-contiguous linear range to another non-contiguous linear range
+ * Use at your own risk!
+ * TODO: efficient implementation of private posMap method
+ * TODO: test/ensure that sense of from and to ratio start position is conserved (codon start position recovery)
+ * TODO: optimize to use int[][] arrays rather than vectors.
+ */
+public class MapList
+{
+ public Vector fromShifts;
+ public Vector toShifts;
+ int fromRatio; // number of steps in fromShifts to one toRatio unit
+ int toRatio; // number of steps in toShifts to one fromRatio
+ public MapList(int from[], int to[], int fromRatio, int toRatio)
+ {
+ fromShifts = new Vector();
+ for (int i = 0; i < from.length; i += 2)
+ {
+ fromShifts.add(new int[]
+ {from[i], from[i + 1]});
+ }
+ toShifts = new Vector();
+ for (int i = 0; i < to.length; i += 2)
+ {
+ toShifts.add(new int[]
+ {to[i], to[i + 1]});
+ }
+ this.fromRatio = fromRatio;
+ this.toRatio = toRatio;
+ }
+
+ /**
+ * get all mapped positions from 'from' to 'to'
+ * @return int[][] { int[] { fromStart, fromFinish, toStart, toFinish }, int [fromFinish-fromStart+2] { toStart..toFinish mappings}}
+ */
+ public int[][] makeFromMap()
+ {
+ return posMap(fromShifts, fromRatio, toShifts, toRatio);
+ }
+
+ /**
+ * get all mapped positions from 'to' to 'from'
+ * @return int[to position]=position mapped in from
+ */
+ public int[][] makeToMap()
+ {
+ return posMap(toShifts, toRatio, fromShifts, fromRatio);
+ }
+
+ /**
+ * construct an int map for intervals in intVals
+ * @param intVals
+ * @return int[] { from, to pos in range }, int[range.to-range.from+1] returning mapped position
+ */
+ private int[][] posMap(Vector intVals, int ratio, Vector toIntVals,
+ int toRatio)
+ {
+ Iterator iv = intVals.iterator();
+ if (!iv.hasNext())
+ {
+ return null;
+ }
+ int[] intv = (int[]) iv.next();
+ int from = intv[0], to = intv[1];
+ if (from > to)
+ {
+ from = intv[1];
+ to = intv[0];
+ }
+ while (iv.hasNext())
+ {
+ intv = (int[]) iv.next();
+ if (intv[0] < from)
+ {
+ from = intv[0];
+ }
+ if (intv[1] < from)
+ {
+ from = intv[1];
+ }
+ if (intv[0] > to)
+ {
+ to = intv[0];
+ }
+ if (intv[1] > to)
+ {
+ to = intv[1];
+ }
+ }
+ int tF = 0, tT = 0;
+ int mp[][] = new int[to - from + 2][];
+ for (int i = 0; i < mp.length; i++)
+ {
+ int[] m = shift(i + from, intVals, ratio, toIntVals, toRatio);
+ if (m != null)
+ {
+ if (i == 0)
+ {
+ tF = tT = m[0];
+ }
+ else
+ {
+ if (m[0] < tF)
+ {
+ tF = m[0];
+ }
+ if (m[0] > tT)
+ {
+ tT = m[0];
+ }
+ }
+ }
+ mp[i] = m;
+ }
+ int[][] map = new int[][]
+ {
+ new int[]
+ {
+ from, to, tF, tT}, new int[to - from + 2]};
+
+ map[0][2] = tF;
+ map[0][3] = tT;
+
+ for (int i = 0; i < mp.length; i++)
+ {
+ if (mp[i] != null)
+ {
+ map[1][i] = mp[i][0] - tF;
+ }
+ else
+ {
+ map[1][i] = -1; // indicates an out of range mapping
+ }
+ }
+ return map;
+ }
+
+ /**
+ * addShift
+ * @param pos start position for shift (in original reference frame)
+ * @param shift length of shift
+ *
+ public void addShift(int pos, int shift)
+ {
+ int sidx = 0;
+ int[] rshift=null;
+ while (sidx= intv[0] && pos <= intv[1])
+ {
+ return new int[]
+ {
+ count + pos - intv[0] + 1, +1};
+ }
+ else
+ {
+ count += intv[1] - intv[0] + 1;
+ }
+ }
+ else
+ {
+ if (pos >= intv[1] && pos <= intv[0])
+ {
+ return new int[]
+ {
+ count + intv[0] - pos + 1, -1};
+ }
+ else
+ {
+ count += intv[0] - intv[1] + 1;
+ }
+ }
+ }
+ return null;
+ }
+
+ /**
+ * count out pos positions into a series of intervals and return the position
+ * @param intVals
+ * @param pos
+ * @return position pos in interval set
+ */
+ private int[] countToPos(Iterator intVals, int pos)
+ {
+ int count = 0, diff = 0, intv[] =
+ {
+ 0, 0};
+ while (intVals.hasNext())
+ {
+ intv = (int[]) intVals.next();
+ diff = intv[1] - intv[0];
+ if (diff >= 0)
+ {
+ if (pos <= count + 1 + diff)
+ {
+ return new int[]
+ {
+ pos - count - 1 + intv[0], +1};
+ }
+ else
+ {
+ count += 1 + diff;
+ }
+ }
+ else
+ {
+ if (pos <= count + 1 - diff)
+ {
+ return new int[]
+ {
+ intv[0] - (pos - count - 1), -1};
+ }
+ else
+ {
+ count += 1 - diff;
+ }
+ }
+ }
+ return null; //(diff<0) ? (intv[1]-1) : (intv[0]+1);
+ }
+
+ public static void testMap(MapList ml, int fromS, int fromE)
+ {
+ for (int from = 1; from <= 25; from++)
+ {
+ int[] too = ml.shiftFrom(from);
+ System.out.print("ShiftFrom(" + from + ")==");
+ if (too == null)
+ {
+ System.out.print("NaN\n");
+ }
+ else
+ {
+ System.out.print(too[0] + " % " + too[1]);
+ System.out.print("\t+--+\t");
+ int[] toofrom = ml.shiftTo(too[0]);
+ if (toofrom != null)
+ {
+ if (toofrom[0] != from)
+ {
+ System.err.println("Mapping not reflexive:" + from + " " + too[0] +
+ "->" + toofrom[0]);
+ }
+ System.out.println("ShiftTo(" + too[0] + ")==" + toofrom[0] + " % " +
+ toofrom[1]);
+ }
+ else
+ {
+ System.out.println("ShiftTo(" + too[0] + ")==" +
+ "NaN! - not Bijective Mapping!");
+ }
+ }
+ }
+ int mmap[][] = ml.makeFromMap();
+ System.out.println("FromMap : (" + mmap[0][0] + " " + mmap[0][1] + " " +
+ mmap[0][2] + " " + mmap[0][3] + " ");
+ for (int i = 1; i <= mmap[1].length; i++)
+ {
+ if (mmap[1][i - 1] == -1)
+ {
+ System.out.print(i + "=XXX");
+
+ }
+ else
+ {
+ System.out.print(i + "=" + (mmap[0][2] + mmap[1][i - 1]));
+ }
+ if (i % 20 == 0)
+ {
+ System.out.print("\n");
+ }
+ else
+ {
+ System.out.print(",");
+ }
+ }
+ System.out.print("\n");
+ }
+
+ public static void main(String argv[])
+ {
+ MapList ml = new MapList(new int[]
+ {1, 5, 10, 15, 25, 20},
+ new int[]
+ {51, 1}, 1, 3);
+ MapList ml1 = new MapList(new int[]
+ {1, 3, 17, 4},
+ new int[]
+ {51, 1}, 1, 3);
+
+ // test internal consistency
+ int to[] = new int[51];
+ MapList.testMap(ml, 1, 25);
+ /*
+ for (int from=1; from<=51; from++) {
+ int[] too=ml.shiftTo(from);
+ int[] toofrom=ml.shiftFrom(too[0]);
+ System.out.println("ShiftFrom("+from+")=="+too[0]+" % "+too[1]+"\t+-+\tShiftTo("+too[0]+")=="+toofrom[0]+" % "+toofrom[1]);
+ }*/
+ System.out.print("Success?\n"); // if we get here - something must be working!
+ }
+}
diff --git a/src/jalview/ws/JPredThread.java b/src/jalview/ws/JPredThread.java
new file mode 100644
index 0000000..0cac709
--- /dev/null
+++ b/src/jalview/ws/JPredThread.java
@@ -0,0 +1,634 @@
+package jalview.ws;
+
+import java.util.*;
+
+import jalview.analysis.*;
+import jalview.bin.*;
+import jalview.datamodel.*;
+import jalview.datamodel.Alignment;
+import jalview.gui.*;
+import jalview.io.*;
+import jalview.util.*;
+import vamsas.objects.simple.JpredResult;
+
+class JPredThread
+ extends WSThread implements WSClientI
+{
+ // TODO: put mapping between JPredJob input and input data here - JNetAnnotation adding is done after result parsing.
+ class JPredJob
+ extends WSThread.WSJob
+ {
+ // TODO: make JPredJob deal only with what was sent to and received from a JNet service
+ int[] predMap = null; // mapping from sequence(i) to the original sequence(predMap[i]) being predicted on
+ vamsas.objects.simple.Sequence sequence;
+ vamsas.objects.simple.Msfalignment msa;
+ java.util.Hashtable SequenceInfo = null;
+ int msaIndex = 0; // the position of the original sequence in the array of Sequences in the input object that this job holds a prediction for
+ /**
+ *
+ * @return true if getResultSet will return a valid alignment and prediction result.
+ */
+ public boolean hasResults()
+ {
+ if (subjobComplete && result != null && result.isFinished()
+ && ( (JpredResult) result).getPredfile() != null &&
+ ( (JpredResult) result).getAligfile() != null)
+ {
+ return true;
+ }
+ return false;
+ }
+
+ boolean hasValidInput()
+ {
+ if (sequence != null)
+ {
+ return true;
+ }
+ return false;
+ }
+
+ /**
+ *
+ * @return null or Object[] { annotated alignment for this prediction, ColumnSelection for this prediction} or null if no results available.
+ * @throws Exception
+ */
+ public Object[] getResultSet()
+ throws Exception
+ {
+ if (result == null || !result.isFinished())
+ {
+ return null;
+ }
+ Alignment al = null;
+ ColumnSelection alcsel = null;
+ int FirstSeq = -1; // the position of the query sequence in Alignment al
+
+ JpredResult result = (JpredResult)this.result;
+
+ jalview.bin.Cache.log.debug("Parsing output from JNet job.");
+ // JPredFile prediction = new JPredFile("C:/JalviewX/files/jpred.txt", "File");
+ jalview.io.JPredFile prediction = new jalview.io.JPredFile(result.
+ getPredfile(),
+ "Paste");
+ SequenceI[] preds = prediction.getSeqsAsArray();
+ jalview.bin.Cache.log.debug("Got prediction profile.");
+
+ if ( (this.msa != null) && (result.getAligfile() != null))
+ {
+ jalview.bin.Cache.log.debug("Getting associated alignment.");
+ // we ignore the returned alignment if we only predicted on a single sequence
+ String format = new jalview.io.IdentifyFile().Identify(result.
+ getAligfile(),
+ "Paste");
+
+ if (jalview.io.FormatAdapter.isValidFormat(format))
+ {
+ SequenceI sqs[];
+ if (predMap != null)
+ {
+ Object[] alandcolsel = input.getAlignmentAndColumnSelection(
+ alignFrame.getViewport().getGapCharacter());
+ sqs = (SequenceI[]) alandcolsel[0];
+ al = new Alignment(sqs);
+ alcsel = (ColumnSelection) alandcolsel[1];
+ }
+ else
+ {
+ al = new FormatAdapter().readFile(result.getAligfile(),
+ "Paste", format);
+ sqs = new SequenceI[al.getHeight()];
+
+ for (int i = 0, j = al.getHeight(); i < j; i++)
+ {
+ sqs[i] = al.getSequenceAt(i);
+ }
+ if (!jalview.analysis.SeqsetUtils.deuniquify( (Hashtable)
+ SequenceInfo, sqs))
+ {
+ throw (new Exception(
+ "Couldn't recover sequence properties for alignment."));
+ }
+ }
+ FirstSeq = 0;
+ al.setDataset(null);
+
+ jalview.io.JnetAnnotationMaker.add_annotation(prediction, al,
+ FirstSeq,
+ false, predMap);
+
+ }
+ else
+ {
+ throw (new Exception(
+ "Unknown format " + format + " for file : \n" +
+ result.getAligfile()));
+ }
+ }
+ else
+ {
+ al = new Alignment(preds);
+ FirstSeq = prediction.getQuerySeqPosition();
+ if (predMap != null)
+ {
+ char gc = alignFrame.getViewport().getGapCharacter();
+ SequenceI[] sqs = (SequenceI[]) ( (java.lang.Object[]) input.
+ getAlignmentAndColumnSelection(gc))[
+ 0];
+ if (this.msaIndex >= sqs.length)
+ {
+ throw new Error("Implementation Error! Invalid msaIndex for JPredJob on parent MSA input object!");
+ }
+
+ /////
+ //Uses RemoveGapsCommand
+ /////
+ new jalview.commands.RemoveGapsCommand("Remove Gaps",
+ new SequenceI[]
+ {sqs[msaIndex]},
+ alignFrame.getCurrentView().
+ getAlignment());
+
+ SequenceI profileseq = al.getSequenceAt(FirstSeq);
+ profileseq.setSequence(sqs[msaIndex].getSequenceAsString());
+ }
+
+ if (!jalview.analysis.SeqsetUtils.SeqCharacterUnhash(
+ al.getSequenceAt(FirstSeq), SequenceInfo))
+ {
+ throw (new Exception(
+ "Couldn't recover sequence properties for JNet Query sequence!"));
+ }
+ else
+ {
+ al.setDataset(null);
+ jalview.io.JnetAnnotationMaker.add_annotation(prediction, al,
+ FirstSeq,
+ true, predMap);
+ SequenceI profileseq = al.getSequenceAt(0); // this includes any gaps.
+ alignToProfileSeq(al, profileseq);
+ if (predMap != null)
+ {
+ // Adjust input view for gaps
+ // propagate insertions into profile
+ alcsel = propagateInsertions(profileseq, al, input);
+ }
+ }
+ }
+ return new Object[]
+ {
+ al, alcsel}; // , FirstSeq, noMsa};
+ }
+
+ /**
+ * Given an alignment where all other sequences except profileseq are aligned to the ungapped profileseq, insert gaps in the other sequences to realign them with the residues in profileseq
+ * @param al
+ * @param profileseq
+ */
+ private void alignToProfileSeq(Alignment al, SequenceI profileseq)
+ {
+ char gc = al.getGapCharacter();
+ int[] gapMap = profileseq.gapMap();
+ // insert gaps into profile
+ for (int lp = 0, r = 0; r < gapMap.length; r++)
+ {
+ if (gapMap[r] - lp > 1)
+ {
+ StringBuffer sb = new StringBuffer();
+ for (int s = 0, ns = gapMap[r] - lp; s < ns; s++)
+ {
+ sb.append(gc);
+ }
+ for (int s = 1, ns = al.getHeight(); s < ns; s++)
+ {
+ String sq = al.getSequenceAt(s).getSequenceAsString();
+ int diff = gapMap[r] - sq.length();
+ if (diff > 0)
+ {
+ // pad gaps
+ sq = sq + sb;
+ while ( (diff = gapMap[r] - sq.length()) > 0)
+ {
+ sq = sq +
+ ( (diff >= sb.length()) ? sb.toString() :
+ sb.substring(0, diff));
+ }
+ al.getSequenceAt(s).setSequence(sq);
+ }
+ else
+ {
+ al.getSequenceAt(s).setSequence(sq.substring(0, gapMap[r]) +
+ sb.toString() +
+ sq.substring(gapMap[r]));
+ }
+ }
+ }
+ lp = gapMap[r];
+ }
+ }
+
+ /**
+ * Add gaps into the sequences aligned to profileseq under the given AlignmentView
+ * @param profileseq
+ * @param al
+ * @param input
+ */
+ private ColumnSelection propagateInsertions(SequenceI profileseq,
+ Alignment al,
+ AlignmentView input)
+ {
+ char gc = al.getGapCharacter();
+ Object[] alandcolsel = input.getAlignmentAndColumnSelection(gc);
+ ColumnSelection nview = (ColumnSelection) alandcolsel[1];
+ SequenceI origseq;
+ nview.pruneDeletions(ShiftList.parseMap( (origseq = ( (SequenceI[])
+ alandcolsel[0])[0]).gapMap())); // recover original prediction sequence's mapping to view.
+ int[] viscontigs = nview.getVisibleContigs(0, profileseq.getLength());
+ int spos = 0;
+ int offset = 0;
+ // input.pruneDeletions(ShiftList.parseMap(((SequenceI[]) alandcolsel[0])[0].gapMap()))
+ // add profile to visible contigs
+ for (int v = 0; v < viscontigs.length; v += 2)
+ {
+ if (viscontigs[v] > spos)
+ {
+ StringBuffer sb = new StringBuffer();
+ for (int s = 0, ns = viscontigs[v] - spos; s < ns; s++)
+ {
+ sb.append(gc);
+ }
+ for (int s = 0, ns = al.getHeight(); s < ns; s++)
+ {
+ SequenceI sqobj = al.getSequenceAt(s);
+ if (sqobj != profileseq)
+ {
+ String sq = al.getSequenceAt(s).getSequenceAsString();
+ if (sq.length() <= spos + offset)
+ {
+ // pad sequence
+ int diff = spos + offset - sq.length() - 1;
+ if (diff > 0)
+ {
+ // pad gaps
+ sq = sq + sb;
+ while ( (diff = spos + offset - sq.length() - 1) > 0)
+ {
+ sq = sq +
+ ( (diff >= sb.length()) ? sb.toString() :
+ sb.substring(0, diff));
+ }
+ }
+ sq += sb.toString();
+ }
+ else
+ {
+ al.getSequenceAt(s).setSequence(sq.substring(0, spos + offset) +
+ sb.toString() +
+ sq.substring(spos + offset));
+ }
+ }
+ }
+ //offset+=sb.length();
+ }
+ spos = viscontigs[v + 1] + 1;
+ }
+ if ( (offset + spos) < profileseq.getLength())
+ {
+ StringBuffer sb = new StringBuffer();
+ for (int s = 0, ns = profileseq.getLength() - spos - offset; s < ns; s++)
+ {
+ sb.append(gc);
+ }
+ for (int s = 1, ns = al.getHeight(); s < ns; s++)
+ {
+ String sq = al.getSequenceAt(s).getSequenceAsString();
+ // pad sequence
+ int diff = origseq.getLength() - sq.length();
+ while (diff > 0)
+ {
+ sq = sq +
+ ( (diff >= sb.length()) ? sb.toString() : sb.substring(0, diff));
+ diff = origseq.getLength() - sq.length();
+ }
+ }
+ }
+ return nview;
+ }
+
+ public JPredJob(Hashtable SequenceInfo, SequenceI seq, int[] delMap)
+ {
+ super();
+ this.predMap = delMap;
+ String sq = AlignSeq.extractGaps(Comparison.GapChars,
+ seq.getSequenceAsString());
+ if (sq.length() >= 20)
+ {
+ this.SequenceInfo = SequenceInfo;
+ sequence = new vamsas.objects.simple.Sequence();
+ sequence.setId(seq.getName());
+ sequence.setSeq(sq);
+ }
+ }
+
+ public JPredJob(Hashtable SequenceInfo, SequenceI[] msf, int[] delMap)
+ {
+ this(SequenceInfo, msf[0], delMap);
+ if (sequence != null)
+ {
+ if (msf.length > 1)
+ {
+ msa = new vamsas.objects.simple.Msfalignment();
+ jalview.io.PileUpfile pileup = new jalview.io.PileUpfile();
+ msa.setMsf(pileup.print(msf));
+ }
+ }
+ }
+ }
+
+ ext.vamsas.Jpred server;
+ String altitle = "";
+ JPredThread(WebserviceInfo wsinfo, String altitle, ext.vamsas.Jpred server,
+ String wsurl, AlignmentView alview, AlignFrame alframe)
+ {
+ super();
+ this.altitle = altitle;
+ this.server = server;
+ this.wsInfo = wsinfo;
+ this.input = alview;
+ this.alignFrame = alframe;
+ WsUrl = wsurl;
+ }
+
+ JPredThread(WebserviceInfo wsinfo, String altitle, ext.vamsas.Jpred server,
+ String wsurl, Hashtable SequenceInfo, SequenceI seq, int[] delMap,
+ AlignmentView alview, AlignFrame alframe)
+ {
+ this(wsinfo, altitle, server, wsurl, alview, alframe);
+ JPredJob job = new JPredJob(SequenceInfo, seq, delMap);
+ if (job.hasValidInput())
+ {
+ OutputHeader = wsInfo.getProgressText();
+ jobs = new WSJob[]
+ {
+ job};
+ job.jobnum = 0;
+ }
+ }
+
+ JPredThread(WebserviceInfo wsinfo, String altitle, ext.vamsas.Jpred server,
+ Hashtable SequenceInfo, SequenceI[] msf, int[] delMap,
+ AlignmentView alview, AlignFrame alframe, String wsurl)
+ {
+ this(wsinfo, altitle, server, wsurl, alview, alframe);
+ JPredJob job = new JPredJob(SequenceInfo, msf, delMap);
+ if (job.hasValidInput())
+ {
+ jobs = new WSJob[]
+ {
+ job};
+ OutputHeader = wsInfo.getProgressText();
+ job.jobnum = 0;
+ }
+ }
+
+ void StartJob(WSJob j)
+ {
+ if (! (j instanceof JPredJob))
+ {
+ throw new Error("Implementation error - StartJob(JpredJob) called on " +
+ j.getClass());
+ }
+ try
+ {
+ JPredJob job = (JPredJob) j;
+ if (job.msa != null)
+ {
+ job.jobId = server.predictOnMsa(job.msa);
+ }
+ else
+ if (job.sequence != null)
+ {
+ job.jobId = server.predict(job.sequence); // debug like : job.jobId = "/jobs/www-jpred/jp_Yatat29";//
+ }
+
+ if (job.jobId != null)
+ {
+ if (job.jobId.startsWith("Broken"))
+ {
+ job.result = (vamsas.objects.simple.Result)new JpredResult();
+ job.result.setInvalid(true);
+ job.result.setStatus("Submission " + job.jobId);
+ }
+ else
+ {
+ job.submitted = true;
+ job.subjobComplete = false;
+ Cache.log.info(WsUrl + " Job Id '" + job.jobId + "'");
+ }
+ }
+ else
+ {
+ throw new Exception("Server timed out - try again later\n");
+ }
+ }
+ catch (Exception e)
+ {
+ if (e.getMessage().indexOf("Exception") > -1)
+ {
+ wsInfo.setStatus(j.jobnum, WebserviceInfo.STATE_STOPPED_SERVERERROR);
+ wsInfo.setProgressText(j.jobnum,
+ "Failed to submit the prediction. (Just close the window)\n"
+ +
+ "It is most likely that there is a problem with the server.\n");
+ System.err.println(
+ "JPredWS Client: Failed to submit the prediction. Quite possibly because of a server error - see below)\n" +
+ e.getMessage() + "\n");
+
+ jalview.bin.Cache.log.warn("Server Exception", e);
+ }
+ else
+ {
+ wsInfo.setStatus(j.jobnum, WebserviceInfo.STATE_STOPPED_ERROR);
+ // JBPNote - this could be a popup informing the user of the problem.
+ wsInfo.appendProgressText(j.jobnum,
+ "Failed to submit the prediction:\n"
+ + e.getMessage() +
+ wsInfo.getProgressText());
+
+ jalview.bin.Cache.log.debug("Failed Submission of job " + j.jobnum, e);
+
+ }
+ j.allowedServerExceptions = -1;
+ j.subjobComplete = true;
+ }
+ }
+
+ void parseResult()
+ {
+ int results = 0; // number of result sets received
+ JobStateSummary finalState = new JobStateSummary();
+ try
+ {
+ for (int j = 0; j < jobs.length; j++)
+ {
+ finalState.updateJobPanelState(wsInfo, OutputHeader, jobs[j]);
+ if (jobs[j].submitted && jobs[j].subjobComplete && jobs[j].hasResults())
+ {
+ results++;
+ }
+ }
+ }
+ catch (Exception ex)
+ {
+
+ Cache.log.error("Unexpected exception when processing results for " +
+ altitle, ex);
+ wsInfo.setStatus(WebserviceInfo.STATE_STOPPED_ERROR);
+ }
+ if (results > 0)
+ {
+ wsInfo.showResultsNewFrame
+ .addActionListener(new java.awt.event.ActionListener()
+ {
+ public void actionPerformed(
+ java.awt.event.ActionEvent evt)
+ {
+ displayResults(true);
+ }
+ });
+ wsInfo.mergeResults
+ .addActionListener(new java.awt.event.ActionListener()
+ {
+ public void actionPerformed(
+ java.awt.event.ActionEvent evt)
+ {
+ displayResults(false);
+ }
+ });
+ wsInfo.setResultsReady();
+ }
+ else
+ {
+ wsInfo.setFinishedNoResults();
+ }
+ }
+
+ void displayResults(boolean newWindow)
+ {
+ // TODO: cope with multiple subjobs.
+ if (jobs != null)
+ {
+ Object[] res = null;
+ boolean msa = false;
+ for (int jn = 0; jn < jobs.length; jn++)
+ {
+ Object[] jobres = null;
+ JPredJob j = (JPredJob) jobs[jn];
+
+ if (j.hasResults())
+ {
+ // hack - we only deal with all single seuqence predictions or all profile predictions
+ msa = (j.msa != null) ? true : msa;
+ try
+ {
+ jalview.bin.Cache.log.debug("Parsing output of job " + jn);
+ jobres = j.getResultSet();
+ jalview.bin.Cache.log.debug("Finished parsing output.");
+ if (jobs.length == 1)
+ {
+ res = jobres;
+ }
+ else
+ {
+ // do merge with other job results
+ throw new Error(
+ "Multiple JNet subjob merging not yet implemented.");
+ }
+ }
+ catch (Exception e)
+ {
+ jalview.bin.Cache.log.error(
+ "JNet Client: JPred Annotation Parse Error",
+ e);
+ wsInfo.setStatus(j.jobnum, WebserviceInfo.STATE_STOPPED_ERROR);
+ wsInfo.appendProgressText(j.jobnum,
+ OutputHeader + "\n" +
+ j.result.getStatus() +
+ "\nInvalid JNet job result data!\n" +
+ e.getMessage());
+ j.result.setBroken(true);
+ }
+ }
+ }
+
+ if (res != null)
+ {
+ if (newWindow)
+ {
+ AlignFrame af;
+ if (input == null)
+ {
+ if (res[1] != null)
+ {
+ af = new AlignFrame( (Alignment) res[0], (ColumnSelection) res[1],
+ AlignFrame.DEFAULT_WIDTH,
+ AlignFrame.DEFAULT_HEIGHT);
+ }
+ else
+ {
+ af = new AlignFrame( (Alignment) res[0], AlignFrame.DEFAULT_WIDTH,
+ AlignFrame.DEFAULT_HEIGHT);
+ }
+ }
+ else
+ {
+ /*java.lang.Object[] alandcolsel = input.getAlignmentAndColumnSelection(alignFrame.getViewport().getGapCharacter());
+ if (((SequenceI[])alandcolsel[0])[0].getLength()!=res.getWidth()) {
+ if (msa) {
+ throw new Error("Implementation Error! ColumnSelection from input alignment will not map to result alignment!");
+ }
+ }
+ if (!msa) {
+ // update hidden regions to account for loss of gaps in profile. - if any
+ // gapMap returns insert list, interpreted as delete list by pruneDeletions
+ //((ColumnSelection) alandcolsel[1]).pruneDeletions(ShiftList.parseMap(((SequenceI[]) alandcolsel[0])[0].gapMap()));
+ }*/
+
+ af = new AlignFrame( (Alignment) res[0], (ColumnSelection) res[1],
+ AlignFrame.DEFAULT_WIDTH,
+ AlignFrame.DEFAULT_HEIGHT);
+ }
+ Desktop.addInternalFrame(af, altitle,
+ AlignFrame.DEFAULT_WIDTH,
+ AlignFrame.DEFAULT_HEIGHT);
+ }
+ else
+ {
+ Cache.log.info("Append results onto existing alignment.");
+ }
+ }
+ }
+ }
+
+ void pollJob(WSJob job)
+ throws Exception
+ {
+ job.result = server.getresult(job.jobId);
+ }
+
+ public boolean isCancellable()
+ {
+ return false;
+ }
+
+ public void cancelJob()
+ {
+ throw new Error("Implementation error!");
+ }
+
+ public boolean canMergeResults()
+ {
+ return false;
+ }
+
+}