X-Git-Url: http://source.jalview.org/gitweb/?a=blobdiff_plain;f=src%2Fjalview%2Fproject%2FJalview2XML.java;h=aa4cd6ce583a470fadf7a10c56e2c5c72cd8b1ed;hb=9041085cce94f093479be520a8f3553de6e2381f;hp=b408c073e0b31da41ea08a3b90b39154ce0e41dd;hpb=7ec3bb005b1dd1621d386b05087ebab33fc47d0f;p=jalview.git diff --git a/src/jalview/project/Jalview2XML.java b/src/jalview/project/Jalview2XML.java index b408c07..aa4cd6c 100644 --- a/src/jalview/project/Jalview2XML.java +++ b/src/jalview/project/Jalview2XML.java @@ -28,6 +28,8 @@ import java.awt.Color; import java.awt.Font; import java.awt.Rectangle; import java.io.BufferedReader; +import java.io.ByteArrayInputStream; +import java.io.DataInputStream; import java.io.DataOutputStream; import java.io.File; import java.io.FileInputStream; @@ -102,21 +104,17 @@ import jalview.datamodel.features.FeatureMatcher; import jalview.datamodel.features.FeatureMatcherI; import jalview.datamodel.features.FeatureMatcherSet; import jalview.datamodel.features.FeatureMatcherSetI; -import jalview.ext.rbvi.chimera.JalviewChimeraBinding; import jalview.ext.varna.RnaModel; import jalview.gui.AlignFrame; import jalview.gui.AlignViewport; import jalview.gui.AlignmentPanel; import jalview.gui.AppVarna; import jalview.gui.ChimeraViewFrame; -import jalview.gui.ChimeraXViewFrame; import jalview.gui.Desktop; -import jalview.gui.JalviewChimeraXBindingModel; import jalview.gui.JvOptionPane; import jalview.gui.OOMWarning; import jalview.gui.PCAPanel; import jalview.gui.PaintRefresher; -import jalview.gui.PymolViewer; import jalview.gui.SplitFrame; import jalview.gui.StructureViewer; import jalview.gui.StructureViewer.ViewerType; @@ -138,6 +136,7 @@ import jalview.schemes.UserColourScheme; import jalview.structure.StructureSelectionManager; import jalview.structures.models.AAStructureBindingModel; import jalview.util.Format; +import jalview.util.HttpUtils; import jalview.util.MessageManager; import jalview.util.Platform; import jalview.util.StringUtils; @@ -215,6 +214,15 @@ import jalview.xml.binding.jalview.VAMSAS; */ public class Jalview2XML { + + // BH 2018 we add the .jvp binary extension to J2S so that + // it will declare that binary when we do the file save from the browser + + static + { + Platform.addJ2SBinaryType(".jvp?"); + } + private static final String VIEWER_PREFIX = "viewer_"; private static final String RNA_PREFIX = "rna_"; @@ -458,7 +466,7 @@ public class Jalview2XML public boolean isResolvable() { return super.isResolvable() && mp.getTo() != null; - }; + } @Override boolean resolve() @@ -690,7 +698,6 @@ public class Jalview2XML } catch (Exception foo) { } - ; jout.close(); } catch (Exception ex) { @@ -752,9 +759,10 @@ public class Jalview2XML try { // create backupfiles object and get new temp filename destination - BackupFiles backupfiles = new BackupFiles(jarFile); - FileOutputStream fos = new FileOutputStream( - backupfiles.getTempFilePath()); + boolean doBackup = BackupFiles.getEnabled(); + BackupFiles backupfiles = doBackup ? new BackupFiles(jarFile) : null; + FileOutputStream fos = new FileOutputStream(doBackup ? + backupfiles.getTempFilePath() : jarFile); JarOutputStream jout = new JarOutputStream(fos); List frames = new ArrayList<>(); @@ -775,12 +783,14 @@ public class Jalview2XML } catch (Exception foo) { } - ; jout.close(); boolean success = true; - backupfiles.setWriteSuccess(success); - success = backupfiles.rollBackupsAndRenameTempFile(); + if (doBackup) + { + backupfiles.setWriteSuccess(success); + success = backupfiles.rollBackupsAndRenameTempFile(); + } return success; } catch (Exception ex) @@ -951,7 +961,7 @@ public class Jalview2XML else { vamsasSeq = createVamsasSequence(id, jds); -// vamsasSet.addSequence(vamsasSeq); + // vamsasSet.addSequence(vamsasSeq); vamsasSet.getSequence().add(vamsasSeq); vamsasSetIds.put(id, vamsasSeq); seqRefIds.put(id, jds); @@ -1082,13 +1092,14 @@ public class Jalview2XML if (frames[f] instanceof StructureViewerBase) { StructureViewerBase viewFrame = (StructureViewerBase) frames[f]; - matchedFile = saveStructureState(ap, jds, pdb, entry, viewIds, + matchedFile = saveStructureViewer(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(); + String viewerType = viewFrame.getViewerType().toString(); if (!storeDS && !viewIds.contains(viewId)) { viewIds.add(viewId); @@ -1096,13 +1107,13 @@ public class Jalview2XML if (viewerState != null) { copyFileToJar(jout, viewerState.getPath(), - getViewerJarEntryName(viewId)); + getViewerJarEntryName(viewId), viewerType); } else { Cache.log.error("Failed to save viewer state for " + - viewFrame.getViewerType().toString()); + viewerType); } } } @@ -1124,7 +1135,7 @@ public class Jalview2XML if (!pdbfiles.contains(pdbId)) { pdbfiles.add(pdbId); - copyFileToJar(jout, matchedFile, pdbId); + copyFileToJar(jout, matchedFile, pdbId, pdbId); } } @@ -1394,7 +1405,7 @@ public class Jalview2XML } } - //jms.setJGroup(groups); + // jms.setJGroup(groups); Object group; for (JGroup grp : groups) { @@ -1671,6 +1682,7 @@ public class Jalview2XML // using save and then load try { + fileName = fileName.replace('\\', '/'); System.out.println("Writing jar entry " + fileName); JarEntry entry = new JarEntry(fileName); jout.putNextEntry(entry); @@ -1971,7 +1983,7 @@ public class Jalview2XML String varnaStateFile = varna.getStateInfo(model.rna); jarEntryName = RNA_PREFIX + viewId + "_" + nextCounter(); - copyFileToJar(jout, varnaStateFile, jarEntryName); + copyFileToJar(jout, varnaStateFile, jarEntryName, "Varna"); rnaSessions.put(model, jarEntryName); } SecondaryStructure ss = new SecondaryStructure(); @@ -1995,16 +2007,19 @@ public class Jalview2XML * @param jout * @param infilePath * @param jarEntryName + * @param msg + * additional identifying info to log to the console */ protected void copyFileToJar(JarOutputStream jout, String infilePath, - String jarEntryName) + String jarEntryName, String msg) { try (InputStream is = new FileInputStream(infilePath)) { File file = new File(infilePath); if (file.exists() && jout != null) { - System.out.println("Writing jar entry " + jarEntryName); + System.out.println( + "Writing jar entry " + jarEntryName + " (" + msg + ")"); jout.putNextEntry(new JarEntry(jarEntryName)); copyAll(is, jout); jout.closeEntry(); @@ -2020,28 +2035,6 @@ public class Jalview2XML } /** - * 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(); - } - } - - /** * Copies input to output, in 4K buffers; handles any data (text or binary) * * @param in @@ -2072,7 +2065,7 @@ public class Jalview2XML * @param viewFrame * @return */ - protected String saveStructureState(AlignmentPanel ap, SequenceI jds, + protected String saveStructureViewer(AlignmentPanel ap, SequenceI jds, Pdbids pdb, PDBEntry entry, List viewIds, String matchedFile, StructureViewerBase viewFrame) { @@ -2510,7 +2503,7 @@ public class Jalview2XML vamsasSeq.setName(jds.getName()); vamsasSeq.setSequence(jds.getSequenceAsString()); vamsasSeq.setDescription(jds.getDescription()); - jalview.datamodel.DBRefEntry[] dbrefs = null; + List dbrefs = null; if (jds.getDatasetSequence() != null) { vamsasSeq.setDsseqid(seqHash(jds.getDatasetSequence())); @@ -2532,20 +2525,20 @@ public class Jalview2XML */ if (dbrefs != null) { - for (int d = 0; d < dbrefs.length; d++) + for (int d = 0, nd = dbrefs.size(); d < nd; d++) { DBRef dbref = new DBRef(); - DBRefEntry dbRefEntry = dbrefs[d]; - dbref.setSource(dbRefEntry.getSource()); - dbref.setVersion(dbRefEntry.getVersion()); - dbref.setAccessionId(dbRefEntry.getAccessionId()); - if (dbRefEntry instanceof GeneLocus) + DBRefEntry ref = dbrefs.get(d); + dbref.setSource(ref.getSource()); + dbref.setVersion(ref.getVersion()); + dbref.setAccessionId(ref.getAccessionId()); + if (ref instanceof GeneLocus) { dbref.setLocus(true); } - if (dbRefEntry.hasMap()) + if (ref.hasMap()) { - Mapping mp = createVamsasMapping(dbRefEntry.getMap(), parentseq, + Mapping mp = createVamsasMapping(ref.getMap(), parentseq, jds, recurse); dbref.setMapping(mp); } @@ -2740,7 +2733,7 @@ public class Jalview2XML * @param file * - HTTP URL or filename */ - public AlignFrame loadJalviewAlign(final String file) + public AlignFrame loadJalviewAlign(final Object file) { jalview.gui.AlignFrame af = null; @@ -2774,7 +2767,7 @@ public class Jalview2XML public void run() { setLoadingFinishedForNewStructureViewers(); - }; + } }); } catch (Exception x) { @@ -2784,17 +2777,22 @@ public class Jalview2XML return af; } - private jarInputStreamProvider createjarInputStreamProvider( - final String file) throws MalformedURLException - { - URL url = null; - errorMessage = null; - uniqueSetSuffix = null; - seqRefIds = null; - viewportsAdded.clear(); - frefedSequence = null; + @SuppressWarnings("unused") + private jarInputStreamProvider createjarInputStreamProvider(final Object ofile) throws MalformedURLException { - if (file.startsWith("http://")) + // BH 2018 allow for bytes already attached to File object + try { + String file = (ofile instanceof File ? ((File) ofile).getCanonicalPath() : ofile.toString()); + byte[] bytes = Platform.isJS() ? Platform.getFileBytes((File) ofile) + : null; + URL url = null; + errorMessage = null; + uniqueSetSuffix = null; + seqRefIds = null; + viewportsAdded.clear(); + frefedSequence = null; + + if (HttpUtils.startsWithHttpOrHttps(file)) { url = new URL(file); } @@ -2802,26 +2800,31 @@ public class Jalview2XML return new jarInputStreamProvider() { - @Override - public JarInputStream getJarInputStream() throws IOException - { - if (_url != null) - { - return new JarInputStream(_url.openStream()); - } - else - { - return new JarInputStream(new FileInputStream(file)); - } - } - - @Override - public String getFilename() - { - return file; - } - }; - } + @Override + public JarInputStream getJarInputStream() throws IOException { + if (bytes != null) { +// System.out.println("Jalview2XML: opening byte jarInputStream for bytes.length=" + bytes.length); + return new JarInputStream(new ByteArrayInputStream(bytes)); + } + if (_url != null) { +// System.out.println("Jalview2XML: opening url jarInputStream for " + _url); + return new JarInputStream(_url.openStream()); + } else { +// System.out.println("Jalview2XML: opening file jarInputStream for " + file); + return new JarInputStream(new FileInputStream(file)); + } + } + + @Override + public String getFilename() { + return file; + } + }; + } catch (IOException e) { + e.printStackTrace(); + return null; + } + } /** * Recover jalview session from a jalview project archive. Caller may @@ -2863,9 +2866,6 @@ public class Jalview2XML if (jarentry != null && jarentry.getName().endsWith(".xml")) { - InputStreamReader in = new InputStreamReader(jin, UTF_8); - // JalviewModel object = new JalviewModel(); - JAXBContext jc = JAXBContext .newInstance("jalview.xml.binding.jalview"); XMLStreamReader streamReader = XMLInputFactory.newInstance() @@ -2875,11 +2875,6 @@ public class Jalview2XML .unmarshal(streamReader, JalviewModel.class); JalviewModel object = jbe.getValue(); - /* - Unmarshaller unmar = new Unmarshaller(object); - unmar.setValidation(false); - object = (JalviewModel) unmar.unmarshal(in); - */ if (true) // !skipViewport(object)) { _af = loadFromObject(object, file, true, jprovider); @@ -4295,10 +4290,15 @@ public class Jalview2XML } if (!structureViewers.containsKey(sviewid)) { + String viewerType = structureState.getType(); + if (viewerType == null) // pre Jalview 2.9 + { + viewerType = ViewerType.JMOL.toString(); + } structureViewers.put(sviewid, new StructureViewerModel(x, y, width, height, false, false, true, structureState.getViewId(), - structureState.getType())); + viewerType)); // Legacy pre-2.7 conversion JAL-823 : // do not assume any view has to be linked for colour by // sequence @@ -4399,273 +4399,20 @@ public class Jalview2XML return; } - /* - * From 2.9: stateData.type contains JMOL or CHIMERA, data is in jar entry - * "viewer_"+stateData.viewId - */ String type = stateData.getType(); - if (type == null) - { - type = ViewerType.JMOL.toString(); - } try { ViewerType viewerType = ViewerType.valueOf(type); - switch (viewerType) - { - case CHIMERA: - createChimeraViewer(viewerData, af, jprovider, false); - break; - case CHIMERAX: - createChimeraViewer(viewerData, af, jprovider, true); - break; - case PYMOL: - createPymolViewer(viewerData, af, jprovider); - break; - case JMOL: - createJmolViewer(viewerData, af, jprovider); - } + createStructureViewer(viewerType, viewerData, af, jprovider); } catch (IllegalArgumentException | NullPointerException e) { + // TODO JAL-3619 show error dialog / offer an alternative viewer Cache.log.error( "Invalid structure viewer type: " + type); } } /** - * Create a new Chimera or ChimeraX viewer - * - * @param data - * @param af - * @param jprovider - * @param isChimeraX - */ - protected void createChimeraViewer( - Entry viewerData, AlignFrame af, - jarInputStreamProvider jprovider, boolean isChimeraX) - { - 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()); - String extension = isChimeraX - ? JalviewChimeraXBindingModel.CHIMERAX_SESSION_EXTENSION - : JalviewChimeraBinding.CHIMERA_SESSION_EXTENSION; - chimeraSessionFile = copyJarEntry(jprovider, viewerJarEntryName, - "chimera", extension); - - 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 = isChimeraX - ? new ChimeraXViewFrame(chimeraSessionFile, af.alignPanel, - pdbArray, seqsArray, colourByChimera, colourBySequence, - newViewId) - : 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())); - } - - 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)); - if (filedat == null) - { - String reformatedOldFilename = oldfilenam.replaceAll("/", "\\\\"); - filedat = oldFiles.get(new File(reformatedOldFilename)); - } - newFileLoc.append(Platform.escapeBackslashes(filedat.getFilePath())); - pdbfilenames.add(filedat.getFilePath()); - pdbids.add(filedat.getPdbId()); - seqmaps.add(filedat.getSeqList().toArray(new SequenceI[0])); - newFileLoc.append("\""); - cp = ecp + 1; // advance beyond last \" and set cursor so we can - // look for next file statement. - } while ((ncp = state.indexOf("/*file*/", cp)) > -1); - } - if (cp > 0) - { - // just append rest of state - newFileLoc.append(state.substring(cp)); - } - else - { - System.err.print("Ignoring incomplete Jmol state for PDB ids: "); - newFileLoc = new StringBuilder(state); - newFileLoc.append("; load append "); - for (File id : oldFiles.keySet()) - { - // add this and any other pdb files that should be present in - // the viewer - StructureData filedat = oldFiles.get(id); - newFileLoc.append(filedat.getFilePath()); - pdbfilenames.add(filedat.getFilePath()); - pdbids.add(filedat.getPdbId()); - seqmaps.add(filedat.getSeqList().toArray(new SequenceI[0])); - newFileLoc.append(" \""); - newFileLoc.append(filedat.getFilePath()); - newFileLoc.append("\""); - - } - newFileLoc.append(";"); - } - - if (newFileLoc.length() == 0) - { - return; - } - int histbug = newFileLoc.indexOf("history = "); - if (histbug > -1) - { - /* - * change "history = [true|false];" to "history = [1|0];" - */ - histbug += 10; - int diff = histbug == -1 ? -1 : newFileLoc.indexOf(";", histbug); - String val = (diff == -1) ? null - : newFileLoc.substring(histbug, diff); - if (val != null && val.length() >= 4) - { - if (val.contains("e")) // eh? what can it be? - { - if (val.trim().equals("true")) - { - val = "1"; - } - else - { - val = "0"; - } - newFileLoc.replace(histbug, diff, val); - } - } - } - - final String[] pdbf = pdbfilenames - .toArray(new String[pdbfilenames.size()]); - final String[] id = pdbids.toArray(new String[pdbids.size()]); - final SequenceI[][] sq = seqmaps - .toArray(new SequenceI[seqmaps.size()][]); - final String fileloc = newFileLoc.toString(); - final String sviewid = viewerData.getKey(); - final AlignFrame alf = af; - final Rectangle rect = new Rectangle(svattrib.getX(), svattrib.getY(), - svattrib.getWidth(), svattrib.getHeight()); - try - { - javax.swing.SwingUtilities.invokeAndWait(new Runnable() - { - @Override - public void run() - { - JalviewStructureDisplayI sview = null; - try - { - sview = new StructureViewer( - alf.alignPanel.getStructureSelectionManager()) - .createView(StructureViewer.ViewerType.JMOL, - pdbf, id, sq, alf.alignPanel, svattrib, - fileloc, rect, sviewid); - addNewStructureViewer(sview); - } catch (OutOfMemoryError ex) - { - new OOMWarning("restoring structure view for PDB id " + id, - (OutOfMemoryError) ex.getCause()); - if (sview != null && sview.isVisible()) - { - sview.closeViewer(false); - sview.setVisible(false); - sview.dispose(); - } - } - } - }); - } catch (InvocationTargetException ex) - { - warn("Unexpected error when opening Jmol view.", ex); - - } catch (InterruptedException e) - { - // e.printStackTrace(); - } - - } - - /** * Generates a name for the entry in the project jar file to hold state * information for a structure viewer * @@ -4867,7 +4614,18 @@ public class Jalview2XML { AlignFrame af = null; af = new AlignFrame(al, safeInt(view.getWidth()), - safeInt(view.getHeight()), uniqueSeqSetId, viewId); + safeInt(view.getHeight()), uniqueSeqSetId, viewId) +// { +// +// @Override +// protected void processKeyEvent(java.awt.event.KeyEvent e) { +// System.out.println("Jalview2XML AF " + e); +// super.processKeyEvent(e); +// +// } +// +// } + ; af.setFileName(file, FileFormat.Jalview); @@ -5508,7 +5266,7 @@ public class Jalview2XML addDatasetRef(vamsasSet.getDatasetId(), ds); } } - Vector dseqs = null; + Vector dseqs = null; if (!ignoreUnrefed) { // recovering an alignment View @@ -5536,7 +5294,7 @@ public class Jalview2XML // try even harder to restore dataset AlignmentI xtantDS = checkIfHasDataset(vamsasSet.getSequence()); // create a list of new dataset sequences - dseqs = new Vector(); + dseqs = new Vector<>(); } for (int i = 0, iSize = vamsasSet.getSequence().size(); i < iSize; i++) { @@ -5624,7 +5382,8 @@ public class Jalview2XML * vamsasSeq array ordering, to preserve ordering of dataset */ private void ensureJalviewDatasetSequence(Sequence vamsasSeq, - AlignmentI ds, Vector dseqs, boolean ignoreUnrefed, int vseqpos) + AlignmentI ds, Vector dseqs, boolean ignoreUnrefed, + int vseqpos) { // JBP TODO: Check this is called for AlCodonFrames to support recovery of // xRef Codon Maps @@ -6348,58 +6107,174 @@ public class Jalview2XML } /** - * Create a new PyMol viewer + * Creates a new structure viewer window * - * @param data + * @param viewerType + * @param viewerData * @param af * @param jprovider */ - protected void createPymolViewer( - Entry viewerData, AlignFrame af, + protected void createStructureViewer( + ViewerType viewerType, final Entry viewerData, + AlignFrame af, jarInputStreamProvider jprovider) + { + final StructureViewerModel viewerModel = viewerData.getValue(); + String sessionFilePath = null; + + if (viewerType == ViewerType.JMOL) + { + sessionFilePath = rewriteJmolSession(viewerModel, jprovider); + } + else + { + String viewerJarEntryName = getViewerJarEntryName( + viewerModel.getViewId()); + sessionFilePath = copyJarEntry(jprovider, + viewerJarEntryName, + "viewerSession", ".tmp"); + } + final String sessionPath = sessionFilePath; + final String sviewid = viewerData.getKey(); + try + { + SwingUtilities.invokeAndWait(new Runnable() + { + @Override + public void run() + { + JalviewStructureDisplayI sview = null; + try + { + sview = StructureViewer.createView(viewerType, af.alignPanel, + viewerModel, sessionPath, sviewid); + addNewStructureViewer(sview); + } catch (OutOfMemoryError ex) + { + new OOMWarning("Restoring structure view for " + + viewerType, + (OutOfMemoryError) ex.getCause()); + if (sview != null && sview.isVisible()) + { + sview.closeViewer(false); + sview.setVisible(false); + sview.dispose(); + } + } + } + }); + } catch (InvocationTargetException | InterruptedException ex) + { + warn("Unexpected error when opening " + viewerType + + " structure viewer", ex); + } + } + + /** + * Rewrites a Jmol session script, saves it to a temporary file, and returns + * the path of the file. "load file" commands are rewritten to change the + * original PDB file names to those created as the Jalview project is loaded. + * + * @param svattrib + * @param jprovider + * @return + */ + private String rewriteJmolSession(StructureViewerModel svattrib, jarInputStreamProvider jprovider) { - StructureViewerModel data = viewerData.getValue(); - String pymolSessionFile = data.getStateData(); - - /* - * Copy PyMol 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()); - pymolSessionFile = copyJarEntry(jprovider, viewerJarEntryName, - "pymol", ".pse"); - - 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); + String state = svattrib.getStateData(); // Jalview < 2.9 + if (state == null || state.isEmpty()) // Jalview >= 2.9 + { + String jarEntryName = getViewerJarEntryName(svattrib.getViewId()); + state = readJarEntry(jprovider, jarEntryName); } - - boolean colourByPymol = 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(); - - PymolViewer pv = new PymolViewer(pymolSessionFile, - af.alignPanel, pdbArray, seqsArray, colourByPymol, - colourBySequence, newViewId); - pv.setSize(data.getWidth(), data.getHeight()); - pv.setLocation(data.getX(), data.getY()); + // TODO or simpler? for each key in oldFiles, + // replace key.getPath() in state with oldFiles.get(key).getFilePath() + // (allowing for different path escapings) + StringBuilder rewritten = new StringBuilder(state.length()); + int cp = 0, ncp, ecp; + Map oldFiles = svattrib.getFileData(); + while ((ncp = state.indexOf("load ", cp)) > -1) + { + do + { + // look for next filename in load statement + rewritten.append(state.substring(cp, + ncp = (state.indexOf("\"", ncp + 1) + 1))); + String oldfilenam = state.substring(ncp, + ecp = state.indexOf("\"", ncp)); + // recover the new mapping data for this old filename + // have to normalize filename - since Jmol and jalview do + // filename translation differently. + StructureData filedat = oldFiles.get(new File(oldfilenam)); + if (filedat == null) + { + String reformatedOldFilename = oldfilenam.replaceAll("/", "\\\\"); + filedat = oldFiles.get(new File(reformatedOldFilename)); + } + rewritten + .append(Platform.escapeBackslashes(filedat.getFilePath())); + rewritten.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 + rewritten.append(state.substring(cp)); + } + else + { + System.err.print("Ignoring incomplete Jmol state for PDB ids: "); + rewritten = new StringBuilder(state); + rewritten.append("; load append "); + for (File id : oldFiles.keySet()) + { + // add pdb files that should be present in the viewer + StructureData filedat = oldFiles.get(id); + rewritten.append(" \"").append(filedat.getFilePath()).append("\""); + } + rewritten.append(";"); + } + + if (rewritten.length() == 0) + { + return null; + } + final String history = "history = "; + int historyIndex = rewritten.indexOf(history); + if (historyIndex > -1) + { + /* + * change "history = [true|false];" to "history = [1|0];" + */ + historyIndex += history.length(); + String val = rewritten.substring(historyIndex, historyIndex + 5); + if (val.startsWith("true")) + { + rewritten.replace(historyIndex, historyIndex + 4, "1"); + } + else if (val.startsWith("false")) + { + rewritten.replace(historyIndex, historyIndex + 5, "0"); + } + } + + try + { + File tmp = File.createTempFile("viewerSession", ".tmp"); + try (OutputStream os = new FileOutputStream(tmp)) + { + InputStream is = new ByteArrayInputStream( + rewritten.toString().getBytes()); + copyAll(is, os); + return tmp.getAbsolutePath(); + } + } catch (IOException e) + { + Cache.log.error("Error restoring Jmol session: " + e.toString()); + } + return null; } /**