X-Git-Url: http://source.jalview.org/gitweb/?a=blobdiff_plain;f=src%2Fjalview%2Fgui%2FJalview2XML.java;h=d920c7fbe4b7fdfb85d73c980e484e381466c37a;hb=17e77c3f2949a0729322b4a8d907f3f34b6a9914;hp=c960287d73794b1c8f14808bd13f527d63630d14;hpb=c4ec878c9cb59fc40a88ed8ecdf5fda46f3de111;p=jalview.git diff --git a/src/jalview/gui/Jalview2XML.java b/src/jalview/gui/Jalview2XML.java index c960287..d920c7f 100644 --- a/src/jalview/gui/Jalview2XML.java +++ b/src/jalview/gui/Jalview2XML.java @@ -1,6 +1,6 @@ /* - * Jalview - A Sequence Alignment Editor and Viewer (Version 2.8.2) - * Copyright (C) 2014 The Jalview Authors + * Jalview - A Sequence Alignment Editor and Viewer (Version 2.9) + * Copyright (C) 2015 The Jalview Authors * * This file is part of Jalview. * @@ -20,15 +20,22 @@ */ package jalview.gui; +import jalview.api.ViewStyleI; import jalview.api.structures.JalviewStructureDisplayI; import jalview.bin.Cache; +import jalview.datamodel.AlignedCodonFrame; import jalview.datamodel.Alignment; import jalview.datamodel.AlignmentAnnotation; import jalview.datamodel.AlignmentI; import jalview.datamodel.PDBEntry; +import jalview.datamodel.RnaViewerModel; +import jalview.datamodel.SequenceGroup; import jalview.datamodel.SequenceI; +import jalview.datamodel.StructureViewerModel; +import jalview.datamodel.StructureViewerModel.StructureData; +import jalview.ext.varna.RnaModel; +import jalview.gui.StructureViewer.ViewerType; import jalview.schemabinding.version2.AlcodMap; -import jalview.schemabinding.version2.Alcodon; import jalview.schemabinding.version2.AlcodonFrame; import jalview.schemabinding.version2.Annotation; import jalview.schemabinding.version2.AnnotationColours; @@ -50,6 +57,8 @@ import jalview.schemabinding.version2.OtherData; import jalview.schemabinding.version2.PdbentryItem; import jalview.schemabinding.version2.Pdbids; import jalview.schemabinding.version2.Property; +import jalview.schemabinding.version2.RnaViewer; +import jalview.schemabinding.version2.SecondaryStructure; import jalview.schemabinding.version2.Sequence; import jalview.schemabinding.version2.SequenceSet; import jalview.schemabinding.version2.SequenceSetProperties; @@ -72,6 +81,8 @@ import jalview.util.MessageManager; import jalview.util.Platform; import jalview.util.jarInputStreamProvider; import jalview.viewmodel.AlignmentViewport; +import jalview.viewmodel.seqfeatures.FeatureRendererSettings; +import jalview.viewmodel.seqfeatures.FeaturesDisplayed; import jalview.ws.jws2.Jws2Discoverer; import jalview.ws.jws2.dm.AAConSettings; import jalview.ws.jws2.jabaws2.Jws2Instance; @@ -100,6 +111,7 @@ import java.util.HashSet; import java.util.Hashtable; import java.util.IdentityHashMap; import java.util.Iterator; +import java.util.LinkedHashMap; import java.util.List; import java.util.Map; import java.util.Map.Entry; @@ -114,6 +126,7 @@ import javax.swing.JInternalFrame; import javax.swing.JOptionPane; import javax.swing.SwingUtilities; +import org.exolab.castor.xml.Marshaller; import org.exolab.castor.xml.Unmarshaller; /** @@ -128,43 +141,14 @@ import org.exolab.castor.xml.Unmarshaller; */ public class Jalview2XML { + private static final String VIEWER_PREFIX = "viewer_"; - private class ViewerData - { - - private int x; - - private int y; - - private int width; - - private int height; - - private boolean alignWithPanel; - - private boolean colourWithAlignPanel; - - private boolean colourByViewer; + private static final String RNA_PREFIX = "rna_"; - private String stateData = ""; + private static final String UTF_8 = "UTF-8"; - // todo: java bean in place of Object [] - private Map fileData = new HashMap(); - - public ViewerData(int x, int y, int width, int height, - boolean alignWithPanel, boolean colourWithAlignPanel, - boolean colourByViewer) - { - this.x = x; - this.y = y; - this.width = width; - this.height = height; - this.alignWithPanel = alignWithPanel; - this.colourWithAlignPanel = colourWithAlignPanel; - this.colourByViewer = colourByViewer; - } - - } + // use this with nextCounter() to make unique names for entities + private int counter = 0; /* * SequenceI reference -> XML ID string in jalview XML. Populated as XML reps @@ -183,6 +167,18 @@ public class Jalview2XML boolean raiseGUI = true; // whether errors are raised in dialog boxes or not + /* + * Map of reconstructed AlignFrame objects that appear to have come from + * SplitFrame objects (have a dna/protein complement view). + */ + private Map splitFrameCandidates = new HashMap(); + + /* + * Map from displayed rna structure models to their saved session state jar + * entry names + */ + private Map rnaSessions = new HashMap(); + /** * create/return unique hash string for sq * @@ -331,12 +327,12 @@ public class Jalview2XML } /** - * This maintains a list of viewports, the key being the seqSetId. Important - * to set historyItem and redoList for multiple views + * This maintains a map of viewports, the key being the seqSetId. Important to + * set historyItem and redoList for multiple views */ - Hashtable viewportsAdded; + Map viewportsAdded = new HashMap(); - Hashtable annotationIds = new Hashtable(); + Map annotationIds = new HashMap(); String uniqueSetSuffix = ""; @@ -392,7 +388,7 @@ public class Jalview2XML */ public void saveState(JarOutputStream jout) { - JInternalFrame[] frames = Desktop.desktop.getAllFrames(); + AlignFrame[] frames = Desktop.getAlignFrames(); if (frames == null) { @@ -401,78 +397,54 @@ public class Jalview2XML Hashtable dsses = new Hashtable(); + /* + * ensure cached data is clear before starting + */ + // todo tidy up seqRefIds, seqsToIds initialisation / reset + rnaSessions.clear(); + splitFrameCandidates.clear(); + try { // NOTE UTF-8 MUST BE USED FOR WRITING UNICODE CHARS // ////////////////////////////////////////////////// - Vector shortNames = new Vector(); + List shortNames = new ArrayList(); + List viewIds = new ArrayList(); // REVERSE ORDER for (int i = frames.length - 1; i > -1; i--) { - if (frames[i] instanceof AlignFrame) + AlignFrame af = frames[i]; + // skip ? + if (skipList != null + && skipList + .containsKey(af.getViewport().getSequenceSetId())) { - AlignFrame af = (AlignFrame) frames[i]; - // skip ? - if (skipList != null - && skipList.containsKey(af.getViewport() - .getSequenceSetId())) - { - continue; - } - - String shortName = af.getTitle(); - - if (shortName.indexOf(File.separatorChar) > -1) - { - shortName = shortName.substring(shortName - .lastIndexOf(File.separatorChar) + 1); - } - - int count = 1; - - while (shortNames.contains(shortName)) - { - if (shortName.endsWith("_" + (count - 1))) - { - shortName = shortName - .substring(0, shortName.lastIndexOf("_")); - } + continue; + } - shortName = shortName.concat("_" + count); - count++; - } + String shortName = makeFilename(af, shortNames); - shortNames.addElement(shortName); + int ap, apSize = af.alignPanels.size(); - if (!shortName.endsWith(".xml")) + for (ap = 0; ap < apSize; ap++) + { + AlignmentPanel apanel = af.alignPanels.get(ap); + String fileName = apSize == 1 ? shortName : ap + shortName; + if (!fileName.endsWith(".xml")) { - shortName = shortName + ".xml"; + fileName = fileName + ".xml"; } - int ap, apSize = af.alignPanels.size(); + saveState(apanel, fileName, jout, viewIds); - for (ap = 0; ap < apSize; ap++) + String dssid = getDatasetIdRef(af.getViewport().getAlignment() + .getDataset()); + if (!dsses.containsKey(dssid)) { - AlignmentPanel apanel = (AlignmentPanel) af.alignPanels - .elementAt(ap); - String fileName = apSize == 1 ? shortName : ap + shortName; - if (!fileName.endsWith(".xml")) - { - fileName = fileName + ".xml"; - } - - saveState(apanel, fileName, jout); - - String dssid = getDatasetIdRef(af.getViewport().getAlignment() - .getDataset()); - if (!dsses.containsKey(dssid)) - { - dsses.put(dssid, af); - } - + dsses.put(dssid, af); } } } @@ -500,26 +472,69 @@ public class Jalview2XML } } + /** + * Generates a distinct file name, based on the title of the AlignFrame, by + * appending _n for increasing n until an unused name is generated. The new + * name (without its extension) is added to the list. + * + * @param af + * @param namesUsed + * @return the generated name, with .xml extension + */ + protected String makeFilename(AlignFrame af, List namesUsed) + { + String shortName = af.getTitle(); + + if (shortName.indexOf(File.separatorChar) > -1) + { + shortName = shortName.substring(shortName + .lastIndexOf(File.separatorChar) + 1); + } + + int count = 1; + + while (namesUsed.contains(shortName)) + { + if (shortName.endsWith("_" + (count - 1))) + { + shortName = shortName.substring(0, shortName.lastIndexOf("_")); + } + + shortName = shortName.concat("_" + count); + count++; + } + + namesUsed.add(shortName); + + if (!shortName.endsWith(".xml")) + { + shortName = shortName + ".xml"; + } + return shortName; + } + // USE THIS METHOD TO SAVE A SINGLE ALIGNMENT WINDOW public boolean saveAlignment(AlignFrame af, String jarFile, String fileName) { try { - int ap, apSize = af.alignPanels.size(); + int ap = 0; + int apSize = af.alignPanels.size(); FileOutputStream fos = new FileOutputStream(jarFile); JarOutputStream jout = new JarOutputStream(fos); Hashtable dsses = new Hashtable(); - for (ap = 0; ap < apSize; ap++) + List viewIds = new ArrayList(); + + for (AlignmentPanel apanel : af.alignPanels) { - AlignmentPanel apanel = (AlignmentPanel) af.alignPanels - .elementAt(ap); String jfileName = apSize == 1 ? fileName : fileName + ap; + ap++; if (!jfileName.endsWith(".xml")) { jfileName = jfileName + ".xml"; } - saveState(apanel, jfileName, jout); + saveState(apanel, jfileName, jout, viewIds); String dssid = getDatasetIdRef(af.getViewport().getAlignment() .getDataset()); if (!dsses.containsKey(dssid)) @@ -557,7 +572,7 @@ public class Jalview2XML { jfileName = jfileName + ".xml"; } - saveState(_af.alignPanel, jfileName, true, jout); + saveState(_af.alignPanel, jfileName, true, jout, null); } } @@ -571,13 +586,14 @@ public class Jalview2XML * name of alignment panel written to output stream * @param jout * jar output stream + * @param viewIds * @param out * jar entry name */ public JalviewModel saveState(AlignmentPanel ap, String fileName, - JarOutputStream jout) + JarOutputStream jout, List viewIds) { - return saveState(ap, fileName, false, jout); + return saveState(ap, fileName, false, jout, viewIds); } /** @@ -597,9 +613,15 @@ public class Jalview2XML * jar entry name */ public JalviewModel saveState(AlignmentPanel ap, String fileName, - boolean storeDS, JarOutputStream jout) + boolean storeDS, JarOutputStream jout, List viewIds) { + if (viewIds == null) + { + viewIds = new ArrayList(); + } + initSeqRefs(); + List userColours = new ArrayList(); AlignViewport av = ap.av; @@ -651,14 +673,12 @@ public class Jalview2XML Set calcIdSet = new HashSet(); // SAVE SEQUENCES - String id = ""; - jalview.datamodel.SequenceI jds, jdatasq; for (int i = 0; i < jal.getHeight(); i++) { - jds = jal.getSequenceAt(i); - jdatasq = jds.getDatasetSequence() == null ? jds : jds - .getDatasetSequence(); - id = seqHash(jds); + final SequenceI jds = jal.getSequenceAt(i); + final SequenceI jdatasq = jds.getDatasetSequence() == null ? jds + : jds.getDatasetSequence(); + String id = seqHash(jds); if (seqRefIds.get(id) != null) { @@ -714,10 +734,9 @@ public class Jalview2XML } } - if (jdatasq.getSequenceFeatures() != null) + if (jds.getSequenceFeatures() != null) { - jalview.datamodel.SequenceFeature[] sf = jdatasq - .getSequenceFeatures(); + jalview.datamodel.SequenceFeature[] sf = jds.getSequenceFeatures(); int index = 0; while (index < sf.length) { @@ -758,24 +777,24 @@ public class Jalview2XML } } - if (jdatasq.getPDBId() != null) + if (jdatasq.getAllPDBEntries() != null) { - Enumeration en = jdatasq.getPDBId().elements(); + Enumeration en = jdatasq.getAllPDBEntries().elements(); while (en.hasMoreElements()) { Pdbids pdb = new Pdbids(); jalview.datamodel.PDBEntry entry = (jalview.datamodel.PDBEntry) en .nextElement(); - pdb.setId(entry.getId()); + String pdbId = entry.getId(); + pdb.setId(pdbId); pdb.setType(entry.getType()); /* - * Store any JMol or Chimera views associated with this sequence. This + * Store any structure views associated with this sequence. This * section copes with duplicate entries in the project, so a dataset * only view *should* be coped with sensibly. */ - List viewIds = new ArrayList(); // This must have been loaded, is it still visible? JInternalFrame[] frames = Desktop.desktop.getAllFrames(); String matchedFile = null; @@ -786,6 +805,25 @@ public class Jalview2XML StructureViewerBase viewFrame = (StructureViewerBase) frames[f]; matchedFile = saveStructureState(ap, jds, pdb, entry, viewIds, matchedFile, viewFrame); + /* + * Only store each structure viewer's state once in the project + * jar. First time through only (storeDS==false) + */ + String viewId = viewFrame.getViewId(); + if (!storeDS && !viewIds.contains(viewId)) + { + viewIds.add(viewId); + try + { + String viewerState = viewFrame.getStateInfo(); + writeJarEntry(jout, getViewerJarEntryName(viewId), + viewerState.getBytes()); + } catch (IOException e) + { + System.err.println("Error saving viewer state: " + + e.getMessage()); + } + } } } @@ -802,47 +840,14 @@ public class Jalview2XML pdbfiles = new ArrayList(); } - if (!pdbfiles.contains(entry.getId())) + if (!pdbfiles.contains(pdbId)) { - pdbfiles.add(entry.getId()); - DataInputStream dis = null; - try - { - File file = new File(matchedFile); - if (file.exists() && jout != null) - { - byte[] data = new byte[(int) file.length()]; - jout.putNextEntry(new JarEntry(entry.getId())); - dis = new DataInputStream( - new FileInputStream(file)); - dis.readFully(data); - - DataOutputStream dout = new DataOutputStream(jout); - dout.write(data, 0, data.length); - dout.flush(); - jout.closeEntry(); - } - } catch (Exception ex) - { - ex.printStackTrace(); - } finally - { - if (dis != null) - { - try - { - dis.close(); - } catch (IOException e) - { - // ignore - } - } - } - + pdbfiles.add(pdbId); + copyFileToJar(jout, matchedFile, pdbId); } } - if (entry.getProperty() != null) + if (entry.getProperty() != null && !entry.getProperty().isEmpty()) { PdbentryItem item = new PdbentryItem(); Hashtable properties = entry.getProperty(); @@ -862,6 +867,8 @@ public class Jalview2XML } } + saveRnaViewers(jout, jseq, jds, viewIds, ap, storeDS); + jms.addJSeq(jseq); } @@ -870,31 +877,18 @@ public class Jalview2XML jal = av.getAlignment(); } // SAVE MAPPINGS - if (jal.getCodonFrames() != null && jal.getCodonFrames().length > 0) + if (jal.getCodonFrames() != null) { - jalview.datamodel.AlignedCodonFrame[] jac = jal.getCodonFrames(); - for (int i = 0; i < jac.length; i++) + Set jac = jal.getCodonFrames(); + for (AlignedCodonFrame acf : jac) { AlcodonFrame alc = new AlcodonFrame(); vamsasSet.addAlcodonFrame(alc); - for (int p = 0; p < jac[i].aaWidth; p++) - { - Alcodon cmap = new Alcodon(); - if (jac[i].codons[p] != null) - { - // Null codons indicate a gapped column in the translated peptide - // alignment. - cmap.setPos1(jac[i].codons[p][0]); - cmap.setPos2(jac[i].codons[p][1]); - cmap.setPos3(jac[i].codons[p][2]); - } - alc.addAlcodon(cmap); - } - if (jac[i].getProtMappings() != null - && jac[i].getProtMappings().length > 0) + if (acf.getProtMappings() != null + && acf.getProtMappings().length > 0) { - SequenceI[] dnas = jac[i].getdnaSeqs(); - jalview.datamodel.Mapping[] pmaps = jac[i].getProtMappings(); + SequenceI[] dnas = acf.getdnaSeqs(); + jalview.datamodel.Mapping[] pmaps = acf.getProtMappings(); for (int m = 0; m < pmaps.length; m++) { AlcodMap alcmap = new AlcodMap(); @@ -904,6 +898,37 @@ public class Jalview2XML alc.addAlcodMap(alcmap); } } + + // { + // AlcodonFrame alc = new AlcodonFrame(); + // vamsasSet.addAlcodonFrame(alc); + // for (int p = 0; p < acf.aaWidth; p++) + // { + // Alcodon cmap = new Alcodon(); + // if (acf.codons[p] != null) + // { + // // Null codons indicate a gapped column in the translated peptide + // // alignment. + // cmap.setPos1(acf.codons[p][0]); + // cmap.setPos2(acf.codons[p][1]); + // cmap.setPos3(acf.codons[p][2]); + // } + // alc.addAlcodon(cmap); + // } + // if (acf.getProtMappings() != null + // && acf.getProtMappings().length > 0) + // { + // SequenceI[] dnas = acf.getdnaSeqs(); + // jalview.datamodel.Mapping[] pmaps = acf.getProtMappings(); + // for (int m = 0; m < pmaps.length; m++) + // { + // AlcodMap alcmap = new AlcodMap(); + // alcmap.setDnasq(seqHash(dnas[m])); + // alcmap.setMapping(createVamsasMapping(pmaps[m], dnas[m], null, + // false)); + // alc.addAlcodMap(alcmap); + // } + // } } } @@ -951,17 +976,18 @@ public class Jalview2XML } } } + // SAVE ANNOTATIONS /** * store forward refs from an annotationRow to any groups */ - IdentityHashMap groupRefs = new IdentityHashMap(); + IdentityHashMap groupRefs = new IdentityHashMap(); if (storeDS) { for (SequenceI sq : jal.getSequences()) { // Store annotation on dataset sequences only - jalview.datamodel.AlignmentAnnotation[] aa = sq.getAnnotation(); + AlignmentAnnotation[] aa = sq.getAnnotation(); if (aa != null && aa.length > 0) { storeAlignmentAnnotation(aa, groupRefs, av, calcIdSet, storeDS, @@ -974,8 +1000,7 @@ public class Jalview2XML if (jal.getAlignmentAnnotation() != null) { // Store the annotation shown on the alignment. - jalview.datamodel.AlignmentAnnotation[] aa = jal - .getAlignmentAnnotation(); + AlignmentAnnotation[] aa = jal.getAlignmentAnnotation(); storeAlignmentAnnotation(aa, groupRefs, av, calcIdSet, storeDS, vamsasSet); } @@ -987,70 +1012,66 @@ public class Jalview2XML int i = -1; for (jalview.datamodel.SequenceGroup sg : jal.getGroups()) { - groups[++i] = new JGroup(); + JGroup jGroup = new JGroup(); + groups[++i] = jGroup; - groups[i].setStart(sg.getStartRes()); - groups[i].setEnd(sg.getEndRes()); - groups[i].setName(sg.getName()); + jGroup.setStart(sg.getStartRes()); + jGroup.setEnd(sg.getEndRes()); + jGroup.setName(sg.getName()); if (groupRefs.containsKey(sg)) { - // group has references so set it's ID field - groups[i].setId(groupRefs.get(sg).toString()); + // group has references so set its ID field + jGroup.setId(groupRefs.get(sg)); } if (sg.cs != null) { if (sg.cs.conservationApplied()) { - groups[i].setConsThreshold(sg.cs.getConservationInc()); + jGroup.setConsThreshold(sg.cs.getConservationInc()); if (sg.cs instanceof jalview.schemes.UserColourScheme) { - groups[i].setColour(setUserColourScheme(sg.cs, userColours, - jms)); + jGroup.setColour(setUserColourScheme(sg.cs, userColours, jms)); } else { - groups[i] - .setColour(ColourSchemeProperty.getColourName(sg.cs)); + jGroup.setColour(ColourSchemeProperty.getColourName(sg.cs)); } } else if (sg.cs instanceof jalview.schemes.AnnotationColourGradient) { - groups[i].setColour("AnnotationColourGradient"); - groups[i].setAnnotationColours(constructAnnotationColours( + jGroup.setColour("AnnotationColourGradient"); + jGroup.setAnnotationColours(constructAnnotationColours( (jalview.schemes.AnnotationColourGradient) sg.cs, userColours, jms)); } else if (sg.cs instanceof jalview.schemes.UserColourScheme) { - groups[i] - .setColour(setUserColourScheme(sg.cs, userColours, jms)); + jGroup.setColour(setUserColourScheme(sg.cs, userColours, jms)); } else { - groups[i].setColour(ColourSchemeProperty.getColourName(sg.cs)); + jGroup.setColour(ColourSchemeProperty.getColourName(sg.cs)); } - groups[i].setPidThreshold(sg.cs.getThreshold()); + jGroup.setPidThreshold(sg.cs.getThreshold()); } - groups[i].setOutlineColour(sg.getOutlineColour().getRGB()); - groups[i].setDisplayBoxes(sg.getDisplayBoxes()); - groups[i].setDisplayText(sg.getDisplayText()); - groups[i].setColourText(sg.getColourText()); - groups[i].setTextCol1(sg.textColour.getRGB()); - groups[i].setTextCol2(sg.textColour2.getRGB()); - groups[i].setTextColThreshold(sg.thresholdTextColour); - groups[i].setShowUnconserved(sg.getShowNonconserved()); - groups[i].setIgnoreGapsinConsensus(sg.getIgnoreGapsConsensus()); - groups[i].setShowConsensusHistogram(sg.isShowConsensusHistogram()); - groups[i].setShowSequenceLogo(sg.isShowSequenceLogo()); - groups[i].setNormaliseSequenceLogo(sg.isNormaliseSequenceLogo()); - for (int s = 0; s < sg.getSize(); s++) + jGroup.setOutlineColour(sg.getOutlineColour().getRGB()); + jGroup.setDisplayBoxes(sg.getDisplayBoxes()); + jGroup.setDisplayText(sg.getDisplayText()); + jGroup.setColourText(sg.getColourText()); + jGroup.setTextCol1(sg.textColour.getRGB()); + jGroup.setTextCol2(sg.textColour2.getRGB()); + jGroup.setTextColThreshold(sg.thresholdTextColour); + jGroup.setShowUnconserved(sg.getShowNonconserved()); + jGroup.setIgnoreGapsinConsensus(sg.getIgnoreGapsConsensus()); + jGroup.setShowConsensusHistogram(sg.isShowConsensusHistogram()); + jGroup.setShowSequenceLogo(sg.isShowSequenceLogo()); + jGroup.setNormaliseSequenceLogo(sg.isNormaliseSequenceLogo()); + for (SequenceI seq : sg.getSequences()) { - jalview.datamodel.Sequence seq = (jalview.datamodel.Sequence) sg - .getSequenceAt(s); - groups[i].addSeq(seqHash(seq)); + jGroup.addSeq(seqHash(seq)); } } @@ -1064,23 +1085,22 @@ public class Jalview2XML view.setSequenceSetId(makeHashCode(av.getSequenceSetId(), av.getSequenceSetId())); view.setId(av.getViewId()); - view.setViewName(av.viewName); - view.setGatheredViews(av.gatherViewsHere); - - if (ap.av.explodedPosition != null) + if (av.getCodingComplement() != null) { - view.setXpos(av.explodedPosition.x); - view.setYpos(av.explodedPosition.y); - view.setWidth(av.explodedPosition.width); - view.setHeight(av.explodedPosition.height); + view.setComplementId(av.getCodingComplement().getViewId()); } - else + view.setViewName(av.viewName); + view.setGatheredViews(av.isGatherViewsHere()); + + Rectangle position = ap.av.getExplodedGeometry(); + if (position == null) { - view.setXpos(ap.alignFrame.getBounds().x); - view.setYpos(ap.alignFrame.getBounds().y); - view.setWidth(ap.alignFrame.getBounds().width); - view.setHeight(ap.alignFrame.getBounds().height); + position = ap.alignFrame.getBounds(); } + view.setXpos(position.x); + view.setYpos(position.y); + view.setWidth(position.width); + view.setHeight(position.height); view.setStartRes(av.startRes); view.setStartSeq(av.startSeq); @@ -1130,34 +1150,37 @@ public class Jalview2XML view.setFontName(av.font.getName()); view.setFontSize(av.font.getSize()); view.setFontStyle(av.font.getStyle()); - view.setRenderGaps(av.renderGaps); - view.setShowAnnotation(av.getShowAnnotation()); + view.setScaleProteinAsCdna(av.getViewStyle().isScaleProteinAsCdna()); + view.setRenderGaps(av.isRenderGaps()); + view.setShowAnnotation(av.isShowAnnotation()); view.setShowBoxes(av.getShowBoxes()); view.setShowColourText(av.getColourText()); view.setShowFullId(av.getShowJVSuffix()); view.setRightAlignIds(av.isRightAlignIds()); - view.setShowSequenceFeatures(av.showSequenceFeatures); + view.setShowSequenceFeatures(av.isShowSequenceFeatures()); view.setShowText(av.getShowText()); view.setShowUnconserved(av.getShowUnconserved()); view.setWrapAlignment(av.getWrapAlignment()); - view.setTextCol1(av.textColour.getRGB()); - view.setTextCol2(av.textColour2.getRGB()); - view.setTextColThreshold(av.thresholdTextColour); + view.setTextCol1(av.getTextColour().getRGB()); + view.setTextCol2(av.getTextColour2().getRGB()); + view.setTextColThreshold(av.getThresholdTextColour()); view.setShowConsensusHistogram(av.isShowConsensusHistogram()); view.setShowSequenceLogo(av.isShowSequenceLogo()); view.setNormaliseSequenceLogo(av.isNormaliseSequenceLogo()); view.setShowGroupConsensus(av.isShowGroupConsensus()); view.setShowGroupConservation(av.isShowGroupConservation()); - view.setShowNPfeatureTooltip(av.isShowNpFeats()); - view.setShowDbRefTooltip(av.isShowDbRefs()); - view.setFollowHighlight(av.followHighlight); + view.setShowNPfeatureTooltip(av.isShowNPFeats()); + view.setShowDbRefTooltip(av.isShowDBRefs()); + view.setFollowHighlight(av.isFollowHighlight()); view.setFollowSelection(av.followSelection); - view.setIgnoreGapsinConsensus(av.getIgnoreGapsConsensus()); + view.setIgnoreGapsinConsensus(av.isIgnoreGapsConsensus()); if (av.getFeaturesDisplayed() != null) { jalview.schemabinding.version2.FeatureSettings fs = new jalview.schemabinding.version2.FeatureSettings(); - String[] renderOrder = ap.getSeqPanel().seqCanvas.getFeatureRenderer().renderOrder; + String[] renderOrder = ap.getSeqPanel().seqCanvas + .getFeatureRenderer().getRenderOrder() + .toArray(new String[0]); Vector settingsAdded = new Vector(); Object gstyle = null; @@ -1184,12 +1207,13 @@ public class Jalview2XML } else { - setting.setColour(ap.getSeqPanel().seqCanvas.getFeatureRenderer() - .getColour(renderOrder[ro]).getRGB()); + setting.setColour(ap.getSeqPanel().seqCanvas + .getFeatureRenderer().getColour(renderOrder[ro]) + .getRGB()); } - setting.setDisplay(av.getFeaturesDisplayed() - .containsKey(renderOrder[ro])); + setting.setDisplay(av.getFeaturesDisplayed().isVisible( + renderOrder[ro])); float rorder = ap.getSeqPanel().seqCanvas.getFeatureRenderer() .getOrder(renderOrder[ro]); if (rorder > -1) @@ -1202,8 +1226,8 @@ public class Jalview2XML } // Make sure we save none displayed feature settings - Iterator en = ap.getSeqPanel().seqCanvas.getFeatureRenderer().featureColours - .keySet().iterator(); + Iterator en = ap.getSeqPanel().seqCanvas.getFeatureRenderer() + .getFeatureColours().keySet().iterator(); while (en.hasNext()) { String key = en.next().toString(); @@ -1227,8 +1251,9 @@ public class Jalview2XML fs.addSetting(setting); settingsAdded.addElement(key); } - en = ap.getSeqPanel().seqCanvas.getFeatureRenderer().featureGroups - .keySet().iterator(); + // is groups actually supposed to be a map here ? + en = ap.getSeqPanel().seqCanvas.getFeatureRenderer() + .getFeatureGroups().iterator(); Vector groupsAdded = new Vector(); while (en.hasNext()) { @@ -1240,7 +1265,7 @@ public class Jalview2XML Group g = new Group(); g.setName(grp); g.setDisplay(((Boolean) ap.getSeqPanel().seqCanvas - .getFeatureRenderer().featureGroups.get(grp)) + .getFeatureRenderer().checkGroupVisibility(grp, false)) .booleanValue()); fs.addGroup(g); groupsAdded.addElement(grp); @@ -1261,8 +1286,8 @@ public class Jalview2XML for (int c = 0; c < av.getColumnSelection().getHiddenColumns() .size(); c++) { - int[] region = (int[]) av.getColumnSelection() - .getHiddenColumns().elementAt(c); + int[] region = av.getColumnSelection().getHiddenColumns() + .get(c); HiddenColumns hc = new HiddenColumns(); hc.setStart(region[0]); hc.setEnd(region[1]); @@ -1298,12 +1323,12 @@ public class Jalview2XML // using save and then load try { + System.out.println("Writing jar entry " + fileName); JarEntry entry = new JarEntry(fileName); jout.putNextEntry(entry); PrintWriter pout = new PrintWriter(new OutputStreamWriter(jout, - "UTF-8")); - org.exolab.castor.xml.Marshaller marshaller = new org.exolab.castor.xml.Marshaller( - pout); + UTF_8)); + Marshaller marshaller = new Marshaller(pout); marshaller.marshal(object); pout.flush(); jout.closeEntry(); @@ -1317,6 +1342,165 @@ public class Jalview2XML } /** + * Save any Varna viewers linked to this sequence. Writes an rnaViewer element + * for each viewer, with + *
    + *
  • viewer geometry (position, size, split pane divider location)
  • + *
  • index of the selected structure in the viewer (currently shows gapped + * or ungapped)
  • + *
  • the id of the annotation holding RNA secondary structure
  • + *
  • (currently only one SS is shown per viewer, may be more in future)
  • + *
+ * 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 + *
    + *
  • rna_viewId_sequenceId_annotationId_[gapped|trimmed]
  • + *
+ * + * @param jout + * @param jseq + * @param jds + * @param viewIds + * @param ap + * @param storeDataset + */ + protected void saveRnaViewers(JarOutputStream jout, JSeq jseq, + final SequenceI jds, List viewIds, AlignmentPanel ap, + boolean storeDataset) + { + if (Desktop.desktop == null) + { + return; + } + 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 @@ -1333,26 +1517,30 @@ public class Jalview2XML Pdbids pdb, PDBEntry entry, List viewIds, String matchedFile, StructureViewerBase viewFrame) { - final AAStructureBindingModel bindingModel = viewFrame - .getBinding(); - for (int peid = 0; peid < bindingModel - .getPdbCount(); peid++) + 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()))) + .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())) + 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): " @@ -1363,10 +1551,8 @@ public class Jalview2XML // can get at it if the ID // match is ambiguous (e.g. // 1QIP==1qipA) - String statestring = viewFrame.getStateInfo(); - for (int smap = 0; smap < viewFrame.getBinding() - .getSequence()[peid].length; smap++) + 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]) @@ -1380,21 +1566,9 @@ public class Jalview2XML final String viewId = viewFrame.getViewId(); state.setViewId(viewId); state.setAlignwithAlignPanel(viewFrame.isUsedforaligment(ap)); - state.setColourwithAlignPanel(viewFrame - .isUsedforcolourby(ap)); + state.setColourwithAlignPanel(viewFrame.isUsedforcolourby(ap)); state.setColourByJmol(viewFrame.isColouredByViewer()); - /* - * Only store each structure viewer's state once in each XML document. - */ - if (!viewIds.contains(viewId)) - { - viewIds.add(viewId); - state.setContent(statestring.replaceAll("\n", "")); - } - else - { - state.setContent("# duplicate state"); - } + state.setType(viewFrame.getViewerType().toString()); pdb.addStructureState(state); } } @@ -1429,62 +1603,65 @@ public class Jalview2XML } private void storeAlignmentAnnotation(AlignmentAnnotation[] aa, - IdentityHashMap groupRefs, AlignmentViewport av, - Set calcIdSet, boolean storeDS, SequenceSet vamsasSet) + IdentityHashMap groupRefs, + AlignmentViewport av, Set calcIdSet, boolean storeDS, + SequenceSet vamsasSet) { for (int i = 0; i < aa.length; i++) { Annotation an = new Annotation(); - if (aa[i].annotationId != null) + AlignmentAnnotation annotation = aa[i]; + if (annotation.annotationId != null) { - annotationIds.put(aa[i].annotationId, aa[i]); + annotationIds.put(annotation.annotationId, annotation); } - an.setId(aa[i].annotationId); + an.setId(annotation.annotationId); - an.setVisible(aa[i].visible); + an.setVisible(annotation.visible); - an.setDescription(aa[i].description); + an.setDescription(annotation.description); - if (aa[i].sequenceRef != null) + if (annotation.sequenceRef != null) { - // TODO later annotation sequenceRef should be the XML ID of the - // sequence rather than its display name - an.setSequenceRef(aa[i].sequenceRef.getName()); + // 2.9 JAL-1781 xref on sequence id rather than name + an.setSequenceRef(seqsToIds.get(annotation.sequenceRef)); } - if (aa[i].groupRef != null) + if (annotation.groupRef != null) { - Object groupIdr = groupRefs.get(aa[i].groupRef); + String groupIdr = groupRefs.get(annotation.groupRef); if (groupIdr == null) { // make a locally unique String - groupRefs.put(aa[i].groupRef, + groupRefs.put( + annotation.groupRef, groupIdr = ("" + System.currentTimeMillis() - + aa[i].groupRef.getName() + groupRefs.size())); + + annotation.groupRef.getName() + groupRefs + .size())); } an.setGroupRef(groupIdr.toString()); } // store all visualization attributes for annotation - an.setGraphHeight(aa[i].graphHeight); - an.setCentreColLabels(aa[i].centreColLabels); - an.setScaleColLabels(aa[i].scaleColLabel); - an.setShowAllColLabels(aa[i].showAllColLabels); - an.setBelowAlignment(aa[i].belowAlignment); + an.setGraphHeight(annotation.graphHeight); + an.setCentreColLabels(annotation.centreColLabels); + an.setScaleColLabels(annotation.scaleColLabel); + an.setShowAllColLabels(annotation.showAllColLabels); + an.setBelowAlignment(annotation.belowAlignment); - if (aa[i].graph > 0) + if (annotation.graph > 0) { an.setGraph(true); - an.setGraphType(aa[i].graph); - an.setGraphGroup(aa[i].graphGroup); - if (aa[i].getThreshold() != null) + an.setGraphType(annotation.graph); + an.setGraphGroup(annotation.graphGroup); + if (annotation.getThreshold() != null) { ThresholdLine line = new ThresholdLine(); - line.setLabel(aa[i].getThreshold().label); - line.setValue(aa[i].getThreshold().value); - line.setColour(aa[i].getThreshold().colour.getRGB()); + line.setLabel(annotation.getThreshold().label); + line.setValue(annotation.getThreshold().value); + line.setColour(annotation.getThreshold().colour.getRGB()); an.setThresholdLine(line); } } @@ -1493,77 +1670,78 @@ public class Jalview2XML an.setGraph(false); } - an.setLabel(aa[i].label); + an.setLabel(annotation.label); - if (aa[i] == av.getAlignmentQualityAnnot() - || aa[i] == av.getAlignmentConservationAnnotation() - || aa[i] == av.getAlignmentConsensusAnnotation() - || aa[i].autoCalculated) + if (annotation == av.getAlignmentQualityAnnot() + || annotation == av.getAlignmentConservationAnnotation() + || annotation == av.getAlignmentConsensusAnnotation() + || annotation.autoCalculated) { // new way of indicating autocalculated annotation - - an.setAutoCalculated(aa[i].autoCalculated); + an.setAutoCalculated(annotation.autoCalculated); } - if (aa[i].hasScore()) + if (annotation.hasScore()) { - an.setScore(aa[i].getScore()); + an.setScore(annotation.getScore()); } - if (aa[i].getCalcId() != null) + if (annotation.getCalcId() != null) { - calcIdSet.add(aa[i].getCalcId()); - an.setCalcId(aa[i].getCalcId()); + calcIdSet.add(annotation.getCalcId()); + an.setCalcId(annotation.getCalcId()); } - if (aa[i].hasProperties()) + if (annotation.hasProperties()) { - for (String pr : aa[i].getProperties()) + for (String pr : annotation.getProperties()) { Property prop = new Property(); prop.setName(pr); - prop.setValue(aa[i].getProperty(pr)); + prop.setValue(annotation.getProperty(pr)); an.addProperty(prop); } } + AnnotationElement ae; - if (aa[i].annotations != null) + if (annotation.annotations != null) { an.setScoreOnly(false); - for (int a = 0; a < aa[i].annotations.length; a++) + for (int a = 0; a < annotation.annotations.length; a++) { - if ((aa[i] == null) || (aa[i].annotations[a] == null)) + if ((annotation == null) || (annotation.annotations[a] == null)) { continue; } ae = new AnnotationElement(); - if (aa[i].annotations[a].description != null) + if (annotation.annotations[a].description != null) { - ae.setDescription(aa[i].annotations[a].description); + ae.setDescription(annotation.annotations[a].description); } - if (aa[i].annotations[a].displayCharacter != null) + if (annotation.annotations[a].displayCharacter != null) { - ae.setDisplayCharacter(aa[i].annotations[a].displayCharacter); + ae.setDisplayCharacter(annotation.annotations[a].displayCharacter); } - if (!Float.isNaN(aa[i].annotations[a].value)) + if (!Float.isNaN(annotation.annotations[a].value)) { - ae.setValue(aa[i].annotations[a].value); + ae.setValue(annotation.annotations[a].value); } ae.setPosition(a); - if (aa[i].annotations[a].secondaryStructure > ' ') + if (annotation.annotations[a].secondaryStructure > ' ') { - ae.setSecondaryStructure(aa[i].annotations[a].secondaryStructure + ae.setSecondaryStructure(annotation.annotations[a].secondaryStructure + ""); } - if (aa[i].annotations[a].colour != null - && aa[i].annotations[a].colour != java.awt.Color.black) + if (annotation.annotations[a].colour != null + && annotation.annotations[a].colour != java.awt.Color.black) { - ae.setColour(aa[i].annotations[a].colour.getRGB()); + ae.setColour(annotation.annotations[a].colour.getRGB()); } an.addAnnotationElement(ae); - if (aa[i].autoCalculated) + if (annotation.autoCalculated) { // only write one non-null entry into the annotation row - // sufficient to get the visualization attributes necessary to @@ -1576,7 +1754,7 @@ public class Jalview2XML { an.setScoreOnly(true); } - if (!storeDS || (storeDS && !aa[i].autoCalculated)) + if (!storeDS || (storeDS && !annotation.autoCalculated)) { // skip autocalculated annotation - these are only provided for // alignments @@ -1675,7 +1853,9 @@ public class Jalview2XML return false; } } - throw new Error(MessageManager.formatMessage("error.unsupported_version_calcIdparam", new String[]{calcIdParam.toString()})); + throw new Error(MessageManager.formatMessage( + "error.unsupported_version_calcIdparam", + new Object[] { calcIdParam.toString() })); } /** @@ -1797,20 +1977,20 @@ public class Jalview2XML mp = new Mapping(); jalview.util.MapList mlst = jmp.getMap(); - int r[] = mlst.getFromRanges(); - for (int s = 0; s < r.length; s += 2) + List r = mlst.getFromRanges(); + for (int[] range : r) { MapListFrom mfrom = new MapListFrom(); - mfrom.setStart(r[s]); - mfrom.setEnd(r[s + 1]); + mfrom.setStart(range[0]); + mfrom.setEnd(range[1]); mp.addMapListFrom(mfrom); } r = mlst.getToRanges(); - for (int s = 0; s < r.length; s += 2) + for (int[] range : r) { MapListTo mto = new MapListTo(); - mto.setStart(r[s]); - mto.setEnd(r[s + 1]); + mto.setStart(range[0]); + mto.setEnd(range[1]); mp.addMapListTo(mto); } mp.setMapFromUnit(mlst.getFromRatio()); @@ -1994,7 +2174,7 @@ public class Jalview2XML }); } catch (Exception x) { - + System.err.println("Error loading alignment: " + x.getMessage()); } } return af; @@ -2007,7 +2187,7 @@ public class Jalview2XML errorMessage = null; uniqueSetSuffix = null; seqRefIds = null; - viewportsAdded = null; + viewportsAdded.clear(); frefedSequence = null; if (file.startsWith("http://")) @@ -2059,17 +2239,13 @@ public class Jalview2XML { seqRefIds = new HashMap(); } - if (viewportsAdded == null) - { - viewportsAdded = new Hashtable(); - } if (frefedSequence == null) { frefedSequence = new Vector(); } - jalview.gui.AlignFrame af = null, _af = null; - Hashtable gatherToThisFrame = new Hashtable(); + AlignFrame af = null, _af = null; + Map gatherToThisFrame = new HashMap(); final String file = jprovider.getFilename(); try { @@ -2087,7 +2263,7 @@ public class Jalview2XML if (jarentry != null && jarentry.getName().endsWith(".xml")) { - InputStreamReader in = new InputStreamReader(jin, "UTF-8"); + InputStreamReader in = new InputStreamReader(jin, UTF_8); JalviewModel object = new JalviewModel(); Unmarshaller unmar = new Unmarshaller(object); @@ -2099,7 +2275,7 @@ public class Jalview2XML if (object.getJalviewModelSequence().getViewportCount() > 0) { af = _af; - if (af.viewport.gatherViewsHere) + if (af.viewport.isGatherViewsHere()) { gatherToThisFrame.put(af.viewport.getSequenceSetId(), af); } @@ -2114,13 +2290,7 @@ public class Jalview2XML } } while (jarentry != null); resolveFrefedSequences(); - } catch (java.io.FileNotFoundException ex) - { - ex.printStackTrace(); - errorMessage = "Couldn't locate Jalview XML file : " + file; - System.err.println("Exception whilst loading jalview XML file : " - + ex + "\n"); - } catch (java.net.UnknownHostException ex) + } catch (IOException ex) { ex.printStackTrace(); errorMessage = "Couldn't locate Jalview XML file : " + file; @@ -2169,11 +2339,20 @@ public class Jalview2XML Desktop.instance.stopLoading(); } - Enumeration en = gatherToThisFrame.elements(); - while (en.hasMoreElements()) + /* + * Regather multiple views (with the same sequence set id) to the frame (if + * any) that is flagged as the one to gather to, i.e. convert them to tabbed + * views instead of separate frames. Note this doesn't restore a state where + * some expanded views in turn have tabbed views - the last "first tab" read + * in will play the role of gatherer for all. + */ + for (AlignFrame fr : gatherToThisFrame.values()) { - Desktop.instance.gatherViews((AlignFrame) en.nextElement()); + Desktop.instance.gatherViews(fr); } + + restoreSplitFrames(); + if (errorMessage != null) { reportErrors(); @@ -2182,6 +2361,110 @@ public class Jalview2XML } /** + * Try to reconstruct and display SplitFrame windows, where each contains + * complementary dna and protein alignments. Done by pairing up AlignFrame + * objects (created earlier) which have complementary viewport ids associated. + */ + protected void restoreSplitFrames() + { + List gatherTo = new ArrayList(); + List addedToSplitFrames = new ArrayList(); + Map dna = new HashMap(); + + /* + * Identify the DNA alignments + */ + for (Entry candidate : splitFrameCandidates + .entrySet()) + { + AlignFrame af = candidate.getValue(); + if (af.getViewport().getAlignment().isNucleotide()) + { + dna.put(candidate.getKey().getId(), af); + } + } + + /* + * Try to match up the protein complements + */ + for (Entry candidate : splitFrameCandidates + .entrySet()) + { + AlignFrame af = candidate.getValue(); + if (!af.getViewport().getAlignment().isNucleotide()) + { + String complementId = candidate.getKey().getComplementId(); + // only non-null complements should be in the Map + if (complementId != null && dna.containsKey(complementId)) + { + final AlignFrame dnaFrame = dna.get(complementId); + SplitFrame sf = createSplitFrame(dnaFrame, af); + addedToSplitFrames.add(dnaFrame); + addedToSplitFrames.add(af); + if (af.viewport.isGatherViewsHere()) + { + gatherTo.add(sf); + } + } + } + } + + /* + * Open any that we failed to pair up (which shouldn't happen!) as + * standalone AlignFrame's. + */ + for (Entry candidate : splitFrameCandidates + .entrySet()) + { + AlignFrame af = candidate.getValue(); + if (!addedToSplitFrames.contains(af)) + { + Viewport view = candidate.getKey(); + Desktop.addInternalFrame(af, view.getTitle(), view.getWidth(), + view.getHeight()); + System.err.println("Failed to restore view " + view.getTitle() + + " to split frame"); + } + } + + /* + * Gather back into tabbed views as flagged. + */ + for (SplitFrame sf : gatherTo) + { + Desktop.instance.gatherViews(sf); + } + + splitFrameCandidates.clear(); + } + + /** + * Construct and display one SplitFrame holding DNA and protein alignments. + * + * @param dnaFrame + * @param proteinFrame + * @return + */ + protected SplitFrame createSplitFrame(AlignFrame dnaFrame, + AlignFrame proteinFrame) + { + SplitFrame splitFrame = new SplitFrame(dnaFrame, proteinFrame); + String title = MessageManager.getString("label.linked_view_title"); + int width = (int) dnaFrame.getBounds().getWidth(); + int height = (int) (dnaFrame.getBounds().getHeight() + + proteinFrame.getBounds().getHeight() + 50); + Desktop.addInternalFrame(splitFrame, title, width, height); + + /* + * And compute cDNA consensus (couldn't do earlier with consensus as + * mappings were not yet present) + */ + proteinFrame.viewport.alignmentChanged(proteinFrame.alignPanel); + + return splitFrame; + } + + /** * check errorMessage for a valid error message and raise an error box in the * GUI or write the current errorMessage to stderr and then clear the error * state. @@ -2218,7 +2501,7 @@ public class Jalview2XML errorMessage = null; } - Hashtable alreadyLoadedPDB; + Map alreadyLoadedPDB = new HashMap(); /** * when set, local views will be updated from view stored in JalviewXML @@ -2227,22 +2510,52 @@ public class Jalview2XML */ 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) { - if (alreadyLoadedPDB == null) - { - alreadyLoadedPDB = new Hashtable(); - } - if (alreadyLoadedPDB.containsKey(pdbId)) { return alreadyLoadedPDB.get(pdbId).toString(); } - try + String tempFile = copyJarEntry(jprovider, pdbId, "jalview_pdb"); + if (tempFile != null) { - JarInputStream jin = jprovider.getJarInputStream(); - /* + 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 + * @return + */ + protected String copyJarEntry(jarInputStreamProvider jprovider, + String jarEntryName, String prefix) + { + BufferedReader in = null; + PrintWriter out = null; + + try + { + JarInputStream jin = jprovider.getJarInputStream(); + /* * if (jprovider.startsWith("http://")) { jin = new JarInputStream(new * URL(jprovider).openStream()); } else { jin = new JarInputStream(new * FileInputStream(jprovider)); } @@ -2252,38 +2565,46 @@ public class Jalview2XML do { entry = jin.getNextJarEntry(); - } while (entry != null && !entry.getName().equals(pdbId)); + } while (entry != null && !entry.getName().equals(jarEntryName)); if (entry != null) { - BufferedReader in = new BufferedReader(new InputStreamReader(jin)); - File outFile = File.createTempFile("jalview_pdb", ".txt"); + in = new BufferedReader(new InputStreamReader(jin, UTF_8)); + File outFile = File.createTempFile(prefix, ".tmp"); outFile.deleteOnExit(); - PrintWriter out = new PrintWriter(new FileOutputStream(outFile)); + out = new PrintWriter(new FileOutputStream(outFile)); String data; while ((data = in.readLine()) != null) { out.println(data); } - try - { - out.flush(); - } catch (Exception foo) - { - } - ; - out.close(); + out.flush(); String t = outFile.getAbsolutePath(); - alreadyLoadedPDB.put(pdbId, t); return t; } else { - warn("Couldn't find PDB file entry in Jalview Jar for " + pdbId); + 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; @@ -2335,10 +2656,10 @@ public class Jalview2XML // //////////////////////////////// // LOAD SEQUENCES - Vector hiddenSeqs = null; + List hiddenSeqs = null; jalview.datamodel.Sequence jseq; - ArrayList tmpseqs = new ArrayList(); + List tmpseqs = new ArrayList(); boolean multipleView = false; @@ -2370,10 +2691,10 @@ public class Jalview2XML { if (hiddenSeqs == null) { - hiddenSeqs = new Vector(); + hiddenSeqs = new ArrayList(); } - hiddenSeqs.addElement(seqRefIds.get(seqId)); + hiddenSeqs.add(seqRefIds.get(seqId)); } } @@ -2381,13 +2702,10 @@ public class Jalview2XML // / // Create the alignment object from the sequence set // /////////////////////////////// - jalview.datamodel.Sequence[] orderedSeqs = new jalview.datamodel.Sequence[tmpseqs - .size()]; - - tmpseqs.toArray(orderedSeqs); + SequenceI[] orderedSeqs = tmpseqs + .toArray(new SequenceI[tmpseqs.size()]); - jalview.datamodel.Alignment al = new jalview.datamodel.Alignment( - orderedSeqs); + Alignment al = new Alignment(orderedSeqs); // / Add the alignment properties for (int i = 0; i < vamsasSet.getSequenceSetPropertiesCount(); i++) @@ -2414,7 +2732,7 @@ public class Jalview2XML } // /////////////////////////////// - Hashtable pdbloaded = new Hashtable(); + Hashtable pdbloaded = new Hashtable(); // TODO nothing writes to this?? if (!multipleView) { // load sequence features, database references and any associated PDB @@ -2460,7 +2778,17 @@ public class Jalview2XML { jalview.datamodel.PDBEntry entry = new jalview.datamodel.PDBEntry(); entry.setId(ids[p].getId()); - entry.setType(ids[p].getType()); + if (ids[p].getType() != null) + { + if (ids[p].getType().equalsIgnoreCase("PDB")) + { + entry.setType(PDBEntry.Type.PDB); + } + else + { + entry.setType(PDBEntry.Type.FILE); + } + } if (ids[p].getFile() != null) { if (!pdbloaded.containsKey(ids[p].getFile())) @@ -2473,8 +2801,7 @@ public class Jalview2XML } } StructureSelectionManager.getStructureSelectionManager( - Desktop.instance) - .registerPDBEntry(entry); + Desktop.instance).registerPDBEntry(entry); al.getSequenceAt(i).getDatasetSequence().addPDBId(entry); } } @@ -2491,35 +2818,13 @@ public class Jalview2XML AlcodonFrame[] alc = vamsasSet.getAlcodonFrame(); for (int i = 0; i < alc.length; i++) { - jalview.datamodel.AlignedCodonFrame cf = new jalview.datamodel.AlignedCodonFrame( - alc[i].getAlcodonCount()); - if (alc[i].getAlcodonCount() > 0) - { - Alcodon[] alcods = alc[i].getAlcodon(); - for (int p = 0; p < cf.codons.length; p++) - { - if (alcods[p].hasPos1() && alcods[p].hasPos2() - && alcods[p].hasPos3()) - { - // translated codons require three valid positions - cf.codons[p] = new int[3]; - cf.codons[p][0] = (int) alcods[p].getPos1(); - cf.codons[p][1] = (int) alcods[p].getPos2(); - cf.codons[p][2] = (int) alcods[p].getPos3(); - } - else - { - cf.codons[p] = null; - } - } - } + 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()); + SequenceI dnaseq = seqRefIds.get(maps[m].getDnasq()); // Load Mapping jalview.datamodel.Mapping mapping = null; // attach to dna sequence reference. @@ -2534,23 +2839,23 @@ public class Jalview2XML else { // defer to later - frefedSequence.add(new Object[] - { maps[m].getDnasq(), cf, mapping }); + frefedSequence.add(new Object[] { maps[m].getDnasq(), cf, + mapping }); } } } al.addCodonFrame(cf); } - } // //////////////////////////////// // LOAD ANNOTATIONS - ArrayList autoAlan = new ArrayList(); - /** + List autoAlan = new ArrayList(); + + /* * store any annotations which forward reference a group's ID */ - Hashtable> groupAnnotRefs = new Hashtable>(); + Map> groupAnnotRefs = new Hashtable>(); if (vamsasSet.getAnnotationCount() > 0) { @@ -2558,40 +2863,42 @@ public class Jalview2XML 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 (an[i].getLabel().equals("Quality") - || an[i].getLabel().equals("Conservation") - || an[i].getLabel().equals("Consensus")) + 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 (!an[i].hasAutoCalculated()) + if (!annotation.hasAutoCalculated()) { - an[i].setAutoCalculated(true); + annotation.setAutoCalculated(true); } } if (autoForView - || (an[i].hasAutoCalculated() && an[i].isAutoCalculated())) + || (annotation.hasAutoCalculated() && annotation + .isAutoCalculated())) { // remove ID - we don't recover annotation from other views for // view-specific annotation - an[i].setId(null); + annotation.setId(null); } // set visiblity for other annotation in this view - if (an[i].getId() != null - && annotationIds.containsKey(an[i].getId())) + String annotationId = annotation.getId(); + if (annotationId != null && annotationIds.containsKey(annotationId)) { - jalview.datamodel.AlignmentAnnotation jda = (jalview.datamodel.AlignmentAnnotation) annotationIds - .get(an[i].getId()); + AlignmentAnnotation jda = annotationIds.get(annotationId); // in principle Visible should always be true for annotation displayed // in multiple views - if (an[i].hasVisible()) + if (annotation.hasVisible()) { - jda.visible = an[i].getVisible(); + jda.visible = annotation.getVisible(); } al.addAnnotation(jda); @@ -2599,11 +2906,11 @@ public class Jalview2XML continue; } // Construct new annotation from model. - AnnotationElement[] ae = an[i].getAnnotationElement(); + AnnotationElement[] ae = annotation.getAnnotationElement(); jalview.datamodel.Annotation[] anot = null; java.awt.Color firstColour = null; int anpos; - if (!an[i].getScoreOnly()) + if (!annotation.getScoreOnly()) { anot = new jalview.datamodel.Annotation[al.getWidth()]; for (int aa = 0; aa < ae.length && aa < anot.length; aa++) @@ -2640,27 +2947,27 @@ public class Jalview2XML } jalview.datamodel.AlignmentAnnotation jaa = null; - if (an[i].getGraph()) + if (annotation.getGraph()) { float llim = 0, hlim = 0; // if (autoForView || an[i].isAutoCalculated()) { // hlim=11f; // } - jaa = new jalview.datamodel.AlignmentAnnotation(an[i].getLabel(), - an[i].getDescription(), anot, llim, hlim, - an[i].getGraphType()); + jaa = new jalview.datamodel.AlignmentAnnotation( + annotation.getLabel(), annotation.getDescription(), anot, + llim, hlim, annotation.getGraphType()); - jaa.graphGroup = an[i].getGraphGroup(); + jaa.graphGroup = annotation.getGraphGroup(); jaa._linecolour = firstColour; - if (an[i].getThresholdLine() != null) + if (annotation.getThresholdLine() != null) { - jaa.setThreshold(new jalview.datamodel.GraphLine(an[i] - .getThresholdLine().getValue(), an[i] + jaa.setThreshold(new jalview.datamodel.GraphLine(annotation + .getThresholdLine().getValue(), annotation .getThresholdLine().getLabel(), new java.awt.Color( - an[i].getThresholdLine().getColour()))); + annotation.getThresholdLine().getColour()))); } - if (autoForView || an[i].isAutoCalculated()) + if (autoForView || annotation.isAutoCalculated()) { // Hardwire the symbol display line to ensure that labels for // histograms are displayed @@ -2680,19 +2987,26 @@ public class Jalview2XML jaa.annotationId = an[i].getId(); } // recover sequence association - if (an[i].getSequenceRef() != null) + String sequenceRef = an[i].getSequenceRef(); + if (sequenceRef != null) { - if (al.findName(an[i].getSequenceRef()) != 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(al.findName(an[i].getSequenceRef()), - 1, true); - al.findName(an[i].getSequenceRef()).addAlignmentAnnotation(jaa); + 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) { - ArrayList aal = groupAnnotRefs + List aal = groupAnnotRefs .get(an[i].getGroupRef()); if (aal == null) { @@ -2766,38 +3080,37 @@ public class Jalview2XML boolean addAnnotSchemeGroup = false; for (int i = 0; i < groups.length; i++) { + JGroup jGroup = groups[i]; ColourSchemeI cs = null; - - if (groups[i].getColour() != null) + if (jGroup.getColour() != null) { - if (groups[i].getColour().startsWith("ucs")) + if (jGroup.getColour().startsWith("ucs")) { - cs = getUserColourScheme(jms, groups[i].getColour()); + cs = getUserColourScheme(jms, jGroup.getColour()); } - else if (groups[i].getColour().equals("AnnotationColourGradient") - && groups[i].getAnnotationColours() != null) + else if (jGroup.getColour().equals("AnnotationColourGradient") + && jGroup.getAnnotationColours() != null) { addAnnotSchemeGroup = true; cs = null; } else { - cs = ColourSchemeProperty.getColour(al, groups[i].getColour()); + cs = ColourSchemeProperty.getColour(al, jGroup.getColour()); } if (cs != null) { - cs.setThreshold(groups[i].getPidThreshold(), true); + cs.setThreshold(jGroup.getPidThreshold(), true); } } - Vector seqs = new Vector(); + Vector seqs = new Vector(); - for (int s = 0; s < groups[i].getSeqCount(); s++) + for (int s = 0; s < jGroup.getSeqCount(); s++) { - String seqId = groups[i].getSeq(s) + ""; - jalview.datamodel.SequenceI ts = seqRefIds - .get(seqId); + String seqId = jGroup.getSeq(s) + ""; + SequenceI ts = seqRefIds.get(seqId); if (ts != null) { @@ -2810,36 +3123,35 @@ public class Jalview2XML continue; } - jalview.datamodel.SequenceGroup sg = new jalview.datamodel.SequenceGroup( - seqs, groups[i].getName(), cs, groups[i].getDisplayBoxes(), - groups[i].getDisplayText(), groups[i].getColourText(), - groups[i].getStart(), groups[i].getEnd()); + SequenceGroup sg = new SequenceGroup(seqs, jGroup.getName(), cs, + jGroup.getDisplayBoxes(), jGroup.getDisplayText(), + jGroup.getColourText(), jGroup.getStart(), jGroup.getEnd()); - sg.setOutlineColour(new java.awt.Color(groups[i].getOutlineColour())); + sg.setOutlineColour(new java.awt.Color(jGroup.getOutlineColour())); - sg.textColour = new java.awt.Color(groups[i].getTextCol1()); - sg.textColour2 = new java.awt.Color(groups[i].getTextCol2()); - sg.setShowNonconserved(groups[i].hasShowUnconserved() ? groups[i] + 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 = groups[i].getTextColThreshold(); - if (groups[i].hasShowConsensusHistogram()) + sg.thresholdTextColour = jGroup.getTextColThreshold(); + if (jGroup.hasShowConsensusHistogram()) { - sg.setShowConsensusHistogram(groups[i].isShowConsensusHistogram()); + sg.setShowConsensusHistogram(jGroup.isShowConsensusHistogram()); } ; - if (groups[i].hasShowSequenceLogo()) + if (jGroup.hasShowSequenceLogo()) { - sg.setshowSequenceLogo(groups[i].isShowSequenceLogo()); + sg.setshowSequenceLogo(jGroup.isShowSequenceLogo()); } - if (groups[i].hasNormaliseSequenceLogo()) + if (jGroup.hasNormaliseSequenceLogo()) { - sg.setNormaliseSequenceLogo(groups[i].isNormaliseSequenceLogo()); + sg.setNormaliseSequenceLogo(jGroup.isNormaliseSequenceLogo()); } - if (groups[i].hasIgnoreGapsinConsensus()) + if (jGroup.hasIgnoreGapsinConsensus()) { - sg.setIgnoreGapsConsensus(groups[i].getIgnoreGapsinConsensus()); + sg.setIgnoreGapsConsensus(jGroup.getIgnoreGapsinConsensus()); } - if (groups[i].getConsThreshold() != 0) + if (jGroup.getConsThreshold() != 0) { jalview.analysis.Conservation c = new jalview.analysis.Conservation( "All", ResidueProperties.propHash, 3, @@ -2849,14 +3161,14 @@ public class Jalview2XML sg.cs.setConservation(c); } - if (groups[i].getId() != null && groupAnnotRefs.size() > 0) + if (jGroup.getId() != null && groupAnnotRefs.size() > 0) { // re-instate unique group/annotation row reference - ArrayList jaal = groupAnnotRefs - .get(groups[i].getId()); + List jaal = groupAnnotRefs.get(jGroup + .getId()); if (jaal != null) { - for (jalview.datamodel.AlignmentAnnotation jaa : jaal) + for (AlignmentAnnotation jaa : jaal) { jaa.groupRef = sg; if (jaa.autoCalculated) @@ -2881,8 +3193,8 @@ public class Jalview2XML if (addAnnotSchemeGroup) { // reconstruct the annotation colourscheme - sg.cs = constructAnnotationColour( - groups[i].getAnnotationColours(), null, al, jms, false); + sg.cs = constructAnnotationColour(jGroup.getAnnotationColours(), + null, al, jms, false); } } } @@ -2973,90 +3285,202 @@ public class Jalview2XML av = af.viewport; ap = af.alignPanel; } - // LOAD TREES - // ///////////////////////////////////// - if (loadTreesAndStructures && jms.getTreeCount() > 0) + + /* + * Load any trees, PDB structures and viewers + * + * Not done if flag is false (when this method is used for New View) + */ + if (loadTreesAndStructures) { - try + 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++) { - for (int t = 0; t < jms.getTreeCount(); t++) + 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()); - Tree tree = jms.getTree(t); + /* + * 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"); + RnaModel rna = new RnaModel(rnaTitle, ann, seq, null, gapped); + appVarna.addModelSession(rna, rnaTitle, tempStateFile); + } + appVarna.setInitialSelection(viewer.getSelectedRna()); + } + } + } - 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; + /** + * 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; + } + } + } - } - if (tp == null) - { - warn("There was a problem recovering stored Newick tree: \n" - + tree.getNewick()); - continue; - } + /* + * 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); - tp.fitToWindow.setState(tree.getFitToWindow()); - tp.fitToWindow_actionPerformed(null); + return varna; + } - if (tree.getFontName() != null) - { - tp.setTreeFont(new java.awt.Font(tree.getFontName(), tree - .getFontStyle(), tree.getFontSize())); - } - else + /** + * 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) { - tp.setTreeFont(new java.awt.Font(view.getFontName(), view - .getFontStyle(), tree.getFontSize())); + // 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; - tp.showPlaceholders(tree.getMarkUnlinked()); - tp.showBootstrap(tree.getShowBootstrap()); - tp.showDistances(tree.getShowDistances()); + } + if (tp == null) + { + warn("There was a problem recovering stored Newick tree: \n" + + tree.getNewick()); + continue; + } - tp.treeCanvas.threshold = tree.getThreshold(); + tp.fitToWindow.setState(tree.getFitToWindow()); + tp.fitToWindow_actionPerformed(null); - if (tree.getCurrentTree()) - { - af.viewport.setCurrentTree(tp.getTree()); - } + 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())); } - } catch (Exception ex) - { - ex.printStackTrace(); + 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()); + } } - } - // //LOAD STRUCTURES - if (loadTreesAndStructures) + } catch (Exception ex) { - loadStructures(jprovider, jseqs, af, ap); + ex.printStackTrace(); } - // and finally return. - return af; } /** @@ -3067,12 +3491,14 @@ public class Jalview2XML * @param af * @param ap */ - protected void loadStructures(jarInputStreamProvider jprovider, + protected void loadPDBStructures(jarInputStreamProvider jprovider, JSeq[] jseqs, AlignFrame af, AlignmentPanel ap) { - // run through all PDB ids on the alignment, and collect mappings between - // jmol view ids and all sequences referring to it - Map jmolViewIds = new HashMap(); + /* + * Run through all PDB ids on the alignment, and collect mappings between + * distinct view ids and all sequences referring to that view. + */ + Map structureViewers = new LinkedHashMap(); for (int i = 0; i < jseqs.length; i++) { @@ -3085,10 +3511,10 @@ public class Jalview2XML for (int s = 0; s < structureStateCount; s++) { // check to see if we haven't already created this structure view - final StructureState structureState = ids[p].getStructureState(s); + final StructureState structureState = ids[p] + .getStructureState(s); String sviewid = (structureState.getViewId() == null) ? null - : structureState.getViewId() - + uniqueSetSuffix; + : 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 @@ -3105,17 +3531,19 @@ public class Jalview2XML // Desktop.desktop.getComponentAt(x, y); // TODO: NOW: check that this recovers the PDB file correctly. String pdbFile = loadPDBFile(jprovider, ids[p].getId()); - jalview.datamodel.SequenceI seq = seqRefIds - .get(jseqs[i].getId() + ""); + jalview.datamodel.SequenceI seq = seqRefIds.get(jseqs[i] + .getId() + ""); if (sviewid == null) { sviewid = "_jalview_pre2_4_" + x + "," + y + "," + width + "," + height; } - if (!jmolViewIds.containsKey(sviewid)) + if (!structureViewers.containsKey(sviewid)) { - jmolViewIds.put(sviewid, new ViewerData(x, y, width, height, - false, false, true)); + 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 @@ -3125,44 +3553,52 @@ public class Jalview2XML // file }, orig_fileloc, SequenceI[][] {{ seqs_file 1 }, { // seqs_file 2}, boolean[] { // linkAlignPanel,superposeWithAlignpanel}} from hash - ViewerData jmoldat = jmolViewIds.get(sviewid); - jmoldat.alignWithPanel |= structureState - .hasAlignwithAlignPanel() ? structureState.getAlignwithAlignPanel() : false; - // never colour by linked panel if not specified - jmoldat.colourWithAlignPanel |= structureState - .hasColourwithAlignPanel() ? structureState.getColourwithAlignPanel() - : false; - // default for pre-2.7 projects is that Jmol colouring is enabled - jmoldat.colourByViewer &= structureState - .hasColourByJmol() ? structureState + 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.stateData.length() < structureState.getContent() - .length()) + if (jmoldat.getStateData().length() < structureState + .getContent().length()) { { - jmoldat.stateData = structureState.getContent(); + jmoldat.setStateData(structureState.getContent()); } } if (ids[p].getFile() != null) { File mapkey = new File(ids[p].getFile()); - Object[] seqstrmaps = jmoldat.fileData.get(mapkey); + StructureData seqstrmaps = jmoldat.getFileData().get(mapkey); if (seqstrmaps == null) { - jmoldat.fileData.put(mapkey, - seqstrmaps = new Object[] - { pdbFile, ids[p].getId(), new Vector(), - new Vector() }); + jmoldat.getFileData().put( + mapkey, + seqstrmaps = jmoldat.new StructureData(pdbFile, + ids[p].getId())); } - if (!((Vector) seqstrmaps[2]).contains(seq)) + if (!seqstrmaps.getSeqList().contains(seq)) { - ((Vector) seqstrmaps[2]).addElement(seq); - // ((Vector)seqstrmaps[3]).addElement(n) : - // in principle, chains - // should be stored here : do we need to - // TODO: store and recover seq/pdb_id : - // chain mappings + seqstrmaps.getSeqList().add(seq); + // TODO and chains? } } else @@ -3174,249 +3610,379 @@ public class Jalview2XML } } } + // Instantiate the associated structure views + for (Entry 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 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 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"); + + Set> fileData = data.getFileData() + .entrySet(); + List pdbs = new ArrayList(); + List allseqs = new ArrayList(); + for (Entry 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 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 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())); + } - // Instantiate the associated Jmol views - for (Entry entry : jmolViewIds.entrySet()) + List pdbfilenames = new ArrayList(); + List seqmaps = new ArrayList(); + List pdbids = new ArrayList(); + StringBuilder newFileLoc = new StringBuilder(64); + int cp = 0, ncp, ecp; + Map 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)); + 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()) { - String sviewid = entry.getKey(); - ViewerData svattrib = entry.getValue(); - String state = svattrib.stateData; - Map oldFiles = svattrib.fileData; - final boolean useinJmolsuperpos = svattrib.alignWithPanel; - final boolean usetoColourbyseq = svattrib.colourWithAlignPanel; - final boolean jmolColouring = svattrib.colourByViewer; - int x = svattrib.x; - int y = svattrib.y; - int width = svattrib.width; - int height = svattrib.height; - // collate the pdbfile -> sequence mappings from this view - Vector pdbfilenames = new Vector(); - Vector seqmaps = new Vector(); - Vector pdbids = new Vector(); + // 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("\""); - /* - * Search for any Jmol windows already open from other alignment views - * that exactly match the stored structure state - */ - AppJmol comp = null; - JInternalFrame[] frames = getAllFrames(); - for (JInternalFrame frame : frames) + } + 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 (frame instanceof AppJmol) + if (val.trim().equals("true")) { - /* - * Post jalview 2.4 schema includes structure view id - */ - if (sviewid != null - && ((StructureViewerBase) frame).getViewId().equals( - sviewid)) - { - comp = (AppJmol) frame; - } - /* - * Otherwise test for matching position and size of viewer frame - */ - else if (frame.getX() == x && frame.getY() == y - && frame.getHeight() == height - && frame.getWidth() == width) - { - comp = (AppJmol) frame; - } + val = "1"; + } + else + { + val = "0"; } + newFileLoc.replace(histbug, diff, val); } + } + } - if (comp == null) + 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() { - /* - * 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. - */ - StringBuffer newFileLoc = null; - int cp = 0, ncp, ecp; - while ((ncp = state.indexOf("load ", cp)) > -1) - { - if (newFileLoc == null) - { - newFileLoc = new StringBuffer(); - } - 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. - Object[] filedat = oldFiles.get(new File(oldfilenam)); - newFileLoc.append(Platform - .escapeString((String) filedat[0])); - pdbfilenames.addElement((String) filedat[0]); - pdbids.addElement((String) filedat[1]); - seqmaps.addElement(((Vector) filedat[2]) - .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) + JalviewStructureDisplayI sview = null; + try { - // just append rest of state - newFileLoc.append(state.substring(cp)); - } - else + sview = new StructureViewer(alf.alignPanel + .getStructureSelectionManager()).createView( + StructureViewer.ViewerType.JMOL, pdbf, id, sq, + alf.alignPanel, svattrib, fileloc, rect, sviewid); + addNewStructureViewer(sview); + } catch (OutOfMemoryError ex) { - System.err - .print("Ignoring incomplete Jmol state for PDB ids: "); - newFileLoc = new StringBuffer(state); - newFileLoc.append("; load append "); - for (File id : oldFiles.keySet()) + new OOMWarning("restoring structure view for PDB id " + id, + (OutOfMemoryError) ex.getCause()); + if (sview != null && sview.isVisible()) { - // add this and any other pdb files that should be present in - // the viewer - Object[] filedat = oldFiles.get(id); - String nfilename; - newFileLoc.append(((String) filedat[0])); - pdbfilenames.addElement((String) filedat[0]); - pdbids.addElement((String) filedat[1]); - seqmaps.addElement(((Vector) filedat[2]) - .toArray(new SequenceI[0])); - newFileLoc.append(" \""); - newFileLoc.append((String) filedat[0]); - newFileLoc.append("\""); - + sview.closeViewer(false); + sview.setVisible(false); + sview.dispose(); } - newFileLoc.append(";"); } + } + }); + } catch (InvocationTargetException ex) + { + warn("Unexpected error when opening Jmol view.", ex); - if (newFileLoc != null) - { - int histbug = newFileLoc.indexOf("history = "); - 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")) - { - if (val.trim().equals("true")) - { - val = "1"; - } - else - { - val = "0"; - } - newFileLoc.replace(histbug, diff, val); - } - } - // TODO: assemble String[] { pdb files }, String[] { id for each - // file }, orig_fileloc, SequenceI[][] {{ seqs_file 1 }, { - // seqs_file 2}} from hash - final String[] pdbf = pdbfilenames - .toArray(new String[pdbfilenames.size()]), id = pdbids - .toArray(new String[pdbids.size()]); - final SequenceI[][] sq = seqmaps - .toArray(new SequenceI[seqmaps.size()][]); - final String fileloc = newFileLoc.toString(), vid = sviewid; - final AlignFrame alf = af; - final java.awt.Rectangle rect = new java.awt.Rectangle(x, y, - width, height); - try - { - javax.swing.SwingUtilities.invokeAndWait(new Runnable() - { - @Override - public void run() - { - JalviewStructureDisplayI sview = null; - try - { - // JAL-1333 note - we probably can't migrate Jmol views to UCSF Chimera! - sview = new StructureViewer(alf.alignPanel - .getStructureSelectionManager()).createView( - StructureViewer.ViewerType.JMOL, pdbf, id, sq, - alf.alignPanel, - useinJmolsuperpos, usetoColourbyseq, - jmolColouring, fileloc, rect, vid); - addNewStructureViewer(sview); - } catch (OutOfMemoryError ex) - { - new OOMWarning("restoring structure view for PDB id " - + id, (OutOfMemoryError) ex.getCause()); - if (sview != null && sview.isVisible()) - { - sview.closeViewer(); - sview.setVisible(false); - sview.dispose(); - } - } - } - }); - } catch (InvocationTargetException ex) - { - warn("Unexpected error when opening Jmol view.", ex); + } catch (InterruptedException e) + { + // e.printStackTrace(); + } - } 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 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 } - else - // if (comp != null) + /* + * 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()) { - linkStructureViewer(ap, comp, oldFiles, useinJmolsuperpos, - usetoColourbyseq, jmolColouring); + comp = (StructureViewerBase) frame; + // no break in faint hope of an exact match on viewId } } } + return comp; } /** - * Link an AlignmentPanel to an existing JMol viewer. + * Link an AlignmentPanel to an existing structure viewer. * * @param ap * @param viewer * @param oldFiles - * @param useinJmolsuperpos + * @param useinViewerSuperpos * @param usetoColourbyseq - * @param jmolColouring + * @param viewerColouring */ - protected void linkStructureViewer(AlignmentPanel ap, AppJmol viewer, - Map oldFiles, - final boolean useinJmolsuperpos, final boolean usetoColourbyseq, - final boolean jmolColouring) + 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. - // add mapping for sequences in this view to an already open Jmol - // instance + final boolean useinViewerSuperpos = stateData.isAlignWithPanel(); + final boolean usetoColourbyseq = stateData.isColourWithAlignPanel(); + final boolean viewerColouring = stateData.isColourByViewer(); + Map 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 - Object[] filedat = oldFiles.get(id); - String pdbFile = (String) filedat[0]; - SequenceI[] seq = ((Vector) filedat[2]) - .toArray(new SequenceI[0]); - viewer.jmb.getSsm().setMapping(seq, null, pdbFile, + StructureData filedat = oldFiles.get(id); + String pdbFile = filedat.getFilePath(); + SequenceI[] seq = filedat.getSeqList().toArray(new SequenceI[0]); + binding.getSsm().setMapping(seq, null, pdbFile, jalview.io.AppletFormatAdapter.FILE); - viewer.jmb.addSequenceForStructFile(pdbFile, seq); + binding.addSequenceForStructFile(pdbFile, seq); } - // and add the AlignmentPanel's reference to the Jmol view + // and add the AlignmentPanel's reference to the view panel viewer.addAlignmentPanel(ap); - if (useinJmolsuperpos) + if (useinViewerSuperpos) { viewer.useAlignmentPanelForSuperposition(ap); } @@ -3426,7 +3992,7 @@ public class Jalview2XML } if (usetoColourbyseq) { - viewer.useAlignmentPanelForColourbyseq(ap, !jmolColouring); + viewer.useAlignmentPanelForColourbyseq(ap, !viewerColouring); } else { @@ -3471,7 +4037,8 @@ public class Jalview2XML * @return true if version is development/null or evaluates to the same or * later X.Y.Z (where X,Y,Z are like [0-9]+b?[0-9]*) */ - private boolean isVersionStringLaterThan(String supported, String version) + protected boolean isVersionStringLaterThan(String supported, + String version) { if (version == null || version.equalsIgnoreCase("DEVELOPMENT BUILD") || version.equalsIgnoreCase("Test") @@ -3542,10 +4109,10 @@ public class Jalview2XML } } - AlignFrame loadViewport(String file, JSeq[] JSEQ, Vector hiddenSeqs, - Alignment al, JalviewModelSequence jms, Viewport view, - String uniqueSeqSetId, String viewId, - ArrayList autoAlan) + AlignFrame loadViewport(String file, JSeq[] JSEQ, + List hiddenSeqs, Alignment al, + JalviewModelSequence jms, Viewport view, String uniqueSeqSetId, + String viewId, List autoAlan) { AlignFrame af = null; af = new AlignFrame(al, view.getWidth(), view.getHeight(), @@ -3559,19 +4126,18 @@ public class Jalview2XML .getSequenceAt(i), new java.awt.Color(JSEQ[i].getColour())); } - af.viewport.gatherViewsHere = view.getGatheredViews(); + af.viewport.setGatherViewsHere(view.getGatheredViews()); if (view.getSequenceSetId() != null) { - jalview.gui.AlignViewport av = (jalview.gui.AlignViewport) viewportsAdded - .get(uniqueSeqSetId); + AlignmentViewport av = viewportsAdded.get(uniqueSeqSetId); af.viewport.setSequenceSetId(uniqueSeqSetId); if (av != null) { // propagate shared settings to this new view - af.viewport.historyList = av.historyList; - af.viewport.redoList = av.redoList; + af.viewport.setHistoryList(av.getHistoryList()); + af.viewport.setRedoList(av.getRedoList()); } else { @@ -3596,14 +4162,17 @@ public class Jalview2XML af.viewport.hideRepSequences(al.getSequenceAt(s), hidden); } - jalview.datamodel.SequenceI[] hseqs = new jalview.datamodel.SequenceI[hiddenSeqs - .size()]; - - for (int s = 0; s < hiddenSeqs.size(); s++) - { - hseqs[s] = (jalview.datamodel.SequenceI) hiddenSeqs.elementAt(s); - } + // jalview.datamodel.SequenceI[] hseqs = new + // jalview.datamodel.SequenceI[hiddenSeqs + // .size()]; + // + // for (int s = 0; s < hiddenSeqs.size(); s++) + // { + // hseqs[s] = (jalview.datamodel.SequenceI) hiddenSeqs.elementAt(s); + // } + SequenceI[] hseqs = hiddenSeqs.toArray(new SequenceI[hiddenSeqs + .size()]); af.viewport.hideSequence(hseqs); } @@ -3624,27 +4193,30 @@ public class Jalview2XML af.viewport.setConservationSelected(view.getConservationSelected()); af.viewport.setShowJVSuffix(view.getShowFullId()); af.viewport.setRightAlignIds(view.getRightAlignIds()); - af.viewport.setFont(new java.awt.Font(view.getFontName(), view - .getFontStyle(), view.getFontSize())); - af.alignPanel.fontChanged(); + 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.alignPanel.setWrapAlignment(view.getWrapAlignment()); af.viewport.setShowAnnotation(view.getShowAnnotation()); - af.alignPanel.setAnnotationVisible(view.getShowAnnotation()); af.viewport.setShowBoxes(view.getShowBoxes()); af.viewport.setShowText(view.getShowText()); - af.viewport.textColour = new java.awt.Color(view.getTextCol1()); - af.viewport.textColour2 = new java.awt.Color(view.getTextCol2()); - af.viewport.thresholdTextColour = view.getTextColThreshold(); + 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.setStartRes(view.getStartRes()); af.viewport.setStartSeq(view.getStartSeq()); - + af.alignPanel.updateLayout(); ColourSchemeI cs = null; // apply colourschemes if (view.getBgColour() != null) @@ -3685,10 +4257,8 @@ public class Jalview2XML af.viewport.setColourAppliesToAllGroups(true); - if (view.getShowSequenceFeatures()) - { - af.viewport.showSequenceFeatures = true; - } + af.viewport.setShowSequenceFeatures(view.getShowSequenceFeatures()); + if (view.hasCentreColumnLabels()) { af.viewport.setCentreColumnLabels(view.getCentreColumnLabels()); @@ -3700,7 +4270,7 @@ public class Jalview2XML } if (view.hasFollowHighlight()) { - af.viewport.followHighlight = view.getFollowHighlight(); + af.viewport.setFollowHighlight(view.getFollowHighlight()); } if (view.hasFollowSelection()) { @@ -3729,11 +4299,11 @@ public class Jalview2XML } if (view.hasShowDbRefTooltip()) { - af.viewport.setShowDbRefs(view.getShowDbRefTooltip()); + af.viewport.setShowDBRefs(view.getShowDbRefTooltip()); } if (view.hasShowNPfeatureTooltip()) { - af.viewport.setShowNpFeats(view.hasShowNPfeatureTooltip()); + af.viewport.setShowNPFeats(view.hasShowNPfeatureTooltip()); } if (view.hasShowGroupConsensus()) { @@ -3755,9 +4325,14 @@ public class Jalview2XML // recover featre settings if (jms.getFeatureSettings() != null) { - af.viewport.setFeaturesDisplayed(new Hashtable()); + FeaturesDisplayed fdi; + af.viewport.setFeaturesDisplayed(fdi = new FeaturesDisplayed()); String[] renderOrder = new String[jms.getFeatureSettings() .getSettingCount()]; + Hashtable featureGroups = new Hashtable(); + Hashtable featureColours = new Hashtable(); + Hashtable featureOrder = new Hashtable(); + for (int fs = 0; fs < jms.getFeatureSettings().getSettingCount(); fs++) { Setting setting = jms.getFeatureSettings().getSetting(fs); @@ -3784,41 +4359,42 @@ public class Jalview2XML gc.setColourByLabel(setting.getColourByLabel()); } // and put in the feature colour table. - af.alignPanel.getSeqPanel().seqCanvas.getFeatureRenderer().setColour( - setting.getType(), gc); + featureColours.put(setting.getType(), gc); } else { - af.alignPanel.getSeqPanel().seqCanvas.getFeatureRenderer().setColour( - setting.getType(), + featureColours.put(setting.getType(), new java.awt.Color(setting.getColour())); } renderOrder[fs] = setting.getType(); if (setting.hasOrder()) { - af.alignPanel.getSeqPanel().seqCanvas.getFeatureRenderer().setOrder( - setting.getType(), setting.getOrder()); + featureOrder.put(setting.getType(), setting.getOrder()); } else { - af.alignPanel.getSeqPanel().seqCanvas.getFeatureRenderer().setOrder( - setting.getType(), - fs / jms.getFeatureSettings().getSettingCount()); + featureOrder.put(setting.getType(), new Float(fs + / jms.getFeatureSettings().getSettingCount())); } if (setting.getDisplay()) { - af.viewport.getFeaturesDisplayed().put(setting.getType(), new Integer( - setting.getColour())); + fdi.setVisible(setting.getType()); } } - af.alignPanel.getSeqPanel().seqCanvas.getFeatureRenderer().renderOrder = renderOrder; - Hashtable fgtable; - af.alignPanel.getSeqPanel().seqCanvas.getFeatureRenderer().featureGroups = fgtable = new Hashtable(); + Hashtable fgtable = new Hashtable(); for (int gs = 0; gs < jms.getFeatureSettings().getGroupCount(); gs++) { Group grp = jms.getFeatureSettings().getGroup(gs); fgtable.put(grp.getName(), new Boolean(grp.getDisplay())); } + // FeatureRendererSettings frs = new FeatureRendererSettings(renderOrder, + // fgtable, featureColours, jms.getFeatureSettings().hasTransparency() ? + // jms.getFeatureSettings().getTransparency() : 0.0, featureOrder); + FeatureRendererSettings frs = new FeatureRendererSettings( + renderOrder, fgtable, featureColours, 1.0f, featureOrder); + af.alignPanel.getSeqPanel().seqCanvas.getFeatureRenderer() + .transferSettings(frs); + } if (view.getHiddenColumnsCount() > 0) @@ -3848,12 +4424,27 @@ public class Jalview2XML } } af.setMenusFromViewport(af.viewport); + // TODO: we don't need to do this if the viewport is aready visible. - Desktop.addInternalFrame(af, view.getTitle(), view.getWidth(), - view.getHeight()); - af.alignPanel.updateAnnotation(false, true); // recompute any autoannotation - reorderAutoannotation(af, al, autoAlan); - af.alignPanel.alignmentChanged(); + /* + * Add the AlignFrame to the desktop (it may be 'gathered' later), unless it + * has a 'cdna/protein complement' view, in which case save it in order to + * populate a SplitFrame once all views have been read in. + */ + String complementaryViewId = view.getComplementId(); + if (complementaryViewId == null) + { + Desktop.addInternalFrame(af, view.getTitle(), view.getWidth(), + view.getHeight()); + // recompute any autoannotation + af.alignPanel.updateAnnotation(false, true); + reorderAutoannotation(af, al, autoAlan); + af.alignPanel.alignmentChanged(); + } + else + { + splitFrameCandidates.put(view, af); + } return af; } @@ -3983,7 +4574,7 @@ public class Jalview2XML } private void reorderAutoannotation(AlignFrame af, Alignment al, - ArrayList autoAlan) + List autoAlan) { // copy over visualization settings for autocalculated annotation in the // view @@ -3992,8 +4583,8 @@ public class Jalview2XML /** * Kludge for magic autoannotation names (see JAL-811) */ - String[] magicNames = new String[] - { "Consensus", "Quality", "Conservation" }; + String[] magicNames = new String[] { "Consensus", "Quality", + "Conservation" }; JvAnnotRow nullAnnot = new JvAnnotRow(-1, null); Hashtable visan = new Hashtable(); for (String nm : magicNames) @@ -4007,11 +4598,11 @@ public class Jalview2XML + auan.template.getCalcId()), auan); } int hSize = al.getAlignmentAnnotation().length; - ArrayList reorder = new ArrayList(); + List reorder = new ArrayList(); // work through any autoCalculated annotation already on the view // removing it if it should be placed in a different location on the // annotation panel. - List remains = new ArrayList(visan.keySet()); + List remains = new ArrayList(visan.keySet()); for (int h = 0; h < hSize; h++) { jalview.datamodel.AlignmentAnnotation jalan = al @@ -4183,9 +4774,8 @@ public class Jalview2XML { // JBP TODO: Check this is called for AlCodonFrames to support recovery of // xRef Codon Maps - jalview.datamodel.Sequence sq = (jalview.datamodel.Sequence) seqRefIds - .get(vamsasSeq.getId()); - jalview.datamodel.SequenceI dsq = null; + SequenceI sq = seqRefIds.get(vamsasSeq.getId()); + SequenceI dsq = null; if (sq != null && sq.getDatasetSequence() != null) { dsq = sq.getDatasetSequence(); @@ -4260,7 +4850,7 @@ public class Jalview2XML // if (pre || post) if (sq != dsq) { - StringBuffer sb = new StringBuffer(); + // StringBuffer sb = new StringBuffer(); String newres = jalview.analysis.AlignSeq.extractGaps( jalview.util.Comparison.GapChars, sq.getSequenceAsString()); if (!newres.equalsIgnoreCase(dsq.getSequenceAsString()) @@ -4287,20 +4877,24 @@ public class Jalview2XML } } - java.util.Hashtable datasetIds = null; + /* + * TODO use AlignmentI here and in related methods - needs + * AlignmentI.getDataset() changed to return AlignmentI instead of Alignment + */ + Hashtable datasetIds = null; - java.util.IdentityHashMap dataset2Ids = null; + IdentityHashMap dataset2Ids = null; private Alignment getDatasetFor(String datasetId) { if (datasetIds == null) { - datasetIds = new Hashtable(); + datasetIds = new Hashtable(); return null; } if (datasetIds.containsKey(datasetId)) { - return (Alignment) datasetIds.get(datasetId); + return datasetIds.get(datasetId); } return null; } @@ -4309,7 +4903,7 @@ public class Jalview2XML { if (datasetIds == null) { - datasetIds = new Hashtable(); + datasetIds = new Hashtable(); } datasetIds.put(datasetId, dataset); } @@ -4320,7 +4914,7 @@ public class Jalview2XML * @param dataset * @return */ - private String getDatasetIdRef(jalview.datamodel.Alignment dataset) + private String getDatasetIdRef(Alignment dataset) { if (dataset.getDataset() != null) { @@ -4332,11 +4926,11 @@ public class Jalview2XML // make a new datasetId and record it if (dataset2Ids == null) { - dataset2Ids = new IdentityHashMap(); + dataset2Ids = new IdentityHashMap(); } else { - datasetId = (String) dataset2Ids.get(dataset); + datasetId = dataset2Ids.get(dataset); } if (datasetId == null) { @@ -4400,8 +4994,7 @@ public class Jalview2XML } else { - frefedSequence.add(new Object[] - { dsfor, jmap }); + frefedSequence.add(new Object[] { dsfor, jmap }); } } else @@ -4410,14 +5003,14 @@ public class Jalview2XML * local sequence definition */ Sequence ms = mc.getSequence(); - jalview.datamodel.Sequence djs = null; + SequenceI djs = null; String sqid = ms.getDsseqid(); if (sqid != null && sqid.length() > 0) { /* * recover dataset sequence */ - djs = (jalview.datamodel.Sequence) seqRefIds.get(sqid); + djs = seqRefIds.get(sqid); } else { @@ -4455,8 +5048,7 @@ public class Jalview2XML boolean keepSeqRefs) { initSeqRefs(); - jalview.schemabinding.version2.JalviewModel jm = saveState(ap, null, - null); + JalviewModel jm = saveState(ap, null, null, null); if (!keepSeqRefs) { @@ -4476,7 +5068,7 @@ public class Jalview2XML frefedSequence = new Vector(); } - viewportsAdded = new Hashtable(); + viewportsAdded.clear(); AlignFrame af = loadFromObject(jm, null, false, null); af.alignPanels.clear(); @@ -4623,13 +5215,9 @@ public class Jalview2XML } else if (jvobj instanceof jalview.datamodel.AlignmentAnnotation) { - if (annotationIds == null) - { - annotationIds = new Hashtable(); - } String anid; - annotationIds.put(anid = jv2vobj.get(jvobj).toString(), jvobj); - jalview.datamodel.AlignmentAnnotation jvann = (jalview.datamodel.AlignmentAnnotation) jvobj; + AlignmentAnnotation jvann = (AlignmentAnnotation) jvobj; + annotationIds.put(anid = jv2vobj.get(jvobj).toString(), jvann); if (jvann.annotationId == null) { jvann.annotationId = anid; @@ -4681,4 +5269,76 @@ public class Jalview2XML skipList = skipList2; } + /** + * Reads the jar entry of given name and returns its contents, or null if the + * entry is not found. + * + * @param jprovider + * @param jarEntryName + * @return + */ + protected String readJarEntry(jarInputStreamProvider jprovider, + String jarEntryName) + { + String result = null; + BufferedReader in = null; + + try + { + /* + * Reopen the jar input stream and traverse its entries to find a matching + * name + */ + JarInputStream jin = jprovider.getJarInputStream(); + JarEntry entry = null; + do + { + entry = jin.getNextJarEntry(); + } while (entry != null && !entry.getName().equals(jarEntryName)); + + if (entry != null) + { + StringBuilder out = new StringBuilder(256); + in = new BufferedReader(new InputStreamReader(jin, UTF_8)); + String data; + + while ((data = in.readLine()) != null) + { + out.append(data); + } + result = out.toString(); + } + 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 + } + } + } + + return result; + } + + /** + * Returns an incrementing counter (0, 1, 2...) + * + * @return + */ + private synchronized int nextCounter() + { + return counter++; + } }