+ @Override
+ public void run()
+ {
+ JvOptionPane
+ .showInternalMessageDialog(Desktop.desktop,
+ finalErrorMessage, "Error "
+ + (saving ? "saving" : "loading")
+ + " Jalview file",
+ JvOptionPane.WARNING_MESSAGE);
+ }
+ });
+ }
+ else
+ {
+ System.err.println("Problem loading Jalview file: " + errorMessage);
+ }
+ }
+ errorMessage = null;
+ }
+
+ Map<String, String> alreadyLoadedPDB = new HashMap<String, String>();
+
+ /**
+ * when set, local views will be updated from view stored in JalviewXML
+ * Currently (28th Sep 2008) things will go horribly wrong in vamsas document
+ * sync if this is set to true.
+ */
+ private final boolean updateLocalViews = false;
+
+ /**
+ * Returns the path to a temporary file holding the PDB file for the given PDB
+ * id. The first time of asking, searches for a file of that name in the
+ * Jalview project jar, and copies it to a new temporary file. Any repeat
+ * requests just return the path to the file previously created.
+ *
+ * @param jprovider
+ * @param pdbId
+ * @return
+ */
+ String loadPDBFile(jarInputStreamProvider jprovider, String pdbId,
+ String origFile)
+ {
+ if (alreadyLoadedPDB.containsKey(pdbId))
+ {
+ return alreadyLoadedPDB.get(pdbId).toString();
+ }
+
+ String tempFile = copyJarEntry(jprovider, pdbId, "jalview_pdb",
+ origFile);
+ if (tempFile != null)
+ {
+ alreadyLoadedPDB.put(pdbId, tempFile);
+ }
+ return tempFile;
+ }
+
+ /**
+ * Copies the jar entry of given name to a new temporary file and returns the
+ * path to the file, or null if the entry is not found.
+ *
+ * @param jprovider
+ * @param jarEntryName
+ * @param prefix
+ * a prefix for the temporary file name, must be at least three
+ * characters long
+ * @param origFile
+ * null or original file - so new file can be given the same suffix
+ * as the old one
+ * @return
+ */
+ protected String copyJarEntry(jarInputStreamProvider jprovider,
+ String jarEntryName, String prefix, String origFile)
+ {
+ BufferedReader in = null;
+ PrintWriter out = null;
+ String suffix = ".tmp";
+ if (origFile == null)
+ {
+ origFile = jarEntryName;
+ }
+ int sfpos = origFile.lastIndexOf(".");
+ if (sfpos > -1 && sfpos < (origFile.length() - 3))
+ {
+ suffix = "." + origFile.substring(sfpos + 1);
+ }
+ try
+ {
+ JarInputStream jin = jprovider.getJarInputStream();
+ /*
+ * if (jprovider.startsWith("http://")) { jin = new JarInputStream(new
+ * URL(jprovider).openStream()); } else { jin = new JarInputStream(new
+ * FileInputStream(jprovider)); }
+ */
+
+ JarEntry entry = null;
+ do
+ {
+ entry = jin.getNextJarEntry();
+ } while (entry != null && !entry.getName().equals(jarEntryName));
+ if (entry != null)
+ {
+ in = new BufferedReader(new InputStreamReader(jin, UTF_8));
+ File outFile = File.createTempFile(prefix, suffix);
+ outFile.deleteOnExit();
+ out = new PrintWriter(new FileOutputStream(outFile));
+ String data;
+
+ while ((data = in.readLine()) != null)
+ {
+ out.println(data);
+ }
+ out.flush();
+ String t = outFile.getAbsolutePath();
+ return t;
+ }
+ else
+ {
+ warn("Couldn't find entry in Jalview Jar for " + jarEntryName);
+ }
+ } catch (Exception ex)
+ {
+ ex.printStackTrace();
+ } finally
+ {
+ if (in != null)
+ {
+ try
+ {
+ in.close();
+ } catch (IOException e)
+ {
+ // ignore
+ }
+ }
+ if (out != null)
+ {
+ out.close();
+ }
+ }
+
+ return null;
+ }
+
+ private class JvAnnotRow
+ {
+ public JvAnnotRow(int i, AlignmentAnnotation jaa)
+ {
+ order = i;
+ template = jaa;
+ }
+
+ /**
+ * persisted version of annotation row from which to take vis properties
+ */
+ public jalview.datamodel.AlignmentAnnotation template;
+
+ /**
+ * original position of the annotation row in the alignment
+ */
+ public int order;
+ }
+
+ /**
+ * Load alignment frame from jalview XML DOM object
+ *
+ * @param object
+ * DOM
+ * @param file
+ * filename source string
+ * @param loadTreesAndStructures
+ * when false only create Viewport
+ * @param jprovider
+ * data source provider
+ * @return alignment frame created from view stored in DOM
+ */
+ AlignFrame loadFromObject(JalviewModel object, String file,
+ boolean loadTreesAndStructures, jarInputStreamProvider jprovider)
+ {
+ SequenceSet vamsasSet = object.getVamsasModel().getSequenceSet(0);
+ Sequence[] vamsasSeq = vamsasSet.getSequence();
+
+ JalviewModelSequence jms = object.getJalviewModelSequence();
+
+ Viewport view = (jms.getViewportCount() > 0) ? jms.getViewport(0)
+ : null;
+
+ // ////////////////////////////////
+ // LOAD SEQUENCES
+
+ List<SequenceI> hiddenSeqs = null;
+
+ List<SequenceI> tmpseqs = new ArrayList<SequenceI>();
+
+ boolean multipleView = false;
+ SequenceI referenceseqForView = null;
+ JSeq[] jseqs = object.getJalviewModelSequence().getJSeq();
+ int vi = 0; // counter in vamsasSeq array
+ for (int i = 0; i < jseqs.length; i++)
+ {
+ String seqId = jseqs[i].getId();
+
+ SequenceI tmpSeq = seqRefIds.get(seqId);
+ if (tmpSeq != null)
+ {
+ if (!incompleteSeqs.containsKey(seqId))
+ {
+ // may not need this check, but keep it for at least 2.9,1 release
+ if (tmpSeq.getStart() != jseqs[i].getStart()
+ || tmpSeq.getEnd() != jseqs[i].getEnd())
+ {
+ System.err
+ .println("Warning JAL-2154 regression: updating start/end for sequence "
+ + tmpSeq.toString() + " to " + jseqs[i]);
+ }
+ }
+ else
+ {
+ incompleteSeqs.remove(seqId);
+ }
+ if (vamsasSeq.length > vi && vamsasSeq[vi].getId().equals(seqId))
+ {
+ // most likely we are reading a dataset XML document so
+ // update from vamsasSeq section of XML for this sequence
+ tmpSeq.setName(vamsasSeq[vi].getName());
+ tmpSeq.setDescription(vamsasSeq[vi].getDescription());
+ tmpSeq.setSequence(vamsasSeq[vi].getSequence());
+ vi++;
+ }
+ else
+ {
+ // reading multiple views, so vamsasSeq set is a subset of JSeq
+ multipleView = true;
+ }
+ tmpSeq.setStart(jseqs[i].getStart());
+ tmpSeq.setEnd(jseqs[i].getEnd());
+ tmpseqs.add(tmpSeq);
+ }
+ else
+ {
+ tmpSeq = new jalview.datamodel.Sequence(vamsasSeq[vi].getName(),
+ vamsasSeq[vi].getSequence());
+ tmpSeq.setDescription(vamsasSeq[vi].getDescription());
+ tmpSeq.setStart(jseqs[i].getStart());
+ tmpSeq.setEnd(jseqs[i].getEnd());
+ tmpSeq.setVamsasId(uniqueSetSuffix + seqId);
+ seqRefIds.put(vamsasSeq[vi].getId(), tmpSeq);
+ tmpseqs.add(tmpSeq);
+ vi++;
+ }
+
+ if (jseqs[i].hasViewreference() && jseqs[i].getViewreference())
+ {
+ referenceseqForView = tmpseqs.get(tmpseqs.size() - 1);
+ }
+
+ if (jseqs[i].getHidden())
+ {
+ if (hiddenSeqs == null)
+ {
+ hiddenSeqs = new ArrayList<SequenceI>();
+ }
+
+ hiddenSeqs.add(tmpSeq);
+ }
+ }
+
+ // /
+ // Create the alignment object from the sequence set
+ // ///////////////////////////////
+ SequenceI[] orderedSeqs = tmpseqs
+ .toArray(new SequenceI[tmpseqs.size()]);
+
+ AlignmentI al = null;
+ // so we must create or recover the dataset alignment before going further
+ // ///////////////////////////////
+ if (vamsasSet.getDatasetId() == null || vamsasSet.getDatasetId() == "")
+ {
+ // older jalview projects do not have a dataset - so creat alignment and
+ // dataset
+ al = new Alignment(orderedSeqs);
+ al.setDataset(null);
+ }
+ else
+ {
+ boolean isdsal = object.getJalviewModelSequence().getViewportCount() == 0;
+ if (isdsal)
+ {
+ // we are importing a dataset record, so
+ // recover reference to an alignment already materialsed as dataset
+ al = getDatasetFor(vamsasSet.getDatasetId());
+ }
+ if (al == null)
+ {
+ // materialse the alignment
+ al = new Alignment(orderedSeqs);
+ }
+ if (isdsal)
+ {
+ addDatasetRef(vamsasSet.getDatasetId(), al);
+ }
+
+ // finally, verify all data in vamsasSet is actually present in al
+ // passing on flag indicating if it is actually a stored dataset
+ recoverDatasetFor(vamsasSet, al, isdsal);
+ }
+
+ if (referenceseqForView != null)
+ {
+ al.setSeqrep(referenceseqForView);
+ }
+ // / Add the alignment properties
+ for (int i = 0; i < vamsasSet.getSequenceSetPropertiesCount(); i++)
+ {
+ SequenceSetProperties ssp = vamsasSet.getSequenceSetProperties(i);
+ al.setProperty(ssp.getKey(), ssp.getValue());
+ }
+
+ // ///////////////////////////////
+
+ Hashtable pdbloaded = new Hashtable(); // TODO nothing writes to this??
+ if (!multipleView)
+ {
+ // load sequence features, database references and any associated PDB
+ // structures for the alignment
+ //
+ // prior to 2.10, this part would only be executed the first time a
+ // sequence was encountered, but not afterwards.
+ // now, for 2.10 projects, this is also done if the xml doc includes
+ // dataset sequences not actually present in any particular view.
+ //
+ for (int i = 0; i < vamsasSeq.length; i++)
+ {
+ if (jseqs[i].getFeaturesCount() > 0)
+ {
+ Features[] features = jseqs[i].getFeatures();
+ for (int f = 0; f < features.length; f++)
+ {
+ jalview.datamodel.SequenceFeature sf = new jalview.datamodel.SequenceFeature(
+ features[f].getType(), features[f].getDescription(),
+ features[f].getStatus(), features[f].getBegin(),
+ features[f].getEnd(), features[f].getFeatureGroup());
+
+ sf.setScore(features[f].getScore());
+ for (int od = 0; od < features[f].getOtherDataCount(); od++)
+ {
+ OtherData keyValue = features[f].getOtherData(od);
+ if (keyValue.getKey().startsWith("LINK"))
+ {
+ sf.addLink(keyValue.getValue());
+ }
+ else
+ {
+ sf.setValue(keyValue.getKey(), keyValue.getValue());
+ }
+
+ }
+ // adds feature to datasequence's feature set (since Jalview 2.10)
+ al.getSequenceAt(i).addSequenceFeature(sf);
+ }
+ }
+ if (vamsasSeq[i].getDBRefCount() > 0)
+ {
+ // adds dbrefs to datasequence's set (since Jalview 2.10)
+ addDBRefs(
+ al.getSequenceAt(i).getDatasetSequence() == null ? al.getSequenceAt(i)
+ : al.getSequenceAt(i).getDatasetSequence(),
+ vamsasSeq[i]);
+ }
+ if (jseqs[i].getPdbidsCount() > 0)
+ {
+ Pdbids[] ids = jseqs[i].getPdbids();
+ for (int p = 0; p < ids.length; p++)
+ {
+ jalview.datamodel.PDBEntry entry = new jalview.datamodel.PDBEntry();
+ entry.setId(ids[p].getId());
+ if (ids[p].getType() != null)
+ {
+ if (PDBEntry.Type.getType(ids[p].getType()) != null)
+ {
+ entry.setType(PDBEntry.Type.getType(ids[p].getType()));
+ }
+ else
+ {
+ entry.setType(PDBEntry.Type.FILE);
+ }
+ }
+ // jprovider is null when executing 'New View'
+ if (ids[p].getFile() != null && jprovider != null)
+ {
+ if (!pdbloaded.containsKey(ids[p].getFile()))
+ {
+ entry.setFile(loadPDBFile(jprovider, ids[p].getId(),
+ ids[p].getFile()));
+ }
+ else
+ {
+ entry.setFile(pdbloaded.get(ids[p].getId()).toString());
+ }
+ }
+ if (ids[p].getPdbentryItem() != null)
+ {
+ for (PdbentryItem item : ids[p].getPdbentryItem())
+ {
+ for (Property pr : item.getProperty())
+ {
+ entry.setProperty(pr.getName(), pr.getValue());
+ }
+ }
+ }
+ StructureSelectionManager.getStructureSelectionManager(
+ Desktop.instance).registerPDBEntry(entry);
+ // adds PDBEntry to datasequence's set (since Jalview 2.10)
+ if (al.getSequenceAt(i).getDatasetSequence() != null)
+ {
+ al.getSequenceAt(i).getDatasetSequence().addPDBId(entry);
+ }
+ else
+ {
+ al.getSequenceAt(i).addPDBId(entry);
+ }
+ }
+ }
+ }
+ } // end !multipleview
+
+ // ///////////////////////////////
+ // LOAD SEQUENCE MAPPINGS
+
+ if (vamsasSet.getAlcodonFrameCount() > 0)
+ {
+ // TODO Potentially this should only be done once for all views of an
+ // alignment
+ AlcodonFrame[] alc = vamsasSet.getAlcodonFrame();
+ for (int i = 0; i < alc.length; i++)
+ {
+ AlignedCodonFrame cf = new AlignedCodonFrame();
+ if (alc[i].getAlcodMapCount() > 0)
+ {
+ AlcodMap[] maps = alc[i].getAlcodMap();
+ for (int m = 0; m < maps.length; m++)
+ {
+ SequenceI dnaseq = seqRefIds.get(maps[m].getDnasq());
+ // Load Mapping
+ jalview.datamodel.Mapping mapping = null;
+ // attach to dna sequence reference.
+ if (maps[m].getMapping() != null)
+ {
+ mapping = addMapping(maps[m].getMapping());
+ if (dnaseq != null && mapping.getTo() != null)
+ {
+ cf.addMap(dnaseq, mapping.getTo(), mapping.getMap());
+ }
+ else
+ {
+ // defer to later
+ frefedSequence.add(newAlcodMapRef(maps[m].getDnasq(), cf,
+ mapping));
+ }
+ }
+ }
+ al.addCodonFrame(cf);
+ }
+ }
+ }
+
+ // ////////////////////////////////
+ // LOAD ANNOTATIONS
+ List<JvAnnotRow> autoAlan = new ArrayList<JvAnnotRow>();
+
+ /*
+ * store any annotations which forward reference a group's ID
+ */
+ Map<String, List<AlignmentAnnotation>> groupAnnotRefs = new Hashtable<String, List<AlignmentAnnotation>>();
+
+ if (vamsasSet.getAnnotationCount() > 0)
+ {
+ Annotation[] an = vamsasSet.getAnnotation();
+
+ for (int i = 0; i < an.length; i++)
+ {
+ Annotation annotation = an[i];
+
+ /**
+ * test if annotation is automatically calculated for this view only
+ */
+ boolean autoForView = false;
+ if (annotation.getLabel().equals("Quality")
+ || annotation.getLabel().equals("Conservation")
+ || annotation.getLabel().equals("Consensus"))
+ {
+ // Kludge for pre 2.5 projects which lacked the autocalculated flag
+ autoForView = true;
+ if (!annotation.hasAutoCalculated())
+ {
+ annotation.setAutoCalculated(true);
+ }
+ }
+ if (autoForView
+ || (annotation.hasAutoCalculated() && annotation
+ .isAutoCalculated()))
+ {
+ // remove ID - we don't recover annotation from other views for
+ // view-specific annotation
+ annotation.setId(null);
+ }
+
+ // set visiblity for other annotation in this view
+ String annotationId = annotation.getId();
+ if (annotationId != null && annotationIds.containsKey(annotationId))
+ {
+ AlignmentAnnotation jda = annotationIds.get(annotationId);
+ // in principle Visible should always be true for annotation displayed
+ // in multiple views
+ if (annotation.hasVisible())
+ {
+ jda.visible = annotation.getVisible();
+ }
+
+ al.addAnnotation(jda);
+
+ continue;
+ }
+ // Construct new annotation from model.
+ AnnotationElement[] ae = annotation.getAnnotationElement();
+ jalview.datamodel.Annotation[] anot = null;
+ java.awt.Color firstColour = null;
+ int anpos;
+ if (!annotation.getScoreOnly())
+ {
+ anot = new jalview.datamodel.Annotation[al.getWidth()];
+ for (int aa = 0; aa < ae.length && aa < anot.length; aa++)
+ {
+ anpos = ae[aa].getPosition();
+
+ if (anpos >= anot.length)
+ {
+ continue;
+ }
+
+ anot[anpos] = new jalview.datamodel.Annotation(
+
+ ae[aa].getDisplayCharacter(), ae[aa].getDescription(),
+ (ae[aa].getSecondaryStructure() == null || ae[aa]
+ .getSecondaryStructure().length() == 0) ? ' '
+ : ae[aa].getSecondaryStructure().charAt(0),
+ ae[aa].getValue()
+
+ );
+ // JBPNote: Consider verifying dataflow for IO of secondary
+ // structure annotation read from Stockholm files
+ // this was added to try to ensure that
+ // if (anot[ae[aa].getPosition()].secondaryStructure>' ')
+ // {
+ // anot[ae[aa].getPosition()].displayCharacter = "";
+ // }
+ anot[anpos].colour = new java.awt.Color(ae[aa].getColour());
+ if (firstColour == null)
+ {
+ firstColour = anot[anpos].colour;
+ }
+ }
+ }
+ jalview.datamodel.AlignmentAnnotation jaa = null;
+
+ if (annotation.getGraph())
+ {
+ float llim = 0, hlim = 0;
+ // if (autoForView || an[i].isAutoCalculated()) {
+ // hlim=11f;
+ // }
+ jaa = new jalview.datamodel.AlignmentAnnotation(
+ annotation.getLabel(), annotation.getDescription(), anot,
+ llim, hlim, annotation.getGraphType());
+
+ jaa.graphGroup = annotation.getGraphGroup();
+ jaa._linecolour = firstColour;
+ if (annotation.getThresholdLine() != null)
+ {
+ jaa.setThreshold(new jalview.datamodel.GraphLine(annotation
+ .getThresholdLine().getValue(), annotation
+ .getThresholdLine().getLabel(), new java.awt.Color(
+ annotation.getThresholdLine().getColour())));
+
+ }
+ if (autoForView || annotation.isAutoCalculated())
+ {
+ // Hardwire the symbol display line to ensure that labels for
+ // histograms are displayed
+ jaa.hasText = true;
+ }
+ }
+ else
+ {
+ jaa = new jalview.datamodel.AlignmentAnnotation(an[i].getLabel(),
+ an[i].getDescription(), anot);
+ jaa._linecolour = firstColour;
+ }
+ // register new annotation
+ if (an[i].getId() != null)
+ {
+ annotationIds.put(an[i].getId(), jaa);
+ jaa.annotationId = an[i].getId();
+ }
+ // recover sequence association
+ String sequenceRef = an[i].getSequenceRef();
+ if (sequenceRef != null)
+ {
+ // from 2.9 sequenceRef is to sequence id (JAL-1781)
+ SequenceI sequence = seqRefIds.get(sequenceRef);
+ if (sequence == null)
+ {
+ // in pre-2.9 projects sequence ref is to sequence name
+ sequence = al.findName(sequenceRef);
+ }
+ if (sequence != null)
+ {
+ jaa.createSequenceMapping(sequence, 1, true);
+ sequence.addAlignmentAnnotation(jaa);
+ }
+ }
+ // and make a note of any group association
+ if (an[i].getGroupRef() != null && an[i].getGroupRef().length() > 0)
+ {
+ List<jalview.datamodel.AlignmentAnnotation> aal = groupAnnotRefs
+ .get(an[i].getGroupRef());
+ if (aal == null)
+ {
+ aal = new ArrayList<jalview.datamodel.AlignmentAnnotation>();
+ groupAnnotRefs.put(an[i].getGroupRef(), aal);
+ }
+ aal.add(jaa);
+ }
+
+ if (an[i].hasScore())
+ {
+ jaa.setScore(an[i].getScore());
+ }
+ if (an[i].hasVisible())
+ {
+ jaa.visible = an[i].getVisible();
+ }
+
+ if (an[i].hasCentreColLabels())
+ {
+ jaa.centreColLabels = an[i].getCentreColLabels();
+ }
+
+ if (an[i].hasScaleColLabels())
+ {
+ jaa.scaleColLabel = an[i].getScaleColLabels();
+ }
+ if (an[i].hasAutoCalculated() && an[i].isAutoCalculated())
+ {
+ // newer files have an 'autoCalculated' flag and store calculation
+ // state in viewport properties
+ jaa.autoCalculated = true; // means annotation will be marked for
+ // update at end of load.
+ }
+ if (an[i].hasGraphHeight())
+ {
+ jaa.graphHeight = an[i].getGraphHeight();
+ }
+ if (an[i].hasBelowAlignment())
+ {
+ jaa.belowAlignment = an[i].isBelowAlignment();
+ }
+ jaa.setCalcId(an[i].getCalcId());
+ if (an[i].getPropertyCount() > 0)
+ {
+ for (jalview.schemabinding.version2.Property prop : an[i]
+ .getProperty())
+ {
+ jaa.setProperty(prop.getName(), prop.getValue());
+ }
+ }
+ if (jaa.autoCalculated)
+ {
+ autoAlan.add(new JvAnnotRow(i, jaa));
+ }
+ else
+ // if (!autoForView)
+ {
+ // add autocalculated group annotation and any user created annotation
+ // for the view
+ al.addAnnotation(jaa);
+ }
+ }
+ }
+ // ///////////////////////
+ // LOAD GROUPS
+ // Create alignment markup and styles for this view
+ if (jms.getJGroupCount() > 0)
+ {
+ JGroup[] groups = jms.getJGroup();
+ boolean addAnnotSchemeGroup = false;
+ for (int i = 0; i < groups.length; i++)
+ {
+ JGroup jGroup = groups[i];
+ ColourSchemeI cs = null;
+ if (jGroup.getColour() != null)
+ {
+ if (jGroup.getColour().startsWith("ucs"))
+ {
+ cs = getUserColourScheme(jms, jGroup.getColour());
+ }
+ else if (jGroup.getColour().equals("AnnotationColourGradient")
+ && jGroup.getAnnotationColours() != null)
+ {
+ addAnnotSchemeGroup = true;
+ }
+ else
+ {
+ cs = ColourSchemeProperty.getColourScheme(al, jGroup.getColour());
+ }
+ }
+ int pidThreshold = jGroup.getPidThreshold();
+
+ Vector<SequenceI> seqs = new Vector<SequenceI>();
+
+ for (int s = 0; s < jGroup.getSeqCount(); s++)
+ {
+ String seqId = jGroup.getSeq(s) + "";
+ SequenceI ts = seqRefIds.get(seqId);
+
+ if (ts != null)
+ {
+ seqs.addElement(ts);
+ }
+ }
+
+ if (seqs.size() < 1)
+ {
+ continue;
+ }
+
+ SequenceGroup sg = new SequenceGroup(seqs, jGroup.getName(), cs,
+ jGroup.getDisplayBoxes(), jGroup.getDisplayText(),
+ jGroup.getColourText(), jGroup.getStart(), jGroup.getEnd());
+ sg.getGroupColourScheme().setThreshold(pidThreshold, true);
+ sg.getGroupColourScheme().setConservationInc(jGroup.getConsThreshold());
+ sg.setOutlineColour(new java.awt.Color(jGroup.getOutlineColour()));
+
+ sg.textColour = new java.awt.Color(jGroup.getTextCol1());
+ sg.textColour2 = new java.awt.Color(jGroup.getTextCol2());
+ sg.setShowNonconserved(jGroup.hasShowUnconserved() ? jGroup
+ .isShowUnconserved() : false);
+ sg.thresholdTextColour = jGroup.getTextColThreshold();
+ if (jGroup.hasShowConsensusHistogram())
+ {
+ sg.setShowConsensusHistogram(jGroup.isShowConsensusHistogram());
+ }
+ ;
+ if (jGroup.hasShowSequenceLogo())
+ {
+ sg.setshowSequenceLogo(jGroup.isShowSequenceLogo());
+ }
+ if (jGroup.hasNormaliseSequenceLogo())
+ {
+ sg.setNormaliseSequenceLogo(jGroup.isNormaliseSequenceLogo());
+ }
+ if (jGroup.hasIgnoreGapsinConsensus())
+ {
+ sg.setIgnoreGapsConsensus(jGroup.getIgnoreGapsinConsensus());
+ }
+ if (jGroup.getConsThreshold() != 0)
+ {
+ Conservation c = new Conservation("All", sg.getSequences(null),
+ 0, sg.getWidth() - 1);
+ c.calculate();
+ c.verdict(false, 25);
+ sg.cs.setConservation(c);
+ }
+
+ if (jGroup.getId() != null && groupAnnotRefs.size() > 0)
+ {
+ // re-instate unique group/annotation row reference
+ List<AlignmentAnnotation> jaal = groupAnnotRefs.get(jGroup
+ .getId());
+ if (jaal != null)
+ {
+ for (AlignmentAnnotation jaa : jaal)
+ {
+ jaa.groupRef = sg;
+ if (jaa.autoCalculated)
+ {
+ // match up and try to set group autocalc alignment row for this
+ // annotation
+ if (jaa.label.startsWith("Consensus for "))
+ {
+ sg.setConsensus(jaa);
+ }
+ // match up and try to set group autocalc alignment row for this
+ // annotation
+ if (jaa.label.startsWith("Conservation for "))
+ {
+ sg.setConservationRow(jaa);
+ }
+ }
+ }
+ }
+ }
+ al.addGroup(sg);
+ if (addAnnotSchemeGroup)
+ {
+ // reconstruct the annotation colourscheme
+ sg.setColourScheme(constructAnnotationColour(
+ jGroup.getAnnotationColours(), null, al, jms, false));
+ }
+ }
+ }
+ if (view == null)
+ {
+ // only dataset in this model, so just return.
+ return null;
+ }
+ // ///////////////////////////////
+ // LOAD VIEWPORT
+
+ // If we just load in the same jar file again, the sequenceSetId
+ // will be the same, and we end up with multiple references
+ // to the same sequenceSet. We must modify this id on load
+ // so that each load of the file gives a unique id
+ String uniqueSeqSetId = view.getSequenceSetId() + uniqueSetSuffix;
+ String viewId = (view.getId() == null ? null : view.getId()
+ + uniqueSetSuffix);
+ AlignFrame af = null;
+ AlignViewport av = null;
+ // now check to see if we really need to create a new viewport.
+ if (multipleView && viewportsAdded.size() == 0)
+ {
+ // We recovered an alignment for which a viewport already exists.
+ // TODO: fix up any settings necessary for overlaying stored state onto
+ // state recovered from another document. (may not be necessary).
+ // we may need a binding from a viewport in memory to one recovered from
+ // XML.
+ // and then recover its containing af to allow the settings to be applied.
+ // TODO: fix for vamsas demo
+ System.err
+ .println("About to recover a viewport for existing alignment: Sequence set ID is "
+ + uniqueSeqSetId);
+ Object seqsetobj = retrieveExistingObj(uniqueSeqSetId);
+ if (seqsetobj != null)
+ {
+ if (seqsetobj instanceof String)
+ {
+ uniqueSeqSetId = (String) seqsetobj;
+ System.err
+ .println("Recovered extant sequence set ID mapping for ID : New Sequence set ID is "
+ + uniqueSeqSetId);
+ }
+ else
+ {
+ System.err
+ .println("Warning : Collision between sequence set ID string and existing jalview object mapping.");
+ }
+
+ }
+ }
+ /**
+ * indicate that annotation colours are applied across all groups (pre
+ * Jalview 2.8.1 behaviour)
+ */
+ boolean doGroupAnnColour = Jalview2XML.isVersionStringLaterThan(
+ "2.8.1", object.getVersion());
+
+ AlignmentPanel ap = null;
+ boolean isnewview = true;
+ if (viewId != null)
+ {
+ // Check to see if this alignment already has a view id == viewId
+ jalview.gui.AlignmentPanel views[] = Desktop
+ .getAlignmentPanels(uniqueSeqSetId);
+ if (views != null && views.length > 0)
+ {
+ for (int v = 0; v < views.length; v++)
+ {
+ if (views[v].av.getViewId().equalsIgnoreCase(viewId))
+ {
+ // recover the existing alignpanel, alignframe, viewport
+ af = views[v].alignFrame;
+ av = views[v].av;
+ ap = views[v];
+ // TODO: could even skip resetting view settings if we don't want to
+ // change the local settings from other jalview processes
+ isnewview = false;
+ }
+ }
+ }
+ }
+
+ if (isnewview)
+ {
+ af = loadViewport(file, jseqs, hiddenSeqs, al, jms, view,
+ uniqueSeqSetId, viewId, autoAlan);
+ av = af.viewport;
+ ap = af.alignPanel;
+ }
+
+ /*
+ * Load any trees, PDB structures and viewers
+ *
+ * Not done if flag is false (when this method is used for New View)
+ */
+ if (loadTreesAndStructures)
+ {
+ loadTrees(jms, view, af, av, ap);
+ loadPDBStructures(jprovider, jseqs, af, ap);
+ loadRnaViewers(jprovider, jseqs, ap);
+ }
+ // and finally return.
+ return af;
+ }
+
+ /**
+ * Instantiate and link any saved RNA (Varna) viewers. The state of the Varna
+ * panel is restored from separate jar entries, two (gapped and trimmed) per
+ * sequence and secondary structure.
+ *
+ * Currently each viewer shows just one sequence and structure (gapped and
+ * trimmed), however this method is designed to support multiple sequences or
+ * structures in viewers if wanted in future.
+ *
+ * @param jprovider
+ * @param jseqs
+ * @param ap
+ */
+ private void loadRnaViewers(jarInputStreamProvider jprovider,
+ JSeq[] jseqs, AlignmentPanel ap)
+ {
+ /*
+ * scan the sequences for references to viewers; create each one the first
+ * time it is referenced, add Rna models to existing viewers
+ */
+ for (JSeq jseq : jseqs)
+ {
+ for (int i = 0; i < jseq.getRnaViewerCount(); i++)
+ {
+ RnaViewer viewer = jseq.getRnaViewer(i);
+ AppVarna appVarna = findOrCreateVarnaViewer(viewer,
+ uniqueSetSuffix, ap);
+
+ for (int j = 0; j < viewer.getSecondaryStructureCount(); j++)
+ {
+ SecondaryStructure ss = viewer.getSecondaryStructure(j);
+ SequenceI seq = seqRefIds.get(jseq.getId());
+ AlignmentAnnotation ann = this.annotationIds.get(ss
+ .getAnnotationId());
+
+ /*
+ * add the structure to the Varna display (with session state copied
+ * from the jar to a temporary file)
+ */
+ boolean gapped = ss.isGapped();
+ String rnaTitle = ss.getTitle();
+ String sessionState = ss.getViewerState();
+ String tempStateFile = copyJarEntry(jprovider, sessionState,
+ "varna", null);
+ RnaModel rna = new RnaModel(rnaTitle, ann, seq, null, gapped);
+ appVarna.addModelSession(rna, rnaTitle, tempStateFile);
+ }
+ appVarna.setInitialSelection(viewer.getSelectedRna());
+ }
+ }
+ }
+
+ /**
+ * Locate and return an already instantiated matching AppVarna, or create one
+ * if not found
+ *
+ * @param viewer
+ * @param viewIdSuffix
+ * @param ap
+ * @return
+ */
+ protected AppVarna findOrCreateVarnaViewer(RnaViewer viewer,
+ String viewIdSuffix, AlignmentPanel ap)
+ {
+ /*
+ * on each load a suffix is appended to the saved viewId, to avoid conflicts
+ * if load is repeated
+ */
+ String postLoadId = viewer.getViewId() + viewIdSuffix;
+ for (JInternalFrame frame : getAllFrames())
+ {
+ if (frame instanceof AppVarna)
+ {
+ AppVarna varna = (AppVarna) frame;
+ if (postLoadId.equals(varna.getViewId()))
+ {
+ // this viewer is already instantiated
+ // could in future here add ap as another 'parent' of the
+ // AppVarna window; currently just 1-to-many
+ return varna;
+ }
+ }
+ }
+
+ /*
+ * viewer not found - make it
+ */
+ RnaViewerModel model = new RnaViewerModel(postLoadId,
+ viewer.getTitle(), viewer.getXpos(), viewer.getYpos(),
+ viewer.getWidth(), viewer.getHeight(),
+ viewer.getDividerLocation());
+ AppVarna varna = new AppVarna(model, ap);
+
+ return varna;
+ }
+
+ /**
+ * Load any saved trees
+ *
+ * @param jms
+ * @param view
+ * @param af
+ * @param av
+ * @param ap
+ */
+ protected void loadTrees(JalviewModelSequence jms, Viewport view,
+ AlignFrame af, AlignViewport av, AlignmentPanel ap)
+ {
+ // TODO result of automated refactoring - are all these parameters needed?
+ try
+ {
+ for (int t = 0; t < jms.getTreeCount(); t++)
+ {
+
+ Tree tree = jms.getTree(t);
+
+ TreePanel tp = (TreePanel) retrieveExistingObj(tree.getId());
+ if (tp == null)
+ {
+ tp = af.showNewickTree(
+ new jalview.io.NewickFile(tree.getNewick()),
+ tree.getTitle(), tree.getWidth(), tree.getHeight(),
+ tree.getXpos(), tree.getYpos());
+ if (tree.getId() != null)
+ {
+ // perhaps bind the tree id to something ?
+ }
+ }
+ else
+ {
+ // update local tree attributes ?
+ // TODO: should check if tp has been manipulated by user - if so its
+ // settings shouldn't be modified
+ tp.setTitle(tree.getTitle());
+ tp.setBounds(new Rectangle(tree.getXpos(), tree.getYpos(), tree
+ .getWidth(), tree.getHeight()));
+ tp.av = av; // af.viewport; // TODO: verify 'associate with all
+ // views'
+ // works still
+ tp.treeCanvas.av = av; // af.viewport;
+ tp.treeCanvas.ap = ap; // af.alignPanel;
+
+ }
+ if (tp == null)
+ {
+ warn("There was a problem recovering stored Newick tree: \n"
+ + tree.getNewick());
+ continue;
+ }
+
+ tp.fitToWindow.setState(tree.getFitToWindow());
+ tp.fitToWindow_actionPerformed(null);
+
+ if (tree.getFontName() != null)
+ {
+ tp.setTreeFont(new java.awt.Font(tree.getFontName(), tree
+ .getFontStyle(), tree.getFontSize()));
+ }
+ else
+ {
+ tp.setTreeFont(new java.awt.Font(view.getFontName(), view
+ .getFontStyle(), tree.getFontSize()));
+ }
+
+ tp.showPlaceholders(tree.getMarkUnlinked());
+ tp.showBootstrap(tree.getShowBootstrap());
+ tp.showDistances(tree.getShowDistances());
+
+ tp.treeCanvas.threshold = tree.getThreshold();
+
+ if (tree.getCurrentTree())
+ {
+ af.viewport.setCurrentTree(tp.getTree());
+ }
+ }
+
+ } catch (Exception ex)
+ {
+ ex.printStackTrace();
+ }
+ }
+
+ /**
+ * Load and link any saved structure viewers.
+ *
+ * @param jprovider
+ * @param jseqs
+ * @param af
+ * @param ap
+ */
+ protected void loadPDBStructures(jarInputStreamProvider jprovider,
+ JSeq[] jseqs, AlignFrame af, AlignmentPanel ap)
+ {
+ /*
+ * Run through all PDB ids on the alignment, and collect mappings between
+ * distinct view ids and all sequences referring to that view.
+ */
+ Map<String, StructureViewerModel> structureViewers = new LinkedHashMap<String, StructureViewerModel>();
+
+ for (int i = 0; i < jseqs.length; i++)
+ {
+ if (jseqs[i].getPdbidsCount() > 0)
+ {
+ Pdbids[] ids = jseqs[i].getPdbids();
+ for (int p = 0; p < ids.length; p++)
+ {
+ final int structureStateCount = ids[p].getStructureStateCount();
+ for (int s = 0; s < structureStateCount; s++)
+ {
+ // check to see if we haven't already created this structure view
+ final StructureState structureState = ids[p]
+ .getStructureState(s);
+ String sviewid = (structureState.getViewId() == null) ? null
+ : structureState.getViewId() + uniqueSetSuffix;
+ jalview.datamodel.PDBEntry jpdb = new jalview.datamodel.PDBEntry();
+ // Originally : ids[p].getFile()
+ // : TODO: verify external PDB file recovery still works in normal
+ // jalview project load
+ jpdb.setFile(loadPDBFile(jprovider, ids[p].getId(),
+ ids[p].getFile()));
+ jpdb.setId(ids[p].getId());
+
+ int x = structureState.getXpos();
+ int y = structureState.getYpos();
+ int width = structureState.getWidth();
+ int height = structureState.getHeight();
+
+ // Probably don't need to do this anymore...
+ // Desktop.desktop.getComponentAt(x, y);
+ // TODO: NOW: check that this recovers the PDB file correctly.
+ String pdbFile = loadPDBFile(jprovider, ids[p].getId(),
+ ids[p].getFile());
+ jalview.datamodel.SequenceI seq = seqRefIds.get(jseqs[i]
+ .getId() + "");
+ if (sviewid == null)
+ {
+ sviewid = "_jalview_pre2_4_" + x + "," + y + "," + width
+ + "," + height;
+ }
+ if (!structureViewers.containsKey(sviewid))
+ {
+ structureViewers.put(sviewid,
+ new StructureViewerModel(x, y, width, height, false,
+ false, true, structureState.getViewId(),
+ structureState.getType()));
+ // Legacy pre-2.7 conversion JAL-823 :
+ // do not assume any view has to be linked for colour by
+ // sequence
+ }
+
+ // assemble String[] { pdb files }, String[] { id for each
+ // file }, orig_fileloc, SequenceI[][] {{ seqs_file 1 }, {
+ // seqs_file 2}, boolean[] {
+ // linkAlignPanel,superposeWithAlignpanel}} from hash
+ StructureViewerModel jmoldat = structureViewers.get(sviewid);
+ jmoldat.setAlignWithPanel(jmoldat.isAlignWithPanel()
+ | (structureState.hasAlignwithAlignPanel() ? structureState
+ .getAlignwithAlignPanel() : false));
+
+ /*
+ * Default colour by linked panel to false if not specified (e.g.
+ * for pre-2.7 projects)
+ */
+ boolean colourWithAlignPanel = jmoldat.isColourWithAlignPanel();
+ colourWithAlignPanel |= (structureState
+ .hasColourwithAlignPanel() ? structureState
+ .getColourwithAlignPanel() : false);
+ jmoldat.setColourWithAlignPanel(colourWithAlignPanel);
+
+ /*
+ * Default colour by viewer to true if not specified (e.g. for
+ * pre-2.7 projects)
+ */
+ boolean colourByViewer = jmoldat.isColourByViewer();
+ colourByViewer &= structureState.hasColourByJmol() ? structureState
+ .getColourByJmol() : true;
+ jmoldat.setColourByViewer(colourByViewer);
+
+ if (jmoldat.getStateData().length() < structureState
+ .getContent().length())
+ {
+ {
+ jmoldat.setStateData(structureState.getContent());
+ }
+ }
+ if (ids[p].getFile() != null)
+ {
+ File mapkey = new File(ids[p].getFile());
+ StructureData seqstrmaps = jmoldat.getFileData().get(mapkey);
+ if (seqstrmaps == null)
+ {
+ jmoldat.getFileData().put(
+ mapkey,
+ seqstrmaps = jmoldat.new StructureData(pdbFile,
+ ids[p].getId()));
+ }
+ if (!seqstrmaps.getSeqList().contains(seq))
+ {
+ seqstrmaps.getSeqList().add(seq);
+ // TODO and chains?
+ }
+ }
+ else
+ {
+ errorMessage = ("The Jmol views in this project were imported\nfrom an older version of Jalview.\nPlease review the sequence colour associations\nin the Colour by section of the Jmol View menu.\n\nIn the case of problems, see note at\nhttp://issues.jalview.org/browse/JAL-747");
+ warn(errorMessage);
+ }
+ }
+ }
+ }
+ }
+ // Instantiate the associated structure views
+ for (Entry<String, StructureViewerModel> entry : structureViewers
+ .entrySet())
+ {
+ try
+ {
+ createOrLinkStructureViewer(entry, af, ap, jprovider);
+ } catch (Exception e)
+ {
+ System.err.println("Error loading structure viewer: "
+ + e.getMessage());
+ // failed - try the next one
+ }
+ }
+ }
+
+ /**
+ *
+ * @param viewerData
+ * @param af
+ * @param ap
+ * @param jprovider
+ */
+ protected void createOrLinkStructureViewer(
+ Entry<String, StructureViewerModel> viewerData, AlignFrame af,
+ AlignmentPanel ap, jarInputStreamProvider jprovider)
+ {
+ final StructureViewerModel stateData = viewerData.getValue();
+
+ /*
+ * Search for any viewer windows already open from other alignment views
+ * that exactly match the stored structure state
+ */
+ StructureViewerBase comp = findMatchingViewer(viewerData);
+
+ if (comp != null)
+ {
+ linkStructureViewer(ap, comp, stateData);
+ return;
+ }
+
+ /*
+ * From 2.9: stateData.type contains JMOL or CHIMERA, data is in jar entry
+ * "viewer_"+stateData.viewId
+ */
+ if (ViewerType.CHIMERA.toString().equals(stateData.getType()))
+ {
+ createChimeraViewer(viewerData, af, jprovider);
+ }
+ else
+ {
+ /*
+ * else Jmol (if pre-2.9, stateData contains JMOL state string)
+ */
+ createJmolViewer(viewerData, af, jprovider);
+ }
+ }
+
+ /**
+ * Create a new Chimera viewer.
+ *
+ * @param data
+ * @param af
+ * @param jprovider
+ */
+ protected void createChimeraViewer(
+ Entry<String, StructureViewerModel> viewerData, AlignFrame af,
+ jarInputStreamProvider jprovider)
+ {
+ StructureViewerModel data = viewerData.getValue();
+ String chimeraSessionFile = data.getStateData();
+
+ /*
+ * Copy Chimera session from jar entry "viewer_"+viewId to a temporary file
+ *
+ * NB this is the 'saved' viewId as in the project file XML, _not_ the
+ * 'uniquified' sviewid used to reconstruct the viewer here
+ */
+ String viewerJarEntryName = getViewerJarEntryName(data.getViewId());
+ chimeraSessionFile = copyJarEntry(jprovider, viewerJarEntryName,
+ "chimera", null);
+
+ Set<Entry<File, StructureData>> fileData = data.getFileData()
+ .entrySet();
+ List<PDBEntry> pdbs = new ArrayList<PDBEntry>();
+ List<SequenceI[]> allseqs = new ArrayList<SequenceI[]>();
+ for (Entry<File, StructureData> pdb : fileData)
+ {
+ String filePath = pdb.getValue().getFilePath();
+ String pdbId = pdb.getValue().getPdbId();
+ // pdbs.add(new PDBEntry(filePath, pdbId));
+ pdbs.add(new PDBEntry(pdbId, null, PDBEntry.Type.PDB, filePath));
+ final List<SequenceI> seqList = pdb.getValue().getSeqList();
+ SequenceI[] seqs = seqList.toArray(new SequenceI[seqList.size()]);
+ allseqs.add(seqs);
+ }
+
+ boolean colourByChimera = data.isColourByViewer();
+ boolean colourBySequence = data.isColourWithAlignPanel();
+
+ // TODO use StructureViewer as a factory here, see JAL-1761
+ final PDBEntry[] pdbArray = pdbs.toArray(new PDBEntry[pdbs.size()]);
+ final SequenceI[][] seqsArray = allseqs.toArray(new SequenceI[allseqs
+ .size()][]);
+ String newViewId = viewerData.getKey();
+
+ ChimeraViewFrame cvf = new ChimeraViewFrame(chimeraSessionFile,
+ af.alignPanel, pdbArray, seqsArray, colourByChimera,
+ colourBySequence, newViewId);
+ cvf.setSize(data.getWidth(), data.getHeight());
+ cvf.setLocation(data.getX(), data.getY());
+ }
+
+ /**
+ * Create a new Jmol window. First parse the Jmol state to translate filenames
+ * loaded into the view, and record the order in which files are shown in the
+ * Jmol view, so we can add the sequence mappings in same order.
+ *
+ * @param viewerData
+ * @param af
+ * @param jprovider
+ */
+ protected void createJmolViewer(
+ final Entry<String, StructureViewerModel> viewerData,
+ AlignFrame af, jarInputStreamProvider jprovider)
+ {
+ final StructureViewerModel svattrib = viewerData.getValue();
+ String state = svattrib.getStateData();
+
+ /*
+ * Pre-2.9: state element value is the Jmol state string
+ *
+ * 2.9+: @type is "JMOL", state data is in a Jar file member named "viewer_"
+ * + viewId
+ */
+ if (ViewerType.JMOL.toString().equals(svattrib.getType()))
+ {
+ state = readJarEntry(jprovider,
+ getViewerJarEntryName(svattrib.getViewId()));
+ }
+
+ List<String> pdbfilenames = new ArrayList<String>();
+ List<SequenceI[]> seqmaps = new ArrayList<SequenceI[]>();
+ List<String> pdbids = new ArrayList<String>();
+ StringBuilder newFileLoc = new StringBuilder(64);
+ int cp = 0, ncp, ecp;
+ Map<File, StructureData> oldFiles = svattrib.getFileData();
+ while ((ncp = state.indexOf("load ", cp)) > -1)
+ {
+ do
+ {
+ // look for next filename in load statement
+ newFileLoc.append(state.substring(cp,
+ ncp = (state.indexOf("\"", ncp + 1) + 1)));
+ String oldfilenam = state.substring(ncp,
+ ecp = state.indexOf("\"", ncp));
+ // recover the new mapping data for this old filename
+ // have to normalize filename - since Jmol and jalview do
+ // filename
+ // translation differently.
+ StructureData filedat = oldFiles.get(new File(oldfilenam));
+ if (filedat == null)
+ {
+ String reformatedOldFilename = oldfilenam.replaceAll("/", "\\\\");
+ filedat = oldFiles.get(new File(reformatedOldFilename));
+ }
+ newFileLoc.append(Platform.escapeString(filedat.getFilePath()));
+ pdbfilenames.add(filedat.getFilePath());
+ pdbids.add(filedat.getPdbId());
+ seqmaps.add(filedat.getSeqList().toArray(new SequenceI[0]));
+ newFileLoc.append("\"");
+ cp = ecp + 1; // advance beyond last \" and set cursor so we can
+ // look for next file statement.
+ } while ((ncp = state.indexOf("/*file*/", cp)) > -1);
+ }
+ if (cp > 0)
+ {
+ // just append rest of state
+ newFileLoc.append(state.substring(cp));
+ }
+ else
+ {
+ System.err.print("Ignoring incomplete Jmol state for PDB ids: ");
+ newFileLoc = new StringBuilder(state);
+ newFileLoc.append("; load append ");
+ for (File id : oldFiles.keySet())
+ {
+ // add this and any other pdb files that should be present in
+ // the viewer
+ StructureData filedat = oldFiles.get(id);
+ newFileLoc.append(filedat.getFilePath());
+ pdbfilenames.add(filedat.getFilePath());
+ pdbids.add(filedat.getPdbId());
+ seqmaps.add(filedat.getSeqList().toArray(new SequenceI[0]));
+ newFileLoc.append(" \"");
+ newFileLoc.append(filedat.getFilePath());
+ newFileLoc.append("\"");
+
+ }
+ newFileLoc.append(";");
+ }
+
+ if (newFileLoc.length() == 0)
+ {
+ return;
+ }
+ int histbug = newFileLoc.indexOf("history = ");
+ if (histbug > -1)
+ {
+ /*
+ * change "history = [true|false];" to "history = [1|0];"
+ */
+ histbug += 10;
+ int diff = histbug == -1 ? -1 : newFileLoc.indexOf(";", histbug);
+ String val = (diff == -1) ? null : newFileLoc
+ .substring(histbug, diff);
+ if (val != null && val.length() >= 4)
+ {
+ if (val.contains("e")) // eh? what can it be?
+ {
+ if (val.trim().equals("true"))
+ {
+ val = "1";
+ }
+ else
+ {
+ val = "0";
+ }
+ newFileLoc.replace(histbug, diff, val);
+ }
+ }
+ }
+
+ final String[] pdbf = pdbfilenames.toArray(new String[pdbfilenames
+ .size()]);
+ final String[] id = pdbids.toArray(new String[pdbids.size()]);
+ final SequenceI[][] sq = seqmaps
+ .toArray(new SequenceI[seqmaps.size()][]);
+ final String fileloc = newFileLoc.toString();
+ final String sviewid = viewerData.getKey();
+ final AlignFrame alf = af;
+ final Rectangle rect = new Rectangle(svattrib.getX(), svattrib.getY(),
+ svattrib.getWidth(), svattrib.getHeight());
+ try
+ {
+ javax.swing.SwingUtilities.invokeAndWait(new Runnable()
+ {
+ @Override
+ public void run()
+ {
+ JalviewStructureDisplayI sview = null;
+ try
+ {
+ sview = new StructureViewer(alf.alignPanel
+ .getStructureSelectionManager()).createView(
+ StructureViewer.ViewerType.JMOL, pdbf, id, sq,
+ alf.alignPanel, svattrib, fileloc, rect, sviewid);
+ addNewStructureViewer(sview);
+ } catch (OutOfMemoryError ex)
+ {
+ new OOMWarning("restoring structure view for PDB id " + id,
+ (OutOfMemoryError) ex.getCause());
+ if (sview != null && sview.isVisible())
+ {
+ sview.closeViewer(false);
+ sview.setVisible(false);
+ sview.dispose();
+ }
+ }
+ }
+ });
+ } catch (InvocationTargetException ex)
+ {
+ warn("Unexpected error when opening Jmol view.", ex);
+
+ } catch (InterruptedException e)
+ {
+ // e.printStackTrace();
+ }
+
+ }
+
+ /**
+ * Generates a name for the entry in the project jar file to hold state
+ * information for a structure viewer
+ *
+ * @param viewId
+ * @return
+ */
+ protected String getViewerJarEntryName(String viewId)
+ {
+ return VIEWER_PREFIX + viewId;
+ }
+
+ /**
+ * Returns any open frame that matches given structure viewer data. The match
+ * is based on the unique viewId, or (for older project versions) the frame's
+ * geometry.
+ *
+ * @param viewerData
+ * @return
+ */
+ protected StructureViewerBase findMatchingViewer(
+ Entry<String, StructureViewerModel> viewerData)
+ {
+ final String sviewid = viewerData.getKey();
+ final StructureViewerModel svattrib = viewerData.getValue();
+ StructureViewerBase comp = null;
+ JInternalFrame[] frames = getAllFrames();
+ for (JInternalFrame frame : frames)
+ {
+ if (frame instanceof StructureViewerBase)
+ {
+ /*
+ * Post jalview 2.4 schema includes structure view id
+ */
+ if (sviewid != null
+ && ((StructureViewerBase) frame).getViewId()
+ .equals(sviewid))
+ {
+ comp = (StructureViewerBase) frame;
+ break; // break added in 2.9
+ }
+ /*
+ * Otherwise test for matching position and size of viewer frame
+ */
+ else if (frame.getX() == svattrib.getX()
+ && frame.getY() == svattrib.getY()
+ && frame.getHeight() == svattrib.getHeight()
+ && frame.getWidth() == svattrib.getWidth())
+ {
+ comp = (StructureViewerBase) frame;
+ // no break in faint hope of an exact match on viewId
+ }
+ }
+ }
+ return comp;
+ }
+
+ /**
+ * Link an AlignmentPanel to an existing structure viewer.
+ *
+ * @param ap
+ * @param viewer
+ * @param oldFiles
+ * @param useinViewerSuperpos
+ * @param usetoColourbyseq
+ * @param viewerColouring
+ */
+ protected void linkStructureViewer(AlignmentPanel ap,
+ StructureViewerBase viewer, StructureViewerModel stateData)
+ {
+ // NOTE: if the jalview project is part of a shared session then
+ // view synchronization should/could be done here.
+
+ final boolean useinViewerSuperpos = stateData.isAlignWithPanel();
+ final boolean usetoColourbyseq = stateData.isColourWithAlignPanel();
+ final boolean viewerColouring = stateData.isColourByViewer();
+ Map<File, StructureData> oldFiles = stateData.getFileData();
+
+ /*
+ * Add mapping for sequences in this view to an already open viewer
+ */
+ final AAStructureBindingModel binding = viewer.getBinding();
+ for (File id : oldFiles.keySet())
+ {
+ // add this and any other pdb files that should be present in the
+ // viewer
+ StructureData filedat = oldFiles.get(id);
+ String pdbFile = filedat.getFilePath();
+ SequenceI[] seq = filedat.getSeqList().toArray(new SequenceI[0]);
+ binding.getSsm().setMapping(seq, null, pdbFile, DataSourceType.FILE);
+ binding.addSequenceForStructFile(pdbFile, seq);
+ }
+ // and add the AlignmentPanel's reference to the view panel
+ viewer.addAlignmentPanel(ap);
+ if (useinViewerSuperpos)
+ {
+ viewer.useAlignmentPanelForSuperposition(ap);
+ }
+ else
+ {
+ viewer.excludeAlignmentPanelForSuperposition(ap);
+ }
+ if (usetoColourbyseq)
+ {
+ viewer.useAlignmentPanelForColourbyseq(ap, !viewerColouring);
+ }
+ else
+ {
+ viewer.excludeAlignmentPanelForColourbyseq(ap);
+ }
+ }
+
+ /**
+ * Get all frames within the Desktop.
+ *
+ * @return
+ */
+ protected JInternalFrame[] getAllFrames()
+ {
+ JInternalFrame[] frames = null;
+ // TODO is this necessary - is it safe - risk of hanging?
+ do
+ {
+ try
+ {
+ frames = Desktop.desktop.getAllFrames();
+ } catch (ArrayIndexOutOfBoundsException e)
+ {
+ // occasional No such child exceptions are thrown here...
+ try
+ {
+ Thread.sleep(10);
+ } catch (InterruptedException f)
+ {
+ }
+ }
+ } while (frames == null);
+ return frames;
+ }
+
+ /**
+ * Answers true if 'version' is equal to or later than 'supported', where each
+ * is formatted as major/minor versions like "2.8.3" or "2.3.4b1" for bugfix
+ * changes. Development and test values for 'version' are leniently treated
+ * i.e. answer true.
+ *
+ * @param supported
+ * - minimum version we are comparing against
+ * @param version
+ * - version of data being processsed
+ * @return
+ */
+ public static boolean isVersionStringLaterThan(String supported,
+ String version)
+ {
+ if (supported == null || version == null
+ || version.equalsIgnoreCase("DEVELOPMENT BUILD")
+ || version.equalsIgnoreCase("Test")
+ || version.equalsIgnoreCase("AUTOMATED BUILD"))
+ {
+ System.err.println("Assuming project file with "
+ + (version == null ? "null" : version)
+ + " is compatible with Jalview version " + supported);
+ return true;
+ }
+ else
+ {
+ return StringUtils.compareVersions(version, supported, "b") >= 0;
+ }
+ }
+
+ Vector<JalviewStructureDisplayI> newStructureViewers = null;
+
+ protected void addNewStructureViewer(JalviewStructureDisplayI sview)
+ {
+ if (newStructureViewers != null)
+ {
+ sview.getBinding().setFinishedLoadingFromArchive(false);
+ newStructureViewers.add(sview);
+ }
+ }
+
+ protected void setLoadingFinishedForNewStructureViewers()
+ {
+ if (newStructureViewers != null)
+ {
+ for (JalviewStructureDisplayI sview : newStructureViewers)
+ {
+ sview.getBinding().setFinishedLoadingFromArchive(true);
+ }
+ newStructureViewers.clear();
+ newStructureViewers = null;
+ }
+ }
+
+ AlignFrame loadViewport(String file, JSeq[] JSEQ,
+ List<SequenceI> hiddenSeqs, AlignmentI al,
+ JalviewModelSequence jms, Viewport view, String uniqueSeqSetId,
+ String viewId, List<JvAnnotRow> autoAlan)
+ {
+ AlignFrame af = null;
+ af = new AlignFrame(al, view.getWidth(), view.getHeight(),
+ uniqueSeqSetId, viewId);
+
+ af.setFileName(file, FileFormat.Jalview);
+
+ for (int i = 0; i < JSEQ.length; i++)
+ {
+ af.viewport.setSequenceColour(af.viewport.getAlignment()
+ .getSequenceAt(i), new java.awt.Color(JSEQ[i].getColour()));
+ }
+
+ if (al.hasSeqrep())
+ {
+ af.getViewport().setColourByReferenceSeq(true);
+ af.getViewport().setDisplayReferenceSeq(true);
+ }
+
+ af.viewport.setGatherViewsHere(view.getGatheredViews());
+
+ if (view.getSequenceSetId() != null)
+ {
+ AlignmentViewport av = viewportsAdded.get(uniqueSeqSetId);
+
+ af.viewport.setSequenceSetId(uniqueSeqSetId);
+ if (av != null)
+ {
+ // propagate shared settings to this new view
+ af.viewport.setHistoryList(av.getHistoryList());
+ af.viewport.setRedoList(av.getRedoList());
+ }
+ else
+ {
+ viewportsAdded.put(uniqueSeqSetId, af.viewport);
+ }
+ // TODO: check if this method can be called repeatedly without
+ // side-effects if alignpanel already registered.
+ PaintRefresher.Register(af.alignPanel, uniqueSeqSetId);
+ }
+ // apply Hidden regions to view.
+ if (hiddenSeqs != null)
+ {
+ for (int s = 0; s < JSEQ.length; s++)
+ {
+ SequenceGroup hidden = new SequenceGroup();
+ boolean isRepresentative = false;
+ for (int r = 0; r < JSEQ[s].getHiddenSequencesCount(); r++)
+ {
+ isRepresentative = true;
+ SequenceI sequenceToHide = al.getSequenceAt(JSEQ[s]
+ .getHiddenSequences(r));
+ hidden.addSequence(sequenceToHide, false);
+ // remove from hiddenSeqs list so we don't try to hide it twice
+ hiddenSeqs.remove(sequenceToHide);
+ }
+ if (isRepresentative)
+ {
+ SequenceI representativeSequence = al.getSequenceAt(s);
+ hidden.addSequence(representativeSequence, false);
+ af.viewport.hideRepSequences(representativeSequence, hidden);
+ }
+ }
+
+ SequenceI[] hseqs = hiddenSeqs.toArray(new SequenceI[hiddenSeqs
+ .size()]);
+ af.viewport.hideSequence(hseqs);
+
+ }
+ // recover view properties and display parameters
+ if (view.getViewName() != null)
+ {
+ af.viewport.viewName = view.getViewName();
+ af.setInitialTabVisible();
+ }
+ af.setBounds(view.getXpos(), view.getYpos(), view.getWidth(),
+ view.getHeight());
+
+ af.viewport.setShowAnnotation(view.getShowAnnotation());
+ af.viewport.setAbovePIDThreshold(view.getPidSelected());
+ af.viewport.setThreshold(view.getPidThreshold());
+
+ af.viewport.setColourText(view.getShowColourText());
+
+ af.viewport.setConservationSelected(view.getConservationSelected());
+ af.viewport.setIncrement(view.getConsThreshold());
+ af.viewport.setShowJVSuffix(view.getShowFullId());
+ af.viewport.setRightAlignIds(view.getRightAlignIds());
+ af.viewport.setFont(
+ new java.awt.Font(view.getFontName(), view.getFontStyle(), view
+ .getFontSize()), true);
+ ViewStyleI vs = af.viewport.getViewStyle();
+ vs.setScaleProteinAsCdna(view.isScaleProteinAsCdna());
+ af.viewport.setViewStyle(vs);
+ // TODO: allow custom charWidth/Heights to be restored by updating them
+ // after setting font - which means set above to false
+ af.viewport.setRenderGaps(view.getRenderGaps());
+ af.viewport.setWrapAlignment(view.getWrapAlignment());
+ af.viewport.setShowAnnotation(view.getShowAnnotation());
+
+ af.viewport.setShowBoxes(view.getShowBoxes());
+
+ af.viewport.setShowText(view.getShowText());
+
+ af.viewport.setTextColour(new java.awt.Color(view.getTextCol1()));
+ af.viewport.setTextColour2(new java.awt.Color(view.getTextCol2()));
+ af.viewport.setThresholdTextColour(view.getTextColThreshold());
+ af.viewport.setShowUnconserved(view.hasShowUnconserved() ? view
+ .isShowUnconserved() : false);
+ af.viewport.getRanges().setStartRes(view.getStartRes());
+ af.viewport.getRanges().setStartSeq(view.getStartSeq());
+ af.alignPanel.updateLayout();
+ ColourSchemeI cs = null;
+ // apply colourschemes
+ if (view.getBgColour() != null)
+ {
+ if (view.getBgColour().startsWith("ucs"))
+ {
+ cs = getUserColourScheme(jms, view.getBgColour());
+ }
+ else if (view.getBgColour().startsWith("Annotation"))
+ {
+ AnnotationColours viewAnnColour = view.getAnnotationColours();
+ cs = constructAnnotationColour(viewAnnColour, af, al, jms, true);
+
+ // annpos
+
+ }
+ else
+ {
+ cs = ColourSchemeProperty.getColourScheme(al, view.getBgColour());
+ }
+ }
+
+ af.viewport.setGlobalColourScheme(cs);
+ af.viewport.getResidueShading().setThreshold(
+ view.getPidThreshold(), true);
+ af.viewport.getResidueShading().setConsensus(
+ af.viewport.getSequenceConsensusHash());
+ af.viewport.setColourAppliesToAllGroups(false);
+
+ if (view.getConservationSelected() && cs != null)
+ {
+ af.viewport.getResidueShading().setConservationInc(
+ view.getConsThreshold());
+ }
+
+ af.changeColour(cs);
+
+ af.viewport.setColourAppliesToAllGroups(true);
+
+ af.viewport.setShowSequenceFeatures(view.getShowSequenceFeatures());
+
+ if (view.hasCentreColumnLabels())
+ {
+ af.viewport.setCentreColumnLabels(view.getCentreColumnLabels());
+ }
+ if (view.hasIgnoreGapsinConsensus())
+ {
+ af.viewport.setIgnoreGapsConsensus(view.getIgnoreGapsinConsensus(),
+ null);
+ }
+ if (view.hasFollowHighlight())
+ {
+ af.viewport.setFollowHighlight(view.getFollowHighlight());
+ }
+ if (view.hasFollowSelection())
+ {
+ af.viewport.followSelection = view.getFollowSelection();
+ }
+ if (view.hasShowConsensusHistogram())
+ {
+ af.viewport.setShowConsensusHistogram(view
+ .getShowConsensusHistogram());
+ }
+ else
+ {
+ af.viewport.setShowConsensusHistogram(true);
+ }
+ if (view.hasShowSequenceLogo())
+ {
+ af.viewport.setShowSequenceLogo(view.getShowSequenceLogo());
+ }
+ else
+ {
+ af.viewport.setShowSequenceLogo(false);
+ }
+ if (view.hasNormaliseSequenceLogo())
+ {
+ af.viewport.setNormaliseSequenceLogo(view.getNormaliseSequenceLogo());
+ }
+ if (view.hasShowDbRefTooltip())
+ {
+ af.viewport.setShowDBRefs(view.getShowDbRefTooltip());
+ }
+ if (view.hasShowNPfeatureTooltip())
+ {
+ af.viewport.setShowNPFeats(view.hasShowNPfeatureTooltip());
+ }
+ if (view.hasShowGroupConsensus())
+ {
+ af.viewport.setShowGroupConsensus(view.getShowGroupConsensus());
+ }
+ else
+ {
+ af.viewport.setShowGroupConsensus(false);
+ }
+ if (view.hasShowGroupConservation())
+ {
+ af.viewport.setShowGroupConservation(view.getShowGroupConservation());
+ }
+ else
+ {
+ af.viewport.setShowGroupConservation(false);
+ }