X-Git-Url: http://source.jalview.org/gitweb/?a=blobdiff_plain;f=src%2Fjalview%2Fproject%2FJalview2XML.java;h=6f26036517455f2762710b69aebc28cd9335c8e3;hb=4882f6845b3a82307f68ccc376d36a2f4c884720;hp=8877af2941b735e5bcccfa938e3cf7a6c0967b8c;hpb=cb8e52fbbc5f725e3f7f48c672cdddb0690bd978;p=jalview.git diff --git a/src/jalview/project/Jalview2XML.java b/src/jalview/project/Jalview2XML.java index 8877af2..6f26036 100644 --- a/src/jalview/project/Jalview2XML.java +++ b/src/jalview/project/Jalview2XML.java @@ -26,6 +26,7 @@ import static jalview.math.RotatableMatrix.Axis.Z; import java.awt.Color; import java.awt.Font; +import java.awt.FontMetrics; import java.awt.Rectangle; import java.io.BufferedReader; import java.io.ByteArrayInputStream; @@ -44,6 +45,7 @@ import java.net.MalformedURLException; import java.net.URL; import java.util.ArrayList; import java.util.Arrays; +import java.util.BitSet; import java.util.Collections; import java.util.Enumeration; import java.util.GregorianCalendar; @@ -89,9 +91,12 @@ import jalview.datamodel.AlignedCodonFrame; import jalview.datamodel.Alignment; import jalview.datamodel.AlignmentAnnotation; import jalview.datamodel.AlignmentI; +import jalview.datamodel.ContactMatrix; +import jalview.datamodel.ContactMatrixI; import jalview.datamodel.DBRefEntry; import jalview.datamodel.GeneLocus; import jalview.datamodel.GraphLine; +import jalview.datamodel.GroupSet; import jalview.datamodel.PDBEntry; import jalview.datamodel.Point; import jalview.datamodel.RnaViewerModel; @@ -112,6 +117,7 @@ import jalview.gui.AppVarna; import jalview.gui.Desktop; import jalview.gui.JvOptionPane; import jalview.gui.OOMWarning; +import jalview.gui.OverviewPanel; import jalview.gui.PCAPanel; import jalview.gui.PaintRefresher; import jalview.gui.SplitFrame; @@ -147,6 +153,8 @@ import jalview.viewmodel.ViewportRanges; import jalview.viewmodel.seqfeatures.FeatureRendererModel; import jalview.viewmodel.seqfeatures.FeatureRendererSettings; import jalview.viewmodel.seqfeatures.FeaturesDisplayed; +import jalview.ws.datamodel.MappableContactMatrixI; +import jalview.ws.datamodel.alphafold.PAEContactMatrix; import jalview.ws.jws2.Jws2Discoverer; import jalview.ws.jws2.dm.AAConSettings; import jalview.ws.jws2.jabaws2.Jws2Instance; @@ -185,11 +193,14 @@ import jalview.xml.binding.jalview.JalviewModel.UserColours; import jalview.xml.binding.jalview.JalviewModel.Viewport; import jalview.xml.binding.jalview.JalviewModel.Viewport.CalcIdParam; import jalview.xml.binding.jalview.JalviewModel.Viewport.HiddenColumns; +import jalview.xml.binding.jalview.JalviewModel.Viewport.Overview; import jalview.xml.binding.jalview.JalviewUserColours; import jalview.xml.binding.jalview.JalviewUserColours.Colour; +import jalview.xml.binding.jalview.MapListType; import jalview.xml.binding.jalview.MapListType.MapListFrom; import jalview.xml.binding.jalview.MapListType.MapListTo; import jalview.xml.binding.jalview.Mapping; +import jalview.xml.binding.jalview.MatrixType; import jalview.xml.binding.jalview.NoValueColour; import jalview.xml.binding.jalview.ObjectFactory; import jalview.xml.binding.jalview.PcaDataType; @@ -229,6 +240,11 @@ public class Jalview2XML private static final String UTF_8 = "UTF-8"; /** + * used in decision if quit confirmation should be issued + */ + private static boolean stateSavedUpToDate = false; + + /** * prefix for recovering datasets for alignments with multiple views where * non-existent dataset IDs were written for some views */ @@ -616,6 +632,27 @@ public class Jalview2XML { AlignFrame[] frames = Desktop.getAlignFrames(); + setStateSavedUpToDate(true); + + if (Cache.getDefault("DEBUG_DELAY_SAVE", false)) + { + int n = debugDelaySave; + int i = 0; + while (i < n) + { + Console.debug("***** debugging save sleep " + i + "/" + n); + try + { + Thread.sleep(1000); + } catch (InterruptedException e) + { + // TODO Auto-generated catch block + e.printStackTrace(); + } + i++; + } + } + if (frames == null) { return; @@ -763,6 +800,25 @@ public class Jalview2XML FileOutputStream fos = new FileOutputStream( doBackup ? backupfiles.getTempFilePath() : jarFile); + if (Cache.getDefault("DEBUG_DELAY_SAVE", false)) + { + int n = debugDelaySave; + int i = 0; + while (i < n) + { + Console.debug("***** debugging save sleep " + i + "/" + n); + try + { + Thread.sleep(1000); + } catch (InterruptedException e) + { + // TODO Auto-generated catch block + e.printStackTrace(); + } + i++; + } + } + JarOutputStream jout = new JarOutputStream(fos); List frames = new ArrayList<>(); @@ -882,8 +938,7 @@ public class Jalview2XML { System.err.println("error writing date: " + e.toString()); } - object.setVersion( - Cache.getDefault("VERSION", "Development Build")); + object.setVersion(Cache.getDefault("VERSION", "Development Build")); /** * rjal is full height alignment, jal is actual alignment with full metadata @@ -1273,6 +1328,13 @@ public class Jalview2XML tree.setLinkToAllViews( tp.getTreeCanvas().isApplyToAllViews()); + // columnWiseTree + if (tp.isColumnWise()) + { + tree.setColumnWise(true); + String annId = tp.getAssocAnnotation().annotationId; + tree.setColumnReference(annId); + } // jms.addTree(tree); object.getTree().add(tree); } @@ -1448,6 +1510,23 @@ public class Jalview2XML view.setStartRes(vpRanges.getStartRes()); view.setStartSeq(vpRanges.getStartSeq()); + OverviewPanel ov = ap.getOverviewPanel(); + if (ov != null) + { + Overview overview = new Overview(); + overview.setTitle(ov.getTitle()); + Rectangle bounds = ov.getFrameBounds(); + overview.setXpos(bounds.x); + overview.setYpos(bounds.y); + overview.setWidth(bounds.width); + overview.setHeight(bounds.height); + overview.setShowHidden(ov.isShowHiddenRegions()); + overview.setGapColour(ov.getCanvas().getGapColour().getRGB()); + overview.setResidueColour( + ov.getCanvas().getResidueColour().getRGB()); + overview.setHiddenColour(ov.getCanvas().getHiddenColour().getRGB()); + view.setOverview(overview); + } if (av.getGlobalColourScheme() instanceof jalview.schemes.UserColourScheme) { view.setBgColour(setUserColourScheme(av.getGlobalColourScheme(), @@ -1488,6 +1567,8 @@ public class Jalview2XML view.setConservationSelected(av.getConservationSelected()); view.setPidSelected(av.getAbovePIDThreshold()); + view.setCharHeight(av.getCharHeight()); + view.setCharWidth(av.getCharWidth()); final Font font = av.getFont(); view.setFontName(font.getName()); view.setFontSize(font.getSize()); @@ -1633,7 +1714,8 @@ public class Jalview2XML .getHiddenColumns(); if (hidden == null) { - Console.warn("REPORT BUG: avoided null columnselection bug (DMAM reported). Please contact Jim about this."); + Console.warn( + "REPORT BUG: avoided null columnselection bug (DMAM reported). Please contact Jim about this."); } else { @@ -2225,6 +2307,75 @@ public class Jalview2XML line.setColour(annotation.getThreshold().colour.getRGB()); an.setThresholdLine(line); } + if (annotation.graph == AlignmentAnnotation.CONTACT_MAP) + { + if (annotation.sequenceRef.getContactMaps() != null) + { + ContactMatrixI cm = annotation.sequenceRef + .getContactMatrixFor(annotation); + if (cm != null) + { + MatrixType xmlmat = new MatrixType(); + xmlmat.setType(cm.getType()); + xmlmat.setRows(BigInteger.valueOf(cm.getWidth())); + xmlmat.setCols(BigInteger.valueOf(cm.getHeight())); + // consider using an opaque to/from -> allow instance to control + // its representation ? + xmlmat.setElements(ContactMatrix.contactToFloatString(cm)); + if (cm.hasGroups()) + { + for (BitSet gp : cm.getGroups()) + { + xmlmat.getGroups().add(stringifyBitset(gp)); + } + } + if (cm.hasTree()) + { + // provenance object for tree ? + xmlmat.getNewick().add(cm.getNewick()); + xmlmat.setTreeMethod(cm.getTreeMethod()); + } + if (cm.hasCutHeight()) + { + xmlmat.setCutHeight(cm.getCutHeight()); + } + // set/get properties + if (cm instanceof MappableContactMatrixI) + { + jalview.util.MapList mlst = ((MappableContactMatrixI) cm) + .getMapFor(annotation.sequenceRef); + if (mlst != null) + { + MapListType mp = new MapListType(); + List r = mlst.getFromRanges(); + for (int[] range : r) + { + MapListFrom mfrom = new MapListFrom(); + mfrom.setStart(range[0]); + mfrom.setEnd(range[1]); + // mp.addMapListFrom(mfrom); + mp.getMapListFrom().add(mfrom); + } + r = mlst.getToRanges(); + for (int[] range : r) + { + MapListTo mto = new MapListTo(); + mto.setStart(range[0]); + mto.setEnd(range[1]); + // mp.addMapListTo(mto); + mp.getMapListTo().add(mto); + } + mp.setMapFromUnit( + BigInteger.valueOf(mlst.getFromRatio())); + mp.setMapToUnit(BigInteger.valueOf(mlst.getToRatio())); + xmlmat.setMapping(mp); + } + } + // and add to model + an.getContactmatrix().add(xmlmat); + } + } + } } else { @@ -2255,10 +2406,9 @@ public class Jalview2XML { for (String pr : annotation.getProperties()) { - jalview.xml.binding.jalview.Annotation.Property prop = new jalview.xml.binding.jalview.Annotation.Property(); + jalview.xml.binding.jalview.Property prop = new jalview.xml.binding.jalview.Property(); prop.setName(pr); prop.setValue(annotation.getProperty(pr)); - // an.addProperty(prop); an.getProperty().add(prop); } } @@ -2329,6 +2479,43 @@ public class Jalview2XML } + private String stringifyBitset(BitSet gp) + { + StringBuilder sb = new StringBuilder(); + for (long val : gp.toLongArray()) + { + if (sb.length() > 0) + { + sb.append(","); + } + sb.append(val); + } + return sb.toString(); + } + + private BitSet deStringifyBitset(String stringified) + { + if ("".equals(stringified) || stringified == null) + { + return new BitSet(); + } + String[] longvals = stringified.split(","); + long[] newlongvals = new long[longvals.length]; + for (int lv = 0; lv < longvals.length; lv++) + { + try + { + newlongvals[lv] = Long.valueOf(longvals[lv]); + } catch (Exception x) + { + errorMessage += "Couldn't destringify bitset from: '" + stringified + + "'"; + newlongvals[lv] = 0; + } + } + return BitSet.valueOf(newlongvals); + + } private CalcIdParam createCalcIdParam(String calcId, AlignViewport av) { AutoCalcSetting settings = av.getCalcIdSettingsFor(calcId); @@ -2418,7 +2605,8 @@ public class Jalview2XML } else { - Console.warn("Cannot resolve a service for the parameters used in this project. Try configuring a JABAWS server."); + Console.warn( + "Cannot resolve a service for the parameters used in this project. Try configuring a JABAWS server."); return false; } } @@ -2462,7 +2650,8 @@ public class Jalview2XML return id.toString(); } // give up and warn that something has gone wrong - Console.warn("Cannot find ID for object in external mapping : " + jvobj); + Console.warn( + "Cannot find ID for object in external mapping : " + jvobj); } return altCode; } @@ -3230,7 +3419,8 @@ public class Jalview2XML } else { - Console.warn("Couldn't find entry in Jalview Jar for " + jarEntryName); + Console.warn( + "Couldn't find entry in Jalview Jar for " + jarEntryName); } } catch (Exception ex) { @@ -3830,11 +4020,94 @@ public class Jalview2XML jaa.setCalcId(annotation.getCalcId()); if (annotation.getProperty().size() > 0) { - for (Annotation.Property prop : annotation.getProperty()) + for (jalview.xml.binding.jalview.Property prop : annotation + .getProperty()) { jaa.setProperty(prop.getName(), prop.getValue()); } } + if (jaa.graph == AlignmentAnnotation.CONTACT_MAP) + { + if (annotation.getContactmatrix() != null + && annotation.getContactmatrix().size() > 0) + { + for (MatrixType xmlmat : annotation.getContactmatrix()) + { + if (PAEContactMatrix.PAEMATRIX.equals(xmlmat.getType())) + { + if (!xmlmat.getRows().equals(xmlmat.getCols())) + { + Console.error("Can't handle non square PAE Matrices"); + } + else + { + float[][] elements = ContactMatrix + .fromFloatStringToContacts(xmlmat.getElements(), + xmlmat.getCols().intValue(), + xmlmat.getRows().intValue()); + jalview.util.MapList mapping = null; + if (xmlmat.getMapping() != null) + { + MapListType m = xmlmat.getMapping(); + // Mapping m = dr.getMapping(); + int fr[] = new int[m.getMapListFrom().size() * 2]; + Iterator from = m.getMapListFrom() + .iterator();// enumerateMapListFrom(); + for (int _i = 0; from.hasNext(); _i += 2) + { + MapListFrom mf = from.next(); + fr[_i] = mf.getStart(); + fr[_i + 1] = mf.getEnd(); + } + int fto[] = new int[m.getMapListTo().size() * 2]; + Iterator to = m.getMapListTo().iterator();// enumerateMapListTo(); + for (int _i = 0; to.hasNext(); _i += 2) + { + MapListTo mf = to.next(); + fto[_i] = mf.getStart(); + fto[_i + 1] = mf.getEnd(); + } + + mapping = new jalview.util.MapList(fr, fto, + m.getMapFromUnit().intValue(), + m.getMapToUnit().intValue()); + } + List newgroups = new ArrayList(); + if (xmlmat.getGroups().size() > 0) + { + for (String sgroup : xmlmat.getGroups()) + { + newgroups.add(deStringifyBitset(sgroup)); + } + } + String nwk = xmlmat.getNewick().size() > 0 + ? xmlmat.getNewick().get(0) + : null; + if (xmlmat.getNewick().size() > 1) + { + Console.log.info( + "Ignoring additional clusterings for contact matrix"); + } + String treeMethod = xmlmat.getTreeMethod(); + double thresh = xmlmat.getCutHeight() != null + ? xmlmat.getCutHeight() + : 0; + GroupSet grpset = new GroupSet(); + grpset.restoreGroups(newgroups, treeMethod, nwk, thresh); + PAEContactMatrix newpae = new PAEContactMatrix( + jaa.sequenceRef, mapping, elements, grpset); + jaa.sequenceRef.addContactListFor(jaa, newpae); + } + } + else + { + Console.error("Ignoring CONTACT_MAP annotation with type " + + xmlmat.getType()); + } + } + } + } + if (jaa.autoCalculated) { autoAlan.add(new JvAnnotRow(i, jaa)); @@ -4045,7 +4318,7 @@ public class Jalview2XML } /* - * Load any trees, PDB structures and viewers + * Load any trees, PDB structures and viewers, Overview * * Not done if flag is false (when this method is used for New View) */ @@ -4055,12 +4328,49 @@ public class Jalview2XML loadPCAViewers(jalviewModel, ap); loadPDBStructures(jprovider, jseqs, af, ap); loadRnaViewers(jprovider, jseqs, ap); + loadOverview(view, jalviewModel.getVersion(), af); } // and finally return. return af; } /** + * Load Overview window, restoring colours, 'show hidden regions' flag, title + * and geometry as saved + * + * @param view + * @param af + */ + protected void loadOverview(Viewport view, String version, AlignFrame af) + { + if (!isVersionStringLaterThan("2.11.3", version) + && view.getOverview() == null) + { + return; + } + /* + * first close any Overview that was opened automatically + * (if so configured in Preferences) so that the view is + * restored in the same state as saved + */ + af.alignPanel.closeOverviewPanel(); + + Overview overview = view.getOverview(); + if (overview != null) + { + OverviewPanel overviewPanel = af + .openOverviewPanel(overview.isShowHidden()); + overviewPanel.setTitle(overview.getTitle()); + overviewPanel.setFrameBounds(overview.getXpos(), overview.getYpos(), + overview.getWidth(), overview.getHeight()); + Color gap = new Color(overview.getGapColour()); + Color residue = new Color(overview.getResidueColour()); + Color hidden = new Color(overview.getHiddenColour()); + overviewPanel.getCanvas().setColours(gap, residue, hidden); + } + } + + /** * Instantiate and link any saved RNA (Varna) viewers. The state of the Varna * panel is restored from separate jar entries, two (gapped and trimmed) per * sequence and secondary structure. @@ -4179,10 +4489,28 @@ public class Jalview2XML TreePanel tp = (TreePanel) retrieveExistingObj(tree.getId()); if (tp == null) { - tp = af.showNewickTree(new NewickFile(tree.getNewick()), - tree.getTitle(), safeInt(tree.getWidth()), - safeInt(tree.getHeight()), safeInt(tree.getXpos()), - safeInt(tree.getYpos())); + if (tree.isColumnWise()) + { + AlignmentAnnotation aa = (AlignmentAnnotation) annotationIds + .get(tree.getColumnReference()); + if (aa == null) + { + Console.warn( + "Null alignment annotation when restoring columnwise tree"); + } + tp = af.showColumnWiseTree(new NewickFile(tree.getNewick()), aa, + tree.getTitle(), safeInt(tree.getWidth()), + safeInt(tree.getHeight()), safeInt(tree.getXpos()), + safeInt(tree.getYpos())); + + } + else + { + tp = af.showNewickTree(new NewickFile(tree.getNewick()), + tree.getTitle(), safeInt(tree.getWidth()), + safeInt(tree.getHeight()), safeInt(tree.getXpos()), + safeInt(tree.getYpos())); + } if (tree.getId() != null) { // perhaps bind the tree id to something ? @@ -4205,8 +4533,9 @@ public class Jalview2XML tp.getTreeCanvas().setApplyToAllViews(tree.isLinkToAllViews()); if (tp == null) { - Console.warn("There was a problem recovering stored Newick tree: \n" - + tree.getNewick()); + Console.warn( + "There was a problem recovering stored Newick tree: \n" + + tree.getNewick()); continue; } @@ -4576,7 +4905,7 @@ public class Jalview2XML * - minimum version we are comparing against * @param version * - version of data being processsed - * @return + * @return true if version is equal to or later than supported */ public static boolean isVersionStringLaterThan(String supported, String version) @@ -4721,9 +5050,15 @@ public class Jalview2XML viewport.setIncrement(safeInt(view.getConsThreshold())); viewport.setShowJVSuffix(safeBoolean(view.isShowFullId())); viewport.setRightAlignIds(safeBoolean(view.isRightAlignIds())); - viewport.setFont(new Font(view.getFontName(), - safeInt(view.getFontStyle()), safeInt(view.getFontSize())), - true); + viewport.setFont( + new Font(view.getFontName(), safeInt(view.getFontStyle()), + safeInt(view.getFontSize())), + (view.getCharWidth() != null) ? false : true); + if (view.getCharWidth() != null) + { + viewport.setCharWidth(view.getCharWidth()); + viewport.setCharHeight(view.getCharHeight()); + } ViewStyleI vs = viewport.getViewStyle(); vs.setScaleProteinAsCdna(view.isScaleProteinAsCdna()); viewport.setViewStyle(vs); @@ -4982,6 +5317,7 @@ public class Jalview2XML { splitFrameCandidates.put(view, af); } + return af; } @@ -5045,7 +5381,10 @@ public class Jalview2XML + annotationId); return null; } - if (matchedAnnotation.getThreshold() == null) + // belt-and-braces create a threshold line if the + // colourscheme needs one but the matchedAnnotation doesn't have one + if (safeInt(viewAnnColour.getAboveThreshold()) != 0 + && matchedAnnotation.getThreshold() == null) { matchedAnnotation.setThreshold( new GraphLine(safeFloat(viewAnnColour.getThreshold()), @@ -5282,14 +5621,16 @@ public class Jalview2XML { if (ds != null && ds != seqSetDS) { - Console.warn("JAL-3171 regression: Overwriting a dataset reference for an alignment" - + " - CDS/Protein crossreference data may be lost"); + Console.warn( + "JAL-3171 regression: Overwriting a dataset reference for an alignment" + + " - CDS/Protein crossreference data may be lost"); if (xtant_ds != null) { // This can only happen if the unique sequence set ID was bound to a // dataset that did not contain any of the sequences in the view // currently being restored. - Console.warn("JAL-3171 SERIOUS! TOTAL CONFUSION - please consider contacting the Jalview Development team so they can investigate why your project caused this message to be displayed."); + Console.warn( + "JAL-3171 SERIOUS! TOTAL CONFUSION - please consider contacting the Jalview Development team so they can investigate why your project caused this message to be displayed."); } } ds = seqSetDS; @@ -5573,7 +5914,8 @@ public class Jalview2XML { if (dataset.getDataset() != null) { - Console.warn("Serious issue! Dataset Object passed to getDatasetIdRef is not a Jalview DATASET alignment..."); + Console.warn( + "Serious issue! Dataset Object passed to getDatasetIdRef is not a Jalview DATASET alignment..."); } String datasetId = makeHashCode(dataset, null); if (datasetId == null) @@ -5905,7 +6247,8 @@ public class Jalview2XML } else { - Console.warn("Couldn't find entry in Jalview Jar for " + jarEntryName); + Console.warn( + "Couldn't find entry in Jalview Jar for " + jarEntryName); } } catch (Exception ex) { @@ -6529,4 +6872,44 @@ public class Jalview2XML return colour; } + + public static void setStateSavedUpToDate(boolean s) + { + Console.debug("Setting overall stateSavedUpToDate to " + s); + stateSavedUpToDate = s; + } + + public static boolean stateSavedUpToDate() + { + Console.debug("Returning overall stateSavedUpToDate value: " + + stateSavedUpToDate); + return stateSavedUpToDate; + } + + public static boolean allSavedUpToDate() + { + if (stateSavedUpToDate()) // nothing happened since last project save + return true; + + AlignFrame[] frames = Desktop.getAlignFrames(); + if (frames != null) + { + for (int i = 0; i < frames.length; i++) + { + if (frames[i] == null) + continue; + if (!frames[i].getViewport().savedUpToDate()) + return false; // at least one alignment is not individually saved + } + } + return true; + } + + // used for debugging and tests + private static int debugDelaySave = 20; + + public static void setDebugDelaySave(int n) + { + debugDelaySave = n; + } }