+ /**
+ * Save any Varna viewers linked to this sequence. Writes an rnaViewer element
+ * for each viewer, with
+ * <ul>
+ * <li>viewer geometry (position, size, split pane divider location)</li>
+ * <li>index of the selected structure in the viewer (currently shows gapped
+ * or ungapped)</li>
+ * <li>the id of the annotation holding RNA secondary structure</li>
+ * <li>(currently only one SS is shown per viewer, may be more in future)</li>
+ * </ul>
+ * Varna viewer state is also written out (in native Varna XML) to separate
+ * project jar entries. A separate entry is written for each RNA structure
+ * displayed, with the naming convention
+ * <ul>
+ * <li>rna_viewId_sequenceId_annotationId_[gapped|trimmed]</li>
+ * </ul>
+ *
+ * @param jout
+ * @param jseq
+ * @param jds
+ * @param viewIds
+ * @param ap
+ * @param storeDataset
+ */
+ protected void saveRnaViewers(JarOutputStream jout, JSeq jseq,
+ final SequenceI jds, List<String> viewIds, AlignmentPanel ap,
+ boolean storeDataset)
+ {
+ JInternalFrame[] frames = Desktop.desktop.getAllFrames();
+ for (int f = frames.length - 1; f > -1; f--)
+ {
+ if (frames[f] instanceof AppVarna)
+ {
+ AppVarna varna = (AppVarna) frames[f];
+ /*
+ * link the sequence to every viewer that is showing it and is linked to
+ * its alignment panel
+ */
+ if (varna.isListeningFor(jds) && ap == varna.getAlignmentPanel())
+ {
+ String viewId = varna.getViewId();
+ RnaViewer rna = new RnaViewer();
+ rna.setViewId(viewId);
+ rna.setTitle(varna.getTitle());
+ rna.setXpos(varna.getX());
+ rna.setYpos(varna.getY());
+ rna.setWidth(varna.getWidth());
+ rna.setHeight(varna.getHeight());
+ rna.setDividerLocation(varna.getDividerLocation());
+ rna.setSelectedRna(varna.getSelectedIndex());
+ jseq.addRnaViewer(rna);
+
+ /*
+ * Store each Varna panel's state once in the project per sequence.
+ * First time through only (storeDataset==false)
+ */
+ // boolean storeSessions = false;
+ // String sequenceViewId = viewId + seqsToIds.get(jds);
+ // if (!storeDataset && !viewIds.contains(sequenceViewId))
+ // {
+ // viewIds.add(sequenceViewId);
+ // storeSessions = true;
+ // }
+ for (RnaModel model : varna.getModels())
+ {
+ if (model.seq == jds)
+ {
+ /*
+ * VARNA saves each view (sequence or alignment secondary
+ * structure, gapped or trimmed) as a separate XML file
+ */
+ String jarEntryName = rnaSessions.get(model);
+ if (jarEntryName == null)
+ {
+
+ String varnaStateFile = varna.getStateInfo(model.rna);
+ jarEntryName = RNA_PREFIX + viewId + "_" + nextCounter();
+ copyFileToJar(jout, varnaStateFile, jarEntryName);
+ rnaSessions.put(model, jarEntryName);
+ }
+ SecondaryStructure ss = new SecondaryStructure();
+ String annotationId = varna.getAnnotation(jds).annotationId;
+ ss.setAnnotationId(annotationId);
+ ss.setViewerState(jarEntryName);
+ ss.setGapped(model.gapped);
+ ss.setTitle(model.title);
+ rna.addSecondaryStructure(ss);
+ }
+ }
+ }
+ }
+ }
+ }
+
+ /**
+ * Copy the contents of a file to a new entry added to the output jar
+ *
+ * @param jout
+ * @param infilePath
+ * @param jarEntryName
+ */
+ protected void copyFileToJar(JarOutputStream jout, String infilePath,
+ String jarEntryName)
+ {
+ DataInputStream dis = null;
+ try
+ {
+ File file = new File(infilePath);
+ if (file.exists() && jout != null)
+ {
+ dis = new DataInputStream(new FileInputStream(file));
+ byte[] data = new byte[(int) file.length()];
+ dis.readFully(data);
+ writeJarEntry(jout, jarEntryName, data);
+ }
+ } catch (Exception ex)
+ {
+ ex.printStackTrace();
+ } finally
+ {
+ if (dis != null)
+ {
+ try
+ {
+ dis.close();
+ } catch (IOException e)
+ {
+ // ignore
+ }
+ }
+ }
+ }
+
+ /**
+ * Write the data to a new entry of given name in the output jar file
+ *
+ * @param jout
+ * @param jarEntryName
+ * @param data
+ * @throws IOException
+ */
+ protected void writeJarEntry(JarOutputStream jout, String jarEntryName,
+ byte[] data) throws IOException
+ {
+ if (jout != null)
+ {
+ System.out.println("Writing jar entry " + jarEntryName);
+ jout.putNextEntry(new JarEntry(jarEntryName));
+ DataOutputStream dout = new DataOutputStream(jout);
+ dout.write(data, 0, data.length);
+ dout.flush();
+ jout.closeEntry();
+ }
+ }
+
+ /**
+ * Save the state of a structure viewer
+ *
+ * @param ap
+ * @param jds
+ * @param pdb
+ * the archive XML element under which to save the state
+ * @param entry
+ * @param viewIds
+ * @param matchedFile
+ * @param viewFrame
+ * @return
+ */
+ protected String saveStructureState(AlignmentPanel ap, SequenceI jds,
+ Pdbids pdb, PDBEntry entry, List<String> viewIds,
+ String matchedFile, StructureViewerBase viewFrame)
+ {
+ final AAStructureBindingModel bindingModel = viewFrame.getBinding();
+
+ /*
+ * Look for any bindings for this viewer to the PDB file of interest
+ * (including part matches excluding chain id)
+ */
+ for (int peid = 0; peid < bindingModel.getPdbCount(); peid++)
+ {
+ final PDBEntry pdbentry = bindingModel.getPdbEntry(peid);
+ final String pdbId = pdbentry.getId();
+ if (!pdbId.equals(entry.getId())
+ && !(entry.getId().length() > 4 && entry.getId()
+ .toLowerCase().startsWith(pdbId.toLowerCase())))
+ {
+ /*
+ * not interested in a binding to a different PDB entry here
+ */
+ continue;
+ }
+ if (matchedFile == null)
+ {
+ matchedFile = pdbentry.getFile();
+ }
+ else if (!matchedFile.equals(pdbentry.getFile()))
+ {
+ Cache.log
+ .warn("Probably lost some PDB-Sequence mappings for this structure file (which apparently has same PDB Entry code): "
+ + pdbentry.getFile());
+ }
+ // record the
+ // file so we
+ // can get at it if the ID
+ // match is ambiguous (e.g.
+ // 1QIP==1qipA)
+
+ for (int smap = 0; smap < viewFrame.getBinding().getSequence()[peid].length; smap++)
+ {
+ // if (jal.findIndex(jmol.jmb.sequence[peid][smap]) > -1)
+ if (jds == viewFrame.getBinding().getSequence()[peid][smap])
+ {
+ StructureState state = new StructureState();
+ state.setVisible(true);
+ state.setXpos(viewFrame.getX());
+ state.setYpos(viewFrame.getY());
+ state.setWidth(viewFrame.getWidth());
+ state.setHeight(viewFrame.getHeight());
+ final String viewId = viewFrame.getViewId();
+ state.setViewId(viewId);
+ state.setAlignwithAlignPanel(viewFrame.isUsedforaligment(ap));
+ state.setColourwithAlignPanel(viewFrame.isUsedforcolourby(ap));
+ state.setColourByJmol(viewFrame.isColouredByViewer());
+ state.setType(viewFrame.getViewerType().toString());
+ pdb.addStructureState(state);
+ }
+ }
+ }
+ return matchedFile;
+ }
+
+ private AnnotationColours constructAnnotationColours(
+ AnnotationColourGradient acg, List<UserColourScheme> userColours,
+ JalviewModelSequence jms)
+ {
+ AnnotationColours ac = new AnnotationColours();
+ ac.setAboveThreshold(acg.getAboveThreshold());
+ ac.setThreshold(acg.getAnnotationThreshold());
+ ac.setAnnotation(acg.getAnnotation());
+ if (acg.getBaseColour() instanceof jalview.schemes.UserColourScheme)
+ {
+ ac.setColourScheme(setUserColourScheme(acg.getBaseColour(),
+ userColours, jms));
+ }
+ else
+ {
+ ac.setColourScheme(ColourSchemeProperty.getColourName(acg
+ .getBaseColour()));
+ }
+
+ ac.setMaxColour(acg.getMaxColour().getRGB());
+ ac.setMinColour(acg.getMinColour().getRGB());
+ ac.setPerSequence(acg.isSeqAssociated());
+ ac.setPredefinedColours(acg.isPredefinedColours());
+ return ac;
+ }
+
+ private void storeAlignmentAnnotation(AlignmentAnnotation[] aa,
+ IdentityHashMap<SequenceGroup, String> groupRefs,
+ AlignmentViewport av, Set<String> calcIdSet, boolean storeDS,
+ SequenceSet vamsasSet)
+ {
+
+ for (int i = 0; i < aa.length; i++)
+ {
+ Annotation an = new Annotation();
+
+ AlignmentAnnotation annotation = aa[i];
+ if (annotation.annotationId != null)
+ {
+ annotationIds.put(annotation.annotationId, annotation);
+ }
+
+ an.setId(annotation.annotationId);
+
+ an.setVisible(annotation.visible);
+
+ an.setDescription(annotation.description);
+
+ if (annotation.sequenceRef != null)
+ {
+ // 2.9 JAL-1781 xref on sequence id rather than name
+ an.setSequenceRef(seqsToIds.get(annotation.sequenceRef));
+ }
+ if (annotation.groupRef != null)
+ {
+ String groupIdr = groupRefs.get(annotation.groupRef);
+ if (groupIdr == null)
+ {
+ // make a locally unique String
+ groupRefs.put(
+ annotation.groupRef,
+ groupIdr = ("" + System.currentTimeMillis()
+ + annotation.groupRef.getName() + groupRefs
+ .size()));
+ }
+ an.setGroupRef(groupIdr.toString());
+ }
+
+ // store all visualization attributes for annotation
+ an.setGraphHeight(annotation.graphHeight);
+ an.setCentreColLabels(annotation.centreColLabels);
+ an.setScaleColLabels(annotation.scaleColLabel);
+ an.setShowAllColLabels(annotation.showAllColLabels);
+ an.setBelowAlignment(annotation.belowAlignment);
+
+ if (annotation.graph > 0)
+ {
+ an.setGraph(true);
+ an.setGraphType(annotation.graph);
+ an.setGraphGroup(annotation.graphGroup);
+ if (annotation.getThreshold() != null)
+ {
+ ThresholdLine line = new ThresholdLine();
+ line.setLabel(annotation.getThreshold().label);
+ line.setValue(annotation.getThreshold().value);
+ line.setColour(annotation.getThreshold().colour.getRGB());
+ an.setThresholdLine(line);
+ }
+ }
+ else
+ {
+ an.setGraph(false);
+ }
+
+ an.setLabel(annotation.label);
+
+ if (annotation == av.getAlignmentQualityAnnot()
+ || annotation == av.getAlignmentConservationAnnotation()
+ || annotation == av.getAlignmentConsensusAnnotation()
+ || annotation.autoCalculated)
+ {
+ // new way of indicating autocalculated annotation -
+ an.setAutoCalculated(annotation.autoCalculated);
+ }
+ if (annotation.hasScore())
+ {
+ an.setScore(annotation.getScore());
+ }
+
+ if (annotation.getCalcId() != null)
+ {
+ calcIdSet.add(annotation.getCalcId());
+ an.setCalcId(annotation.getCalcId());
+ }
+ if (annotation.hasProperties())
+ {
+ for (String pr : annotation.getProperties())
+ {
+ Property prop = new Property();
+ prop.setName(pr);
+ prop.setValue(annotation.getProperty(pr));
+ an.addProperty(prop);
+ }
+ }
+
+ AnnotationElement ae;
+ if (annotation.annotations != null)
+ {
+ an.setScoreOnly(false);
+ for (int a = 0; a < annotation.annotations.length; a++)
+ {
+ if ((annotation == null) || (annotation.annotations[a] == null))
+ {
+ continue;
+ }
+
+ ae = new AnnotationElement();
+ if (annotation.annotations[a].description != null)
+ {
+ ae.setDescription(annotation.annotations[a].description);
+ }
+ if (annotation.annotations[a].displayCharacter != null)
+ {
+ ae.setDisplayCharacter(annotation.annotations[a].displayCharacter);
+ }
+
+ if (!Float.isNaN(annotation.annotations[a].value))
+ {
+ ae.setValue(annotation.annotations[a].value);
+ }
+
+ ae.setPosition(a);
+ if (annotation.annotations[a].secondaryStructure > ' ')
+ {
+ ae.setSecondaryStructure(annotation.annotations[a].secondaryStructure
+ + "");
+ }
+
+ if (annotation.annotations[a].colour != null
+ && annotation.annotations[a].colour != java.awt.Color.black)
+ {
+ ae.setColour(annotation.annotations[a].colour.getRGB());
+ }
+
+ an.addAnnotationElement(ae);
+ if (annotation.autoCalculated)
+ {
+ // only write one non-null entry into the annotation row -
+ // sufficient to get the visualization attributes necessary to
+ // display data
+ continue;
+ }
+ }
+ }
+ else
+ {
+ an.setScoreOnly(true);
+ }
+ if (!storeDS || (storeDS && !annotation.autoCalculated))
+ {
+ // skip autocalculated annotation - these are only provided for
+ // alignments
+ vamsasSet.addAnnotation(an);
+ }
+ }
+
+ }
+