X-Git-Url: http://source.jalview.org/gitweb/?a=blobdiff_plain;f=src%2Fjalview%2Fproject%2FJalview2XML.java;h=b6295d9fde930ac4880ad23690d86f826f276ab1;hb=0fef78440888c7cf6980fe1349661512e3f1b62d;hp=11404dcc727d6d022e180283d9453adb87368e8b;hpb=16d109024847af92482237e43f99b82fd997451a;p=jalview.git diff --git a/src/jalview/project/Jalview2XML.java b/src/jalview/project/Jalview2XML.java index 11404dc..b6295d9 100644 --- a/src/jalview/project/Jalview2XML.java +++ b/src/jalview/project/Jalview2XML.java @@ -24,6 +24,55 @@ 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.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; @@ -38,6 +87,8 @@ import jalview.datamodel.AlignedCodonFrame; import jalview.datamodel.Alignment; import jalview.datamodel.AlignmentAnnotation; import jalview.datamodel.AlignmentI; +import jalview.datamodel.DBRefEntry; +import jalview.datamodel.GeneLocus; import jalview.datamodel.GraphLine; import jalview.datamodel.PDBEntry; import jalview.datamodel.Point; @@ -51,18 +102,21 @@ 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.FeatureRenderer; +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; @@ -92,6 +146,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; @@ -148,54 +203,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. * @@ -1085,15 +1092,17 @@ public class Jalview2XML 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)); + } + else { - System.err.println( - "Error saving viewer state: " + e.getMessage()); + Cache.log.error("Failed to save viewer state for " + + + viewFrame.getViewerType().toString()); } } } @@ -1499,11 +1508,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]); @@ -1987,32 +1999,23 @@ public class Jalview2XML protected void copyFileToJar(JarOutputStream jout, String infilePath, String jarEntryName) { - 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); + 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 - } - } } } @@ -2039,6 +2042,24 @@ public class Jalview2XML } /** + * Copies input to output, in 4K buffers; handles any data (text or binary) + * + * @param in + * @param out + * @throws IOException + */ + protected void copyAll(InputStream in, OutputStream out) + throws IOException + { + byte[] buffer = new byte[4096]; + int bytesRead = 0; + while ((bytesRead = in.read(buffer)) != -1) + { + out.write(buffer, 0, bytesRead); + } + } + + /** * Save the state of a structure viewer * * @param ap @@ -2105,7 +2126,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); @@ -2505,21 +2526,29 @@ public class Jalview2XML parentseq = jds; } } + + /* + * save any dbrefs; special subclass GeneLocus is flagged as 'locus' + */ if (dbrefs != null) { for (int d = 0; d < dbrefs.length; d++) { DBRef dbref = new DBRef(); - dbref.setSource(dbrefs[d].getSource()); - dbref.setVersion(dbrefs[d].getVersion()); - dbref.setAccessionId(dbrefs[d].getAccessionId()); - if (dbrefs[d].hasMap()) + DBRefEntry dbRefEntry = dbrefs[d]; + dbref.setSource(dbRefEntry.getSource()); + dbref.setVersion(dbRefEntry.getVersion()); + dbref.setAccessionId(dbRefEntry.getAccessionId()); + if (dbRefEntry instanceof GeneLocus) { - Mapping mp = createVamsasMapping(dbrefs[d].getMap(), parentseq, + dbref.setLocus(true); + } + if (dbRefEntry.hasMap()) + { + Mapping mp = createVamsasMapping(dbRefEntry.getMap(), parentseq, jds, recurse); dbref.setMapping(mp); } - // vamsasSeq.addDBRef(dbref); vamsasSeq.getDBRef().add(dbref); } } @@ -3150,53 +3179,42 @@ public class Jalview2XML * @param prefix * a prefix for the temporary file name, must be at least three * characters long - * @param origFile + * @param suffixModel * null or original file - so new file can be given the same suffix * as the old one * @return */ protected String copyJarEntry(jarInputStreamProvider jprovider, - String jarEntryName, String prefix, String origFile) + String jarEntryName, String prefix, String suffixModel) { - BufferedReader in = null; - PrintWriter out = null; String suffix = ".tmp"; - if (origFile == null) + if (suffixModel == null) { - origFile = jarEntryName; + suffixModel = jarEntryName; } - int sfpos = origFile.lastIndexOf("."); - if (sfpos > -1 && sfpos < (origFile.length() - 3)) + int sfpos = suffixModel.lastIndexOf("."); + if (sfpos > -1 && sfpos < (suffixModel.length() - 1)) { - suffix = "." + origFile.substring(sfpos + 1); + 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; } @@ -3207,22 +3225,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; @@ -3323,8 +3325,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 @@ -4187,10 +4191,8 @@ public class Jalview2XML // TODO: verify 'associate with all views' works still tp.getTreeCanvas().setViewport(av); // af.viewport; tp.getTreeCanvas().setAssociatedPanel(ap); // af.alignPanel; - // FIXME: should we use safeBoolean here ? - tp.getTreeCanvas().setApplyToAllViews(tree.isLinkToAllViews()); - } + tp.getTreeCanvas().setApplyToAllViews(tree.isLinkToAllViews()); if (tp == null) { warn("There was a problem recovering stored Newick tree: \n" @@ -4401,29 +4403,41 @@ public class Jalview2XML * From 2.9: stateData.type contains JMOL or CHIMERA, data is in jar entry * "viewer_"+stateData.viewId */ - if (ViewerType.CHIMERA.toString().equals(stateData.getType())) + ViewerType viewerType = ViewerType.valueOf(stateData.getType()); + try { - createChimeraViewer(viewerData, af, jprovider); - } - else + 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); + } + } catch (IllegalArgumentException | NullPointerException e) { - /* - * else Jmol (if pre-2.9, stateData contains JMOL state string) - */ - createJmolViewer(viewerData, af, jprovider); + Cache.log.error( + "Invalid structure viewer type: " + stateData.getType()); } } /** - * Create a new Chimera viewer. + * Create a new Chimera or ChimeraX viewer * * @param data * @param af * @param jprovider + * @param isChimeraX */ protected void createChimeraViewer( Entry viewerData, AlignFrame af, - jarInputStreamProvider jprovider) + jarInputStreamProvider jprovider, boolean isChimeraX) { StructureViewerModel data = viewerData.getValue(); String chimeraSessionFile = data.getStateData(); @@ -4435,8 +4449,11 @@ public class Jalview2XML * '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", null); + "chimera", extension); Set> fileData = data.getFileData() .entrySet(); @@ -4462,9 +4479,13 @@ public class Jalview2XML .toArray(new SequenceI[allseqs.size()][]); String newViewId = viewerData.getKey(); - ChimeraViewFrame cvf = new ChimeraViewFrame(chimeraSessionFile, - af.alignPanel, pdbArray, seqsArray, colourByChimera, - colourBySequence, newViewId); + 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()); } @@ -4522,7 +4543,7 @@ public class Jalview2XML String reformatedOldFilename = oldfilenam.replaceAll("/", "\\\\"); filedat = oldFiles.get(new File(reformatedOldFilename)); } - newFileLoc.append(Platform.escapeString(filedat.getFilePath())); + newFileLoc.append(Platform.escapeBackslashes(filedat.getFilePath())); pdbfilenames.add(filedat.getFilePath()); pdbids.add(filedat.getPdbId()); seqmaps.add(filedat.getSeqList().toArray(new SequenceI[0])); @@ -4978,21 +4999,22 @@ public class Jalview2XML } } + /* + * turn off 'alignment colour applies to all groups' + * while restoring global colour scheme + */ + viewport.setColourAppliesToAllGroups(false); viewport.setGlobalColourScheme(cs); viewport.getResidueShading().setThreshold(pidThreshold, view.isIgnoreGapsinConsensus()); viewport.getResidueShading() .setConsensus(viewport.getSequenceConsensusHash()); - viewport.setColourAppliesToAllGroups(false); - if (safeBoolean(view.isConservationSelected()) && cs != null) { viewport.getResidueShading() .setConservationInc(safeInt(view.getConsThreshold())); } - af.changeColour(cs); - viewport.setColourAppliesToAllGroups(true); viewport @@ -5010,11 +5032,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()); @@ -5114,7 +5139,7 @@ public class Jalview2XML } else { - featureOrder.put(featureType, new Float( + featureOrder.put(featureType, Float.valueOf( fs / jm.getFeatureSettings().getSetting().size())); } if (safeBoolean(setting.isDisplay())) @@ -5126,7 +5151,7 @@ public class Jalview2XML for (int gs = 0; gs < jm.getFeatureSettings().getGroup().size(); gs++) { Group grp = jm.getFeatureSettings().getGroup().get(gs); - fgtable.put(grp.getName(), new Boolean(grp.isDisplay())); + fgtable.put(grp.getName(), Boolean.valueOf(grp.isDisplay())); } // FeatureRendererSettings frs = new FeatureRendererSettings(renderOrder, // fgtable, featureColours, jms.getFeatureSettings().hasTransparency() ? @@ -5799,13 +5824,29 @@ public class Jalview2XML return datasetId; } + /** + * Add any saved DBRefEntry's to the sequence. An entry flagged as 'locus' is + * constructed as a special subclass GeneLocus. + * + * @param datasetSequence + * @param sequence + */ private void addDBRefs(SequenceI datasetSequence, Sequence sequence) { for (int d = 0; d < sequence.getDBRef().size(); d++) { DBRef dr = sequence.getDBRef().get(d); - jalview.datamodel.DBRefEntry entry = new jalview.datamodel.DBRefEntry( - dr.getSource(), dr.getVersion(), dr.getAccessionId()); + DBRefEntry entry; + if (dr.isLocus()) + { + entry = new GeneLocus(dr.getSource(), dr.getVersion(), + dr.getAccessionId()); + } + else + { + entry = new DBRefEntry(dr.getSource(), dr.getVersion(), + dr.getAccessionId()); + } if (dr.getMapping() != null) { entry.setMap(addMapping(dr.getMapping())); @@ -6302,6 +6343,61 @@ public class Jalview2XML } /** + * Create a new PyMol viewer + * + * @param data + * @param af + * @param jprovider + */ + protected void createPymolViewer( + Entry viewerData, AlignFrame af, + 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); + } + + 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()); + } + + /** * Populates an XML model of the feature colour scheme for one feature type * * @param featureType