X-Git-Url: http://source.jalview.org/gitweb/?a=blobdiff_plain;f=src%2Fjalview%2Fproject%2FJalview2XML.java;h=aa4cd6ce583a470fadf7a10c56e2c5c72cd8b1ed;hb=9041085cce94f093479be520a8f3553de6e2381f;hp=af48dbac41fb38a2debfb123bdd1f01ea891e598;hpb=f47d6acd3eb0b61bd292e7bcf970599278666672;p=jalview.git diff --git a/src/jalview/project/Jalview2XML.java b/src/jalview/project/Jalview2XML.java index af48dba..aa4cd6c 100644 --- a/src/jalview/project/Jalview2XML.java +++ b/src/jalview/project/Jalview2XML.java @@ -24,6 +24,57 @@ import static jalview.math.RotatableMatrix.Axis.X; import static jalview.math.RotatableMatrix.Axis.Y; import static jalview.math.RotatableMatrix.Axis.Z; +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; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.io.OutputStream; +import java.io.OutputStreamWriter; +import java.io.PrintWriter; +import java.lang.reflect.InvocationTargetException; +import java.math.BigInteger; +import java.net.MalformedURLException; +import java.net.URL; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; +import java.util.Enumeration; +import java.util.GregorianCalendar; +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.Vector; +import java.util.jar.JarEntry; +import java.util.jar.JarInputStream; +import java.util.jar.JarOutputStream; + +import javax.swing.JInternalFrame; +import javax.swing.SwingUtilities; +import javax.xml.bind.JAXBContext; +import javax.xml.bind.JAXBElement; +import javax.xml.bind.Marshaller; +import javax.xml.datatype.DatatypeConfigurationException; +import javax.xml.datatype.DatatypeFactory; +import javax.xml.datatype.XMLGregorianCalendar; +import javax.xml.stream.XMLInputFactory; +import javax.xml.stream.XMLStreamReader; + import jalview.analysis.Conservation; import jalview.analysis.PCA; import jalview.analysis.scoremodels.ScoreModels; @@ -60,7 +111,6 @@ import jalview.gui.AlignmentPanel; import jalview.gui.AppVarna; import jalview.gui.ChimeraViewFrame; import jalview.gui.Desktop; -import jalview.gui.FeatureRenderer; import jalview.gui.JvOptionPane; import jalview.gui.OOMWarning; import jalview.gui.PCAPanel; @@ -86,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; @@ -94,6 +145,7 @@ import jalview.util.matcher.Condition; import jalview.viewmodel.AlignmentViewport; import jalview.viewmodel.PCAModel; import jalview.viewmodel.ViewportRanges; +import jalview.viewmodel.seqfeatures.FeatureRendererModel; import jalview.viewmodel.seqfeatures.FeatureRendererSettings; import jalview.viewmodel.seqfeatures.FeaturesDisplayed; import jalview.ws.jws2.Jws2Discoverer; @@ -150,54 +202,6 @@ import jalview.xml.binding.jalview.SequenceSet.SequenceSetProperties; import jalview.xml.binding.jalview.ThresholdType; import jalview.xml.binding.jalview.VAMSAS; -import java.awt.Color; -import java.awt.Font; -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.math.BigInteger; -import java.net.MalformedURLException; -import java.net.URL; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Collections; -import java.util.Enumeration; -import java.util.GregorianCalendar; -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.Vector; -import java.util.jar.JarEntry; -import java.util.jar.JarInputStream; -import java.util.jar.JarOutputStream; - -import javax.swing.JInternalFrame; -import javax.swing.SwingUtilities; -import javax.xml.bind.JAXBContext; -import javax.xml.bind.JAXBElement; -import javax.xml.bind.Marshaller; -import javax.xml.datatype.DatatypeConfigurationException; -import javax.xml.datatype.DatatypeFactory; -import javax.xml.datatype.XMLGregorianCalendar; -import javax.xml.stream.XMLInputFactory; -import javax.xml.stream.XMLStreamReader; - /** * Write out the current jalview desktop state as a Jalview XML stream. * @@ -210,6 +214,15 @@ import javax.xml.stream.XMLStreamReader; */ 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_"; @@ -453,7 +466,7 @@ public class Jalview2XML public boolean isResolvable() { return super.isResolvable() && mp.getTo() != null; - }; + } @Override boolean resolve() @@ -685,7 +698,6 @@ public class Jalview2XML } catch (Exception foo) { } - ; jout.close(); } catch (Exception ex) { @@ -747,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<>(); @@ -770,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) @@ -946,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); @@ -1077,25 +1092,28 @@ 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); - try + File viewerState = viewFrame.saveSession(); + if (viewerState != null) { - String viewerState = viewFrame.getStateInfo(); - writeJarEntry(jout, getViewerJarEntryName(viewId), - viewerState.getBytes()); - } catch (IOException e) + copyFileToJar(jout, viewerState.getPath(), + getViewerJarEntryName(viewId), viewerType); + } + else { - System.err.println( - "Error saving viewer state: " + e.getMessage()); + Cache.log.error("Failed to save viewer state for " + + + viewerType); } } } @@ -1117,7 +1135,7 @@ public class Jalview2XML if (!pdbfiles.contains(pdbId)) { pdbfiles.add(pdbId); - copyFileToJar(jout, matchedFile, pdbId); + copyFileToJar(jout, matchedFile, pdbId, pdbId); } } @@ -1387,7 +1405,7 @@ public class Jalview2XML } } - //jms.setJGroup(groups); + // jms.setJGroup(groups); Object group; for (JGroup grp : groups) { @@ -1501,11 +1519,14 @@ public class Jalview2XML view.setFollowHighlight(av.isFollowHighlight()); view.setFollowSelection(av.followSelection); view.setIgnoreGapsinConsensus(av.isIgnoreGapsConsensus()); + view.setShowComplementFeatures(av.isShowComplementFeatures()); + view.setShowComplementFeaturesOnTop( + av.isShowComplementFeaturesOnTop()); if (av.getFeaturesDisplayed() != null) { FeatureSettings fs = new FeatureSettings(); - FeatureRenderer fr = ap.getSeqPanel().seqCanvas + FeatureRendererModel fr = ap.getSeqPanel().seqCanvas .getFeatureRenderer(); String[] renderOrder = fr.getRenderOrder().toArray(new String[0]); @@ -1661,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); @@ -1961,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(); @@ -1985,58 +2007,48 @@ 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) { - DataInputStream dis = null; - try + try (InputStream is = new FileInputStream(infilePath)) { 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); + System.out.println( + "Writing jar entry " + jarEntryName + " (" + msg + ")"); + jout.putNextEntry(new JarEntry(jarEntryName)); + copyAll(is, jout); + jout.closeEntry(); + // 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 + * Copies input to output, in 4K buffers; handles any data (text or binary) * - * @param jout - * @param jarEntryName - * @param data + * @param in + * @param out * @throws IOException */ - protected void writeJarEntry(JarOutputStream jout, String jarEntryName, - byte[] data) throws IOException + protected void copyAll(InputStream in, OutputStream out) + throws IOException { - if (jout != null) + byte[] buffer = new byte[4096]; + int bytesRead = 0; + while ((bytesRead = in.read(buffer)) != -1) { - 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(); + out.write(buffer, 0, bytesRead); } } @@ -2053,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) { @@ -2107,7 +2119,7 @@ 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()); state.setType(viewFrame.getViewerType().toString()); // pdb.addStructureState(state); @@ -2491,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())); @@ -2513,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); } @@ -2721,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; @@ -2755,7 +2767,7 @@ public class Jalview2XML public void run() { setLoadingFinishedForNewStructureViewers(); - }; + } }); } catch (Exception x) { @@ -2765,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 { + + // 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 (file.startsWith("http://")) + if (HttpUtils.startsWithHttpOrHttps(file)) { url = new URL(file); } @@ -2783,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 @@ -2844,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() @@ -2856,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); @@ -3168,8 +3182,6 @@ public class Jalview2XML protected String copyJarEntry(jarInputStreamProvider jprovider, String jarEntryName, String prefix, String suffixModel) { - BufferedReader in = null; - PrintWriter out = null; String suffix = ".tmp"; if (suffixModel == null) { @@ -3180,33 +3192,24 @@ public class Jalview2XML { suffix = "." + suffixModel.substring(sfpos + 1); } - try - { - JarInputStream jin = jprovider.getJarInputStream(); - /* - * if (jprovider.startsWith("http://")) { jin = new JarInputStream(new - * URL(jprovider).openStream()); } else { jin = new JarInputStream(new - * FileInputStream(jprovider)); } - */ + try (JarInputStream jin = jprovider.getJarInputStream()) + { JarEntry entry = null; do { entry = jin.getNextJarEntry(); } while (entry != null && !entry.getName().equals(jarEntryName)); + if (entry != null) { - in = new BufferedReader(new InputStreamReader(jin, UTF_8)); + // in = new BufferedReader(new InputStreamReader(jin, UTF_8)); File outFile = File.createTempFile(prefix, suffix); outFile.deleteOnExit(); - out = new PrintWriter(new FileOutputStream(outFile)); - String data; - - while ((data = in.readLine()) != null) + try (OutputStream os = new FileOutputStream(outFile)) { - out.println(data); + copyAll(jin, os); } - out.flush(); String t = outFile.getAbsolutePath(); return t; } @@ -3217,22 +3220,6 @@ public class Jalview2XML } catch (Exception ex) { ex.printStackTrace(); - } finally - { - if (in != null) - { - try - { - in.close(); - } catch (IOException e) - { - // ignore - } - } - if (out != null) - { - out.close(); - } } return null; @@ -3333,8 +3320,10 @@ public class Jalview2XML || tmpSeq.getEnd() != jseq.getEnd()) { System.err.println( - "Warning JAL-2154 regression: updating start/end for sequence " - + tmpSeq.toString() + " to " + jseq); + String.format("Warning JAL-2154 regression: updating start/end for sequence %s from %d/%d to %d/%d", + tmpSeq.getName(), tmpSeq.getStart(), + tmpSeq.getEnd(), jseq.getStart(), + jseq.getEnd())); } } else @@ -4301,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 @@ -4405,246 +4399,17 @@ public class Jalview2XML 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", ".py"); - - 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())); - } - - 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()); + String type = stateData.getType(); 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) + ViewerType viewerType = ViewerType.valueOf(type); + createStructureViewer(viewerType, viewerData, af, jprovider); + } catch (IllegalArgumentException | NullPointerException e) { - // e.printStackTrace(); + // TODO JAL-3619 show error dialog / offer an alternative viewer + Cache.log.error( + "Invalid structure viewer type: " + type); } - } /** @@ -4849,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); @@ -5019,11 +4795,14 @@ public class Jalview2XML viewport.setShowNPFeats(safeBoolean(view.isShowNPfeatureTooltip())); viewport.setShowGroupConsensus(view.isShowGroupConsensus()); viewport.setShowGroupConservation(view.isShowGroupConservation()); + viewport.setShowComplementFeatures(view.isShowComplementFeatures()); + viewport.setShowComplementFeaturesOnTop( + view.isShowComplementFeaturesOnTop()); // recover feature settings if (jm.getFeatureSettings() != null) { - FeatureRenderer fr = af.alignPanel.getSeqPanel().seqCanvas + FeatureRendererModel fr = af.alignPanel.getSeqPanel().seqCanvas .getFeatureRenderer(); FeaturesDisplayed fdi; viewport.setFeaturesDisplayed(fdi = new FeaturesDisplayed()); @@ -5487,7 +5266,7 @@ public class Jalview2XML addDatasetRef(vamsasSet.getDatasetId(), ds); } } - Vector dseqs = null; + Vector dseqs = null; if (!ignoreUnrefed) { // recovering an alignment View @@ -5515,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++) { @@ -5603,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 @@ -6327,6 +6107,177 @@ public class Jalview2XML } /** + * Creates a new structure viewer window + * + * @param viewerType + * @param viewerData + * @param af + * @param jprovider + */ + 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) + { + String state = svattrib.getStateData(); // Jalview < 2.9 + if (state == null || state.isEmpty()) // Jalview >= 2.9 + { + String jarEntryName = getViewerJarEntryName(svattrib.getViewId()); + state = readJarEntry(jprovider, jarEntryName); + } + // 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; + } + + /** * Populates an XML model of the feature colour scheme for one feature type * * @param featureType