X-Git-Url: http://source.jalview.org/gitweb/?a=blobdiff_plain;f=src%2Fjalview%2Fgui%2FJalview2XML.java;h=80cff07f5b666b94c1da62af3fe05c34babdade4;hb=7a3ba197b00d4016556f3cdd635919fe6817867b;hp=afb424aa60cfa204c8625d9e3fdda718f99ec74e;hpb=25aaaa87042b3f507ad4348120df7dd073182759;p=jalview.git diff --git a/src/jalview/gui/Jalview2XML.java b/src/jalview/gui/Jalview2XML.java index afb424a..80cff07 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.2b1) - * Copyright (C) 2014 The Jalview Authors + * Jalview - A Sequence Alignment Editor and Viewer ($$Version-Rel$$) + * Copyright (C) $$Year-Rel$$ The Jalview Authors * * This file is part of Jalview. * @@ -20,8 +20,48 @@ */ package jalview.gui; +import java.awt.Rectangle; +import java.io.BufferedReader; +import java.io.DataInputStream; +import java.io.DataOutputStream; +import java.io.File; +import java.io.FileInputStream; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.InputStreamReader; +import java.io.OutputStreamWriter; +import java.io.PrintWriter; +import java.lang.reflect.InvocationTargetException; +import java.net.MalformedURLException; +import java.net.URL; +import java.util.ArrayList; +import java.util.Enumeration; +import java.util.HashMap; +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; +import java.util.Set; +import java.util.StringTokenizer; +import java.util.Vector; +import java.util.jar.JarEntry; +import java.util.jar.JarInputStream; +import java.util.jar.JarOutputStream; + +import javax.swing.JInternalFrame; +import javax.swing.JOptionPane; +import javax.swing.SwingUtilities; + +import org.exolab.castor.xml.Marshaller; +import org.exolab.castor.xml.Unmarshaller; + 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; @@ -29,8 +69,8 @@ import jalview.datamodel.PDBEntry; import jalview.datamodel.SequenceI; import jalview.datamodel.StructureViewerModel; import jalview.datamodel.StructureViewerModel.StructureData; +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; @@ -83,44 +123,6 @@ import jalview.ws.params.ArgumentI; import jalview.ws.params.AutoCalcSetting; import jalview.ws.params.WsParamSetI; -import java.awt.Rectangle; -import java.io.BufferedReader; -import java.io.DataInputStream; -import java.io.DataOutputStream; -import java.io.File; -import java.io.FileInputStream; -import java.io.FileOutputStream; -import java.io.IOException; -import java.io.InputStreamReader; -import java.io.OutputStreamWriter; -import java.io.PrintWriter; -import java.lang.reflect.InvocationTargetException; -import java.net.MalformedURLException; -import java.net.URL; -import java.util.ArrayList; -import java.util.Enumeration; -import java.util.HashMap; -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; -import java.util.Set; -import java.util.StringTokenizer; -import java.util.Vector; -import java.util.jar.JarEntry; -import java.util.jar.JarInputStream; -import java.util.jar.JarOutputStream; - -import javax.swing.JInternalFrame; -import javax.swing.JOptionPane; -import javax.swing.SwingUtilities; - -import org.exolab.castor.xml.Unmarshaller; - /** * Write out the current jalview desktop state as a Jalview XML stream. * @@ -133,6 +135,8 @@ import org.exolab.castor.xml.Unmarshaller; */ public class Jalview2XML { + private static final String UTF_8 = "UTF-8"; + /* * SequenceI reference -> XML ID string in jalview XML. Populated as XML reps * of sequence objects are created. @@ -150,6 +154,12 @@ 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(); + /** * create/return unique hash string for sq * @@ -298,12 +308,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 = ""; @@ -359,7 +369,7 @@ public class Jalview2XML */ public void saveState(JarOutputStream jout) { - JInternalFrame[] frames = Desktop.desktop.getAllFrames(); + AlignFrame[] frames = Desktop.getAlignFrames(); // Desktop.desktop.getAllFrames(); if (frames == null) { @@ -374,72 +384,40 @@ public class Jalview2XML // NOTE UTF-8 MUST BE USED FOR WRITING UNICODE CHARS // ////////////////////////////////////////////////// - Vector shortNames = new Vector(); + List shortNames = 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); - 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); } } } @@ -467,21 +445,62 @@ 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++) + 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"; @@ -682,9 +701,9 @@ public class Jalview2XML } } - if (jdatasq.getSequenceFeatures() != null) + if (jds.getSequenceFeatures() != null) { - jalview.datamodel.SequenceFeature[] sf = jdatasq + jalview.datamodel.SequenceFeature[] sf = jds .getSequenceFeatures(); int index = 0; while (index < sf.length) @@ -735,7 +754,8 @@ public class Jalview2XML jalview.datamodel.PDBEntry entry = (jalview.datamodel.PDBEntry) en .nextElement(); - pdb.setId(entry.getId()); + String pdbId = entry.getId(); + pdb.setId(pdbId); pdb.setType(entry.getType()); /* @@ -753,6 +773,24 @@ 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 each XML + * document. First time through only (storeDS==false) + */ + String viewId = viewFrame.getViewId(); + if (!storeDS && !viewIds.contains(viewId)) + { + viewIds.add(viewId); + try + { + writeJarEntry(jout, getViewerJarEntryName(viewId), + viewFrame.getStateInfo().getBytes()); + } catch (IOException e) + { + System.err.println("Error saving viewer state: " + + e.getMessage()); + } + } } } @@ -769,47 +807,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(); @@ -837,31 +842,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++) + if (acf.getProtMappings() != null + && acf.getProtMappings().length > 0) { - 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) - { - 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(); @@ -871,6 +863,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); +// } +// } } } @@ -918,6 +941,25 @@ public class Jalview2XML } } } + + /* + * Save associated Varna panels + */ + if (Desktop.desktop != null) + { + for (JInternalFrame frame : Desktop.desktop.getAllFrames()) + { + if (frame instanceof AppVarna) + { + AppVarna vp = (AppVarna) frame; + if (vp.ap == ap) + { + // save Varna state + } + } + } + } + // SAVE ANNOTATIONS /** * store forward refs from an annotationRow to any groups @@ -1031,23 +1073,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); @@ -1097,7 +1138,7 @@ public class Jalview2XML view.setFontName(av.font.getName()); view.setFontSize(av.font.getSize()); view.setFontStyle(av.font.getStyle()); - view.setRenderGaps(av.renderGaps); + view.setRenderGaps(av.isRenderGaps()); view.setShowAnnotation(av.isShowAnnotation()); view.setShowBoxes(av.getShowBoxes()); view.setShowColourText(av.getColourText()); @@ -1107,25 +1148,26 @@ public class Jalview2XML 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() - .getRenderOrder().toArray(new String[0]); + String[] renderOrder = ap.getSeqPanel().seqCanvas + .getFeatureRenderer().getRenderOrder() + .toArray(new String[0]); Vector settingsAdded = new Vector(); Object gstyle = null; @@ -1152,7 +1194,8 @@ public class Jalview2XML } else { - setting.setColour(ap.getSeqPanel().seqCanvas.getFeatureRenderer() + setting.setColour(ap.getSeqPanel().seqCanvas + .getFeatureRenderer() .getColour(renderOrder[ro]).getRGB()); } @@ -1196,8 +1239,8 @@ public class Jalview2XML settingsAdded.addElement(key); } // is groups actually supposed to be a map here ? - en = ap.getSeqPanel().seqCanvas.getFeatureRenderer().getFeatureGroups() - .iterator(); + en = ap.getSeqPanel().seqCanvas.getFeatureRenderer() + .getFeatureGroups().iterator(); Vector groupsAdded = new Vector(); while (en.hasNext()) { @@ -1230,8 +1273,8 @@ public class Jalview2XML for (int c = 0; c < av.getColumnSelection().getHiddenColumns() .size(); c++) { - int[] region = av.getColumnSelection() - .getHiddenColumns().get(c); + int[] region = av.getColumnSelection().getHiddenColumns() + .get(c); HiddenColumns hc = new HiddenColumns(); hc.setStart(region[0]); hc.setEnd(region[1]); @@ -1270,9 +1313,8 @@ public class Jalview2XML 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(); @@ -1286,6 +1328,66 @@ public class Jalview2XML } /** + * Copy the contents of a file to a new file added to the output jar + * + * @param jout + * @param infilePath + * @param jarfileName + */ + protected void copyFileToJar(JarOutputStream jout, String infilePath, + String jarfileName) + { + 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, jarfileName, 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 jarfileName + * @param data + * @throws IOException + */ + protected void writeJarEntry(JarOutputStream jout, String jarfileName, + byte[] data) throws IOException + { + if (jout != null) + { + jout.putNextEntry(new JarEntry(jarfileName)); + DataOutputStream dout = new DataOutputStream(jout); + dout.write(data, 0, data.length); + dout.flush(); + jout.closeEntry(); + } + } + + /** * Save the state of a structure viewer * * @param ap @@ -1302,26 +1404,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): " @@ -1332,10 +1438,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]) @@ -1349,21 +1453,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); } } @@ -1645,7 +1737,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() })); } /** @@ -1767,20 +1861,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()); @@ -1977,7 +2071,7 @@ public class Jalview2XML errorMessage = null; uniqueSetSuffix = null; seqRefIds = null; - viewportsAdded = null; + viewportsAdded.clear(); frefedSequence = null; if (file.startsWith("http://")) @@ -2029,17 +2123,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 { @@ -2057,7 +2147,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); @@ -2069,7 +2159,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); } @@ -2139,11 +2229,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(); @@ -2152,6 +2251,109 @@ 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. @@ -2188,7 +2390,7 @@ public class Jalview2XML errorMessage = null; } - Hashtable alreadyLoadedPDB; + Map alreadyLoadedPDB = new HashMap(); /** * when set, local views will be updated from view stored in JalviewXML @@ -2197,17 +2399,47 @@ 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) + if (alreadyLoadedPDB.containsKey(pdbId)) { - alreadyLoadedPDB = new Hashtable(); + return alreadyLoadedPDB.get(pdbId).toString(); } - if (alreadyLoadedPDB.containsKey(pdbId)) + String tempFile = copyJarEntry(jprovider, pdbId, "jalview_pdb"); + if (tempFile != null) { - return alreadyLoadedPDB.get(pdbId).toString(); + 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 { @@ -2222,38 +2454,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; @@ -2305,10 +2545,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; @@ -2340,10 +2580,10 @@ public class Jalview2XML { if (hiddenSeqs == null) { - hiddenSeqs = new Vector(); + hiddenSeqs = new ArrayList(); } - hiddenSeqs.addElement(seqRefIds.get(seqId)); + hiddenSeqs.add(seqRefIds.get(seqId)); } } @@ -2351,13 +2591,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++) @@ -2384,7 +2621,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 @@ -2430,7 +2667,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())) @@ -2443,8 +2690,7 @@ public class Jalview2XML } } StructureSelectionManager.getStructureSelectionManager( - Desktop.instance) - .registerPDBEntry(entry); + Desktop.instance).registerPDBEntry(entry); al.getSequenceAt(i).getDatasetSequence().addPDBId(entry); } } @@ -2461,35 +2707,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. @@ -2511,12 +2735,11 @@ public class Jalview2XML } al.addCodonFrame(cf); } - } // //////////////////////////////// // LOAD ANNOTATIONS - ArrayList autoAlan = new ArrayList(); + List autoAlan = new ArrayList(); /** * store any annotations which forward reference a group's ID */ @@ -2555,8 +2778,7 @@ public class Jalview2XML if (an[i].getId() != null && annotationIds.containsKey(an[i].getId())) { - jalview.datamodel.AlignmentAnnotation jda = (jalview.datamodel.AlignmentAnnotation) annotationIds - .get(an[i].getId()); + AlignmentAnnotation jda = annotationIds.get(an[i].getId()); // in principle Visible should always be true for annotation displayed // in multiple views if (an[i].hasVisible()) @@ -2766,8 +2988,7 @@ public class Jalview2XML for (int s = 0; s < groups[i].getSeqCount(); s++) { String seqId = groups[i].getSeq(s) + ""; - jalview.datamodel.SequenceI ts = seqRefIds - .get(seqId); + jalview.datamodel.SequenceI ts = seqRefIds.get(seqId); if (ts != null) { @@ -3057,10 +3278,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 @@ -3077,8 +3298,8 @@ 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 @@ -3086,8 +3307,10 @@ public class Jalview2XML } if (!structureViewers.containsKey(sviewid)) { - structureViewers.put(sviewid, new StructureViewerModel(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 @@ -3117,8 +3340,7 @@ public class Jalview2XML * pre-2.7 projects) */ boolean colourByViewer = jmoldat.isColourByViewer(); - colourByViewer &= structureState - .hasColourByJmol() ? structureState + colourByViewer &= structureState.hasColourByJmol() ? structureState .getColourByJmol() : true; jmoldat.setColourByViewer(colourByViewer); @@ -3155,11 +3377,20 @@ public class Jalview2XML } } } - // Instantiate the associated structure views - for (Entry entry : structureViewers.entrySet()) + // Instantiate the associated structure views + for (Entry entry : structureViewers + .entrySet()) + { + try + { + createOrLinkStructureViewer(entry, af, ap, jprovider); + } catch (Exception e) { - createOrLinkStructureViewer(entry, af, ap); + System.err.println("Error loading structure viewer: " + + e.getMessage()); + // failed - try the next one } + } } /** @@ -3167,12 +3398,13 @@ public class Jalview2XML * @param viewerData * @param af * @param ap + * @param jprovider */ protected void createOrLinkStructureViewer( Entry viewerData, AlignFrame af, - AlignmentPanel ap) + AlignmentPanel ap, jarInputStreamProvider jprovider) { - final StructureViewerModel svattrib = viewerData.getValue(); + final StructureViewerModel stateData = viewerData.getValue(); /* * Search for any viewer windows already open from other alignment views @@ -3182,68 +3414,75 @@ public class Jalview2XML if (comp != null) { - linkStructureViewer(ap, comp, svattrib); + linkStructureViewer(ap, comp, stateData); return; } /* - * Pending an XML element for ViewerType, just check if stateData contains - * "chimera" (part of the chimera session filename). + * From 2.9: stateData.type contains JMOL or CHIMERA, data is in jar entry + * "viewer_"+stateData.viewId */ - if (svattrib.getStateData().indexOf("chimera") > -1) + if (ViewerType.CHIMERA.toString().equals(stateData.getType())) { - createChimeraViewer(viewerData, af); + createChimeraViewer(viewerData, af, jprovider); } else { - createJmolViewer(viewerData, af); + /* + * else Jmol (if pre-2.9, stateData contains JMOL state string) + */ + createJmolViewer(viewerData, af, jprovider); } } /** * Create a new Chimera viewer. * - * @param viewerData + * @param data * @param af + * @param jprovider */ protected void createChimeraViewer(Entry viewerData, - AlignFrame af) + AlignFrame af, + jarInputStreamProvider jprovider) { - final StructureViewerModel data = viewerData.getValue(); - String chimeraSession = data.getStateData(); + StructureViewerModel data = viewerData.getValue(); + String chimeraSessionFile = data.getStateData(); - if (new File(chimeraSession).exists()) - { - 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)); - 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 can/should this be done via StructureViewer (like Jmol)? - final PDBEntry[] pdbArray = pdbs.toArray(new PDBEntry[pdbs - .size()]); - final SequenceI[][] seqsArray = allseqs.toArray(new SequenceI[allseqs.size()][]); - new ChimeraViewFrame(chimeraSession, af.alignPanel, pdbArray, - seqsArray, - colourByChimera, colourBySequence); - } - else - { - Cache.log.error("Chimera session file " + chimeraSession - + " not found"); - } + /* + * Copy Chimera session from jar entry "viewer_"+viewId to a temporary file + * + * Note this is the 'saved' viewId as in the project file XML, _not_ the + * 'uniquified' sviewid used to reconstruct the viewer here + */ + chimeraSessionFile = copyJarEntry(jprovider, + getViewerJarEntryName(data.getViewId()), "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(); + new ChimeraViewFrame(chimeraSessionFile, af.alignPanel, pdbArray, + seqsArray, colourByChimera, colourBySequence, newViewId); } /** @@ -3253,12 +3492,27 @@ public class Jalview2XML * * @param viewerData * @param af + * @param jprovider */ protected void createJmolViewer( - final Entry viewerData, AlignFrame af) + 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())); + } + List pdbfilenames = new ArrayList(); List seqmaps = new ArrayList(); List pdbids = new ArrayList(); @@ -3282,8 +3536,7 @@ public class Jalview2XML newFileLoc.append(Platform.escapeString(filedat.getFilePath())); pdbfilenames.add(filedat.getFilePath()); pdbids.add(filedat.getPdbId()); - seqmaps.add(filedat.getSeqList() - .toArray(new SequenceI[0])); + 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. @@ -3307,8 +3560,7 @@ public class Jalview2XML newFileLoc.append(filedat.getFilePath()); pdbfilenames.add(filedat.getFilePath()); pdbids.add(filedat.getPdbId()); - seqmaps.add(filedat.getSeqList() - .toArray(new SequenceI[0])); + seqmaps.add(filedat.getSeqList().toArray(new SequenceI[0])); newFileLoc.append(" \""); newFileLoc.append(filedat.getFilePath()); newFileLoc.append("\""); @@ -3360,8 +3612,6 @@ public class Jalview2XML 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, @@ -3373,7 +3623,7 @@ public class Jalview2XML (OutOfMemoryError) ex.getCause()); if (sview != null && sview.isVisible()) { - sview.closeViewer(); + sview.closeViewer(false); sview.setVisible(false); sview.dispose(); } @@ -3392,6 +3642,18 @@ public class Jalview2XML } /** + * 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_" + 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. @@ -3414,11 +3676,11 @@ public class Jalview2XML * Post jalview 2.4 schema includes structure view id */ if (sviewid != null - && ((StructureViewerBase) frame).getViewId().equals( - sviewid)) + && ((StructureViewerBase) frame).getViewId() + .equals(sviewid)) { - comp = (AppJmol) frame; - // todo: break? + comp = (StructureViewerBase) frame; + break; // break added in 2.9 } /* * Otherwise test for matching position and size of viewer frame @@ -3428,8 +3690,8 @@ public class Jalview2XML && frame.getHeight() == svattrib.getHeight() && frame.getWidth() == svattrib.getWidth()) { - comp = (AppJmol) frame; - // todo: break? + comp = (StructureViewerBase) frame; + // no break in faint hope of an exact match on viewId } } } @@ -3447,15 +3709,15 @@ public class Jalview2XML * @param viewerColouring */ protected void linkStructureViewer(AlignmentPanel ap, - StructureViewerBase viewer, StructureViewerModel svattrib) + StructureViewerBase viewer, StructureViewerModel stateData) { // NOTE: if the jalview project is part of a shared session then // view synchronization should/could be done here. - final boolean useinViewerSuperpos = svattrib.isAlignWithPanel(); - final boolean usetoColourbyseq = svattrib.isColourWithAlignPanel(); - final boolean viewerColouring = svattrib.isColourByViewer(); - Map oldFiles = svattrib.getFileData(); + 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 @@ -3600,10 +3862,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(), @@ -3617,19 +3879,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 { @@ -3654,14 +3915,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); } @@ -3682,27 +3946,27 @@ 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); + // 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) @@ -3756,7 +4020,7 @@ public class Jalview2XML } if (view.hasFollowHighlight()) { - af.viewport.followHighlight = view.getFollowHighlight(); + af.viewport.setFollowHighlight(view.getFollowHighlight()); } if (view.hasFollowSelection()) { @@ -3785,11 +4049,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()) { @@ -3910,12 +4174,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; } @@ -4045,7 +4324,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 @@ -4069,11 +4348,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 @@ -4245,9 +4524,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(); @@ -4322,7 +4600,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()) @@ -4472,14 +4750,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 { @@ -4538,7 +4816,7 @@ public class Jalview2XML frefedSequence = new Vector(); } - viewportsAdded = new Hashtable(); + viewportsAdded.clear(); AlignFrame af = loadFromObject(jm, null, false, null); af.alignPanels.clear(); @@ -4685,13 +4963,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; @@ -4742,4 +5016,67 @@ 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; + } }