From: Ben Soares Date: Fri, 30 Aug 2019 16:19:52 +0000 (+0100) Subject: JAL-3210 Improvements to eclipse detection. New src tree and SwingJS updated from... X-Git-Url: http://source.jalview.org/gitweb/?p=jalview.git;a=commitdiff_plain;h=a83adb45bdf9554e270921b4baad94defd314b36 JAL-3210 Improvements to eclipse detection. New src tree and SwingJS updated from the applet branch. AND IT WORKS (sometimes) --- diff --git a/README b/README index 33f0319..43ffa63 100644 --- a/README +++ b/README @@ -1,6 +1,6 @@ Download and install a clean eclipse-jee-2019-06 -In gradle.properties edit `jalviewjs_eclipse_root` to point to the root dir. Include up to the Eclipse.app folder if it's the macOS version. +In gradle.properties edit `jalviewjs_eclipse_root` to point to the root dir. DO NOT include the Eclipse.app folder in the path (up to this point, but not the .app folder) if it's the macOS version. gradle tasks of interest: diff --git a/build.gradle b/build.gradle index 351d9ac..7890fd0 100644 --- a/build.gradle +++ b/build.gradle @@ -233,19 +233,25 @@ def eclipseBinary def eclipseDropinsDir def eclipsePluginsDir task jalviewjsEclipsePaths { + def eclipseRoot = jalviewjs_eclipse_root + if (eclipseRoot.startsWith("~")) { + eclipseRoot = System.getProperty("user.home") + eclipseRoot.substring(1) + } if (OperatingSystem.current().isMacOsX()) { - eclipseDropinsDir = jalviewjs_eclipse_root+"/Contents/Eclipse/dropins" - eclipsePluginsDir = jalviewjs_eclipse_root+"/Contents/Eclipse/plugins" - eclipseBinary = jalviewjs_eclipse_root+"/Contents/MacOS/eclipse" - } else if (OperatingSystem.current().isWindows()) { // check this! - eclipseDropinsDir = jalviewjs_eclipse_root+"/dropins" - eclipsePluginsDir = jalviewjs_eclipse_root+"/plugins" - eclipseBinary = jalviewjs_eclipse_root+"/eclipse" + eclipseRoot += "/Eclipse.app" + eclipseDropinsDir = eclipseRoot+"/Contents/Eclipse/dropins" + eclipsePluginsDir = eclipseRoot+"/Contents/Eclipse/plugins" + eclipseBinary = eclipseRoot+"/Contents/MacOS/eclipse" + } else if (OperatingSystem.current().isWindows()) { // check these paths!! + eclipseDropinsDir = eclipseRoot+"/dropins" + eclipsePluginsDir = eclipseRoot+"/plugins" + eclipseBinary = eclipseRoot+"/eclipse" } else { // linux or unix - eclipseDropinsDir = jalviewjs_eclipse_root+"/dropins" - eclipsePluginsDir = jalviewjs_eclipse_root+"/plugins" - eclipseBinary = jalviewjs_eclipse_root+"/eclipse" + eclipseDropinsDir = eclipseRoot+"/dropins" + eclipsePluginsDir = eclipseRoot+"/plugins" + eclipseBinary = eclipseRoot+"/eclipse" } + println("ECLIPSE ROOT: "+eclipseRoot) } task jalviewjsEclipseCopyDropins (type: Copy) { @@ -353,8 +359,9 @@ task jalviewjsProjectImport(type: Exec) { executable(eclipseBinary) args(["-nosplash", "--launcher.suppressErrors", "-application", "com.seeq.eclipse.importprojects.headlessimport", "-data", tempEclipseWorkspace.getPath(), "-import", jalviewDirAbsolutePath]) - def tempdir = tempEclipseWorkspace.getPath()+"/.metadata/.plugins/org.eclipse.core.resources/.projects/jalview" - outputs.dir(tempdir) + def projdir = tempEclipseWorkspace.getPath()+"/.metadata/.plugins/org.eclipse.core.resources/.projects/jalview/org.eclipse.jdt.core/" + inputs.file(jalviewDir+"/.project") + outputs.dir(projdir) } task jalviewjsTranspile(type: Exec) { diff --git a/gradle.properties b/gradle.properties index 1fa2f14..e30dcb5 100644 --- a/gradle.properties +++ b/gradle.properties @@ -34,8 +34,7 @@ j11libDir = j11lib dev = false -#jalviewjs_eclipse_root = /Users/bsoares/buildtools/eclipse/eclipse-jee-2019-06/Eclipse.app -jalviewjs_eclipse_root = /home/bsoares/buildtools/eclipse/eclipse-jee-2019-06 +jalviewjs_eclipse_root = ~/buildtools/eclipse/eclipse-jee-2019-06 jalviewjs_utils_dir = utils/jalviewjs jalviewjs_eclipse_plugins_dir = eclipse/plugins diff --git a/src/com/stevesoft/pat/RegOpt.java b/src/com/stevesoft/pat/RegOpt.java index d5f62de..50d799f 100755 --- a/src/com/stevesoft/pat/RegOpt.java +++ b/src/com/stevesoft/pat/RegOpt.java @@ -138,16 +138,16 @@ class Branch extends Pattern n = RegOpt.opt(n, ignoreCase, dontMinQ); } n.setParent(this); - set(Character.valueOf(o.c), n, ignoreCase, dontMinQ); + set(new Character(o.c), n, ignoreCase, dontMinQ); if (ignoreCase) { if (o.c != o.altc) { - set(Character.valueOf(o.altc), n, ignoreCase, dontMinQ); + set(new Character(o.altc), n, ignoreCase, dontMinQ); } if (o.c != o.altc2 && o.altc != o.altc2) { - set(Character.valueOf(o.altc2), n, ignoreCase, dontMinQ); + set(new Character(o.altc2), n, ignoreCase, dontMinQ); } } } @@ -250,7 +250,7 @@ class Branch extends Pattern { return -1; } - Pattern n = (Pattern) h.get(Character.valueOf(pt.src.charAt(pos))); + Pattern n = (Pattern) h.get(new Character(pt.src.charAt(pos))); if (n == null) { return -1; diff --git a/src/com/stevesoft/pat/Regex.java b/src/com/stevesoft/pat/Regex.java index 6d07427..455f040 100755 --- a/src/com/stevesoft/pat/Regex.java +++ b/src/com/stevesoft/pat/Regex.java @@ -16,6 +16,7 @@ import java.util.Hashtable; import com.stevesoft.pat.wrap.StringWrap; + /** Matches a Unicode punctuation character. */ class UnicodePunct extends UniValidator { @@ -306,6 +307,7 @@ class UnicodeLower extends UniValidator */ public class Regex extends RegRes implements FilenameFilter { + /** * BackRefOffset gives the identity number of the first pattern. Version 1.0 * used zero, version 1.1 uses 1 to be more compatible with perl. @@ -1095,16 +1097,13 @@ public class Regex extends RegRes implements FilenameFilter { try { - return getClass().getDeclaredConstructor().newInstance(); + return getClass().newInstance(); } catch (InstantiationException ie) { return null; } catch (IllegalAccessException iae) { return null; - } catch (ReflectiveOperationException roe) - { - return null; } } diff --git a/src/com/stevesoft/pat/RegexReader.java b/src/com/stevesoft/pat/RegexReader.java index a0b42ce..837821e 100755 --- a/src/com/stevesoft/pat/RegexReader.java +++ b/src/com/stevesoft/pat/RegexReader.java @@ -233,7 +233,6 @@ public class RegexReader extends Reader * * @deprecated */ - @Deprecated public int getMaxLines() { return max_lines; @@ -244,7 +243,6 @@ public class RegexReader extends Reader * * @deprecated */ - @Deprecated public void setMaxLines(int ml) { max_lines = ml; @@ -257,7 +255,6 @@ public class RegexReader extends Reader * * @deprecated */ - @Deprecated public char getEOLchar() { return EOLchar; @@ -268,7 +265,6 @@ public class RegexReader extends Reader * * @deprecated */ - @Deprecated public void setEOLchar(char c) { EOLchar = c; diff --git a/src/com/stevesoft/pat/RegexTokenizer.java b/src/com/stevesoft/pat/RegexTokenizer.java index c99bfea..31fa2ba 100755 --- a/src/com/stevesoft/pat/RegexTokenizer.java +++ b/src/com/stevesoft/pat/RegexTokenizer.java @@ -43,13 +43,13 @@ public class RegexTokenizer implements Enumeration if (r.searchFrom(toParse, pos)) { v.addElement(r.left().substring(pos)); - vi.addElement(Integer.valueOf(r.matchFrom() + r.charsMatched())); + vi.addElement(new Integer(r.matchFrom() + r.charsMatched())); for (int i = 0; i < r.numSubs(); i++) { if (r.substring() != null) { v.addElement(r.substring(i + offset)); - vi.addElement(Integer.valueOf(r.matchFrom(i + offset) + vi.addElement(new Integer(r.matchFrom(i + offset) + r.charsMatched(i + offset))); } } diff --git a/src/ext/edu/ucsf/rbvi/strucviz2/ChimUtils.java b/src/ext/edu/ucsf/rbvi/strucviz2/ChimUtils.java index 6b5e36c..1d57a31 100644 --- a/src/ext/edu/ucsf/rbvi/strucviz2/ChimUtils.java +++ b/src/ext/edu/ucsf/rbvi/strucviz2/ChimUtils.java @@ -173,7 +173,7 @@ public abstract class ChimUtils float[] rgbValues = new float[4]; for (int i = 0; i < rgbStrings.length; i++) { - Float f = Float.valueOf(rgbStrings[i]); + Float f = new Float(rgbStrings[i]); rgbValues[i] = f.floatValue(); } if (rgbStrings.length == 4) @@ -203,7 +203,7 @@ public abstract class ChimUtils */ public static Integer makeModelKey(int model, int subModel) { - return Integer.valueOf(model * MAX_SUB_MODELS + subModel); + return new Integer(model * MAX_SUB_MODELS + subModel); } // invoked by the getResdiue (parseConnectivityReplies in diff --git a/src/ext/edu/ucsf/rbvi/strucviz2/ChimeraChain.java b/src/ext/edu/ucsf/rbvi/strucviz2/ChimeraChain.java index 4f871d3..9a29a99 100644 --- a/src/ext/edu/ucsf/rbvi/strucviz2/ChimeraChain.java +++ b/src/ext/edu/ucsf/rbvi/strucviz2/ChimeraChain.java @@ -200,7 +200,7 @@ public class ChimeraChain implements ChimeraStructuralObject */ public ChimeraResidue getResidue(String index) { - // Integer index = Integer.valueOf(residueIndex); + // Integer index = new Integer(residueIndex); if (residueMap.containsKey(index)) return residueMap.get(index); return null; diff --git a/src/ext/edu/ucsf/rbvi/strucviz2/StructureManager.java b/src/ext/edu/ucsf/rbvi/strucviz2/StructureManager.java index 22c9098..09a9713 100644 --- a/src/ext/edu/ucsf/rbvi/strucviz2/StructureManager.java +++ b/src/ext/edu/ucsf/rbvi/strucviz2/StructureManager.java @@ -121,8 +121,8 @@ public class StructureManager for (String chimObjName : names) { // get or open the corresponding models if they already exist - List currentModels = chimeraManager - .getChimeraModels(chimObjName, type); + List currentModels = chimeraManager.getChimeraModels( + chimObjName, type); if (currentModels.size() == 0) { // open and return models @@ -562,11 +562,11 @@ public class StructureManager // Get the corresponding "real" model if (chimeraManager.hasChimeraModel(modelNumber, subModelNumber)) { - ChimeraModel dataModel = chimeraManager - .getChimeraModel(modelNumber, subModelNumber); - if (dataModel.getResidueCount() == selectedModel.getResidueCount() - || dataModel - .getModelType() == StructureManager.ModelType.SMILES) + ChimeraModel dataModel = chimeraManager.getChimeraModel( + modelNumber, subModelNumber); + if (dataModel.getResidueCount() == selectedModel + .getResidueCount() + || dataModel.getModelType() == StructureManager.ModelType.SMILES) { // Select the entire model addChimSelection(dataModel); @@ -576,8 +576,8 @@ public class StructureManager { for (ChimeraChain selectedChain : selectedModel.getChains()) { - ChimeraChain dataChain = dataModel - .getChain(selectedChain.getChainId()); + ChimeraChain dataChain = dataModel.getChain(selectedChain + .getChainId()); if (selectedChain.getResidueCount() == dataChain .getResidueCount()) { @@ -931,7 +931,6 @@ public class StructureManager pathList.add("/usr/local/chimera/bin/chimera"); pathList.add("/usr/local/bin/chimera"); pathList.add("/usr/bin/chimera"); - pathList.add(System.getProperty("user.home") + "/opt/bin/chimera"); } else if (os.startsWith("Windows")) { diff --git a/src/ext/vamsas/JpredSoapBindingStub.java b/src/ext/vamsas/JpredSoapBindingStub.java old mode 100755 new mode 100644 index cff8081..8345551 --- a/src/ext/vamsas/JpredSoapBindingStub.java +++ b/src/ext/vamsas/JpredSoapBindingStub.java @@ -31,7 +31,7 @@ public class JpredSoapBindingStub extends org.apache.axis.client.Stub private java.util.Vector cachedDeserFactories = new java.util.Vector(); - static org.apache.axis.description.OperationDesc[] _operations; + private static org.apache.axis.description.OperationDesc[] _operations; static { @@ -260,6 +260,7 @@ public class JpredSoapBindingStub extends org.apache.axis.client.Stub } } + @Override public java.lang.String predict(vamsas.objects.simple.Sequence seq) throws java.rmi.RemoteException { @@ -297,6 +298,7 @@ public class JpredSoapBindingStub extends org.apache.axis.client.Stub } } + @Override public java.lang.String predictOnMsa( vamsas.objects.simple.Msfalignment msf) throws java.rmi.RemoteException @@ -335,6 +337,7 @@ public class JpredSoapBindingStub extends org.apache.axis.client.Stub } } + @Override public vamsas.objects.simple.Secstructpred getpredict( java.lang.String job_id) throws java.rmi.RemoteException { @@ -373,6 +376,7 @@ public class JpredSoapBindingStub extends org.apache.axis.client.Stub } } + @Override public vamsas.objects.simple.JpredResult getresult(java.lang.String job_id) throws java.rmi.RemoteException { diff --git a/src/ext/vamsas/MuscleWSSoapBindingStub.java b/src/ext/vamsas/MuscleWSSoapBindingStub.java index 1f8d231..026066c 100755 --- a/src/ext/vamsas/MuscleWSSoapBindingStub.java +++ b/src/ext/vamsas/MuscleWSSoapBindingStub.java @@ -23,7 +23,7 @@ package ext.vamsas; public class MuscleWSSoapBindingStub extends org.apache.axis.client.Stub implements ext.vamsas.MuscleWS { - static org.apache.axis.description.OperationDesc[] _operations; + private static final org.apache.axis.description.OperationDesc[] _operations; static { @@ -296,6 +296,7 @@ public class MuscleWSSoapBindingStub extends org.apache.axis.client.Stub } } + @Override public vamsas.objects.simple.WsJobId align( vamsas.objects.simple.SequenceSet seqSet) throws java.rmi.RemoteException @@ -337,6 +338,7 @@ public class MuscleWSSoapBindingStub extends org.apache.axis.client.Stub } } + @Override public vamsas.objects.simple.Alignment getalign(java.lang.String job_id) throws java.rmi.RemoteException { @@ -378,6 +380,7 @@ public class MuscleWSSoapBindingStub extends org.apache.axis.client.Stub } } + @Override public vamsas.objects.simple.MsaResult getResult(java.lang.String job_id) throws java.rmi.RemoteException { @@ -419,6 +422,7 @@ public class MuscleWSSoapBindingStub extends org.apache.axis.client.Stub } } + @Override public vamsas.objects.simple.WsJobId cancel(java.lang.String jobId) throws java.rmi.RemoteException { diff --git a/src/ext/vamsas/RegistryServiceSoapBindingStub.java b/src/ext/vamsas/RegistryServiceSoapBindingStub.java index 08b2a6b..f010ee8 100755 --- a/src/ext/vamsas/RegistryServiceSoapBindingStub.java +++ b/src/ext/vamsas/RegistryServiceSoapBindingStub.java @@ -31,7 +31,7 @@ public class RegistryServiceSoapBindingStub extends private java.util.Vector cachedDeserFactories = new java.util.Vector(); - static org.apache.axis.description.OperationDesc[] _operations; + private static org.apache.axis.description.OperationDesc[] _operations; static { @@ -192,6 +192,7 @@ public class RegistryServiceSoapBindingStub extends } } + @Override public ext.vamsas.ServiceHandles getServices() throws java.rmi.RemoteException { diff --git a/src/ext/vamsas/SeqSearchServiceSoapBindingStub.java b/src/ext/vamsas/SeqSearchServiceSoapBindingStub.java index 390ceb6..df0a504 100644 --- a/src/ext/vamsas/SeqSearchServiceSoapBindingStub.java +++ b/src/ext/vamsas/SeqSearchServiceSoapBindingStub.java @@ -31,7 +31,7 @@ public class SeqSearchServiceSoapBindingStub extends private java.util.Vector cachedDeserFactories = new java.util.Vector(); - static org.apache.axis.description.OperationDesc[] _operations; + private static final org.apache.axis.description.OperationDesc[] _operations; static { @@ -299,6 +299,7 @@ public class SeqSearchServiceSoapBindingStub extends } } + @Override public java.lang.String getDatabase() throws java.rmi.RemoteException { if (super.cachedEndpoint == null) @@ -335,6 +336,7 @@ public class SeqSearchServiceSoapBindingStub extends } } + @Override public vamsas.objects.simple.SeqSearchResult getResult( java.lang.String job_id) throws java.rmi.RemoteException { @@ -373,6 +375,7 @@ public class SeqSearchServiceSoapBindingStub extends } } + @Override public vamsas.objects.simple.WsJobId psearch( vamsas.objects.simple.Alignment al, java.lang.String database) throws java.rmi.RemoteException @@ -412,6 +415,7 @@ public class SeqSearchServiceSoapBindingStub extends } } + @Override public vamsas.objects.simple.WsJobId search( vamsas.objects.simple.Sequence s, java.lang.String database) throws java.rmi.RemoteException @@ -450,6 +454,7 @@ public class SeqSearchServiceSoapBindingStub extends } } + @Override public vamsas.objects.simple.WsJobId cancel(java.lang.String jobId) throws java.rmi.RemoteException { diff --git a/src/ext/vamsas/ServiceHandle.java b/src/ext/vamsas/ServiceHandle.java index 83412ea..428b5ea 100755 --- a/src/ext/vamsas/ServiceHandle.java +++ b/src/ext/vamsas/ServiceHandle.java @@ -126,6 +126,7 @@ public class ServiceHandle implements java.io.Serializable private java.lang.Object __equalsCalc = null; + @Override public synchronized boolean equals(java.lang.Object obj) { if (obj == null) @@ -162,6 +163,7 @@ public class ServiceHandle implements java.io.Serializable private boolean __hashCodeCalc = false; + @Override public synchronized int hashCode() { if (__hashCodeCalc) @@ -191,7 +193,7 @@ public class ServiceHandle implements java.io.Serializable } // Type metadata - private static org.apache.axis.description.TypeDesc typeDesc = new org.apache.axis.description.TypeDesc( + private static final org.apache.axis.description.TypeDesc typeDesc = new org.apache.axis.description.TypeDesc( ServiceHandle.class, true); static diff --git a/src/intervalstore/api/IntervalI.java b/src/intervalstore/api/IntervalI.java new file mode 100644 index 0000000..c170a43 --- /dev/null +++ b/src/intervalstore/api/IntervalI.java @@ -0,0 +1,192 @@ +/* +BSD 3-Clause License + +Copyright (c) 2018, Mungo Carstairs +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + +* Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + +* Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + +* Neither the name of the copyright holder nor the names of its + contributors may be used to endorse or promote products derived from + this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE +FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ +package intervalstore.api; + +import java.util.Collections; +import java.util.Comparator; +import java.util.List; + +public interface IntervalI +{ + + /** + * Compare intervals by start position ascending and end position descending. + */ + static Comparator COMPARATOR_BIGENDIAN = new Comparator() + { + @Override + public int compare(IntervalI o1, IntervalI o2) + { + int ret = Integer.signum(o1.getBegin() - o2.getBegin()); + return (ret == 0 ? Integer.signum(o2.getEnd() - o1.getEnd()) : ret); + } + }; + + /** + * Compare intervals by start position ascending and end position ascending. + */ + static Comparator COMPARATOR_LITTLEENDIAN = new Comparator() + { + @Override + public int compare(IntervalI o1, IntervalI o2) + { + int ret = Integer.signum(o1.getBegin() - o2.getBegin()); + return (ret == 0 ? Integer.signum(o1.getEnd() - o2.getEnd()) : ret); + } + }; + + /** + * a comparator for sorting intervals by start position ascending + */ + static Comparator FORWARD_STRAND = new Comparator() + { + @Override + public int compare(IntervalI o1, IntervalI o2) + { + return Integer.signum(o1.getBegin() - o2.getBegin()); + } + }; + + /** + * a comparator for sorting intervals by end position descending + */ + static Comparator REVERSE_STRAND = new Comparator() + { + @Override + public int compare(IntervalI o1, IntervalI o2) + { + return Integer.signum(o2.getEnd() - o1.getEnd()); + } + }; + + static int NOT_CONTAINED = Integer.MIN_VALUE; + static int CONTAINMENT_UNKNOWN = 0; + + int getBegin(); + int getEnd(); + + /** + * Answers true if this interval contains (or matches) the given interval + * based solely on start and end. + * + * @param i + * @return + */ + default boolean containsInterval(IntervalI i) + { + return i != null && i.getBegin() >= getBegin() + && i.getEnd() <= getEnd(); + } + + + /** + * Answers true if this interval properly contains the given interval, that + * is, it contains it and is larger than it + * + * @param i + * @return + */ + default boolean properlyContainsInterval(IntervalI i) + { + return containsInterval(i) + && (i.getBegin() > getBegin() || i.getEnd() < getEnd()); + } + + /** + * Slower than equalsInterval; also includes type. + * + * Ensure that subclasses override equals(Object). For example: + * + * public boolean equals(Object o) { return o != null && o instanceof XXX && + * equalsInterval((XXX) i); } + * + * + * equalsInterval also must be overridden. + * + * public boolean equalsInterval(IntervalI i) {return ((SimpleFeature)i).start + * == start && ((SimpleFeature)i).end == end && ((SimpleFeature)i).description + * == this.description; } + * + * + * @param o + * @return true if equal, including a type check + */ + @Override + abstract boolean equals(Object o); + + + + /** + * Check that two intervals are equal, in terms of end points, descriptions, + * or any other distinguishing features. + * + * Used in IntervalStore in searches, since it is faster than equals(), as at + * that point we know that we have the correct type. + * + * @param i + * @return true if equal + */ + abstract boolean equalsInterval(IntervalI i); + + default boolean overlapsInterval(IntervalI i) + { + if (i == null) + { + return false; + } + if (i.getBegin() < getBegin()) + { + return i.getEnd() >= getBegin(); + } + if (i.getEnd() > getEnd()) + { + return i.getBegin() <= getEnd(); + } + return true; // i internal to this + } + + /** + * Sorts the list by start position ascending (if forwardString==true), or by + * end position descending + * + * @param intervals + * @param forwardStrand + */ + static void sortIntervals(List intervals, + final boolean forwardStrand) + { + Collections.sort(intervals, + forwardStrand ? FORWARD_STRAND : REVERSE_STRAND); + } + + +} diff --git a/src/intervalstore/api/IntervalStoreI.java b/src/intervalstore/api/IntervalStoreI.java new file mode 100644 index 0000000..3b0f575 --- /dev/null +++ b/src/intervalstore/api/IntervalStoreI.java @@ -0,0 +1,96 @@ +/* +BSD 3-Clause License + +Copyright (c) 2018, Mungo Carstairs +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + +* Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + +* Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + +* Neither the name of the copyright holder nor the names of its + contributors may be used to endorse or promote products derived from + this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE +FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ +package intervalstore.api; + +import java.util.Collection; +import java.util.List; + +import intervalstore.impl.NCList; + +public interface IntervalStoreI extends Collection +{ + + /** + * Returns a (possibly empty) list of items whose extent overlaps the given + * range + * + * @param from + * start of overlap range (inclusive) + * @param to + * end of overlap range (inclusive) + * @return + */ + List findOverlaps(long from, long to); + + /** + * Ensures that the IntervalStore is ready for findOverlap. + * + * @return true iff the data held satisfy the rules of construction of an + * IntervalStore. + * + */ + boolean isValid(); + + /** + * Answers the level of nesting of intervals in the store, as + *
    + *
  • 0 if the store is empty
  • + *
  • 1 if all intervals are 'top level' (non nested)
  • + *
  • else 1 plus the depth of the enclosed NCList
  • + *
+ * + * @return + * @see NCList#getDepth() + */ + int getDepth(); + + /** + * Return the number of top-level (not-contained) intervals. + * + * @return + */ + int getWidth(); + + List findOverlaps(long start, long end, List result); + + String prettyPrint(); + + /** + * Resort and rebuild links. + * + * @return + */ + boolean revalidate(); + + IntervalI get(int i); + +} \ No newline at end of file diff --git a/src/intervalstore/impl/BinarySearcher.java b/src/intervalstore/impl/BinarySearcher.java new file mode 100644 index 0000000..1086e91 --- /dev/null +++ b/src/intervalstore/impl/BinarySearcher.java @@ -0,0 +1,91 @@ +/* +BSD 3-Clause License + +Copyright (c) 2018, Mungo Carstairs +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + +* Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + +* Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + +* Neither the name of the copyright holder nor the names of its + contributors may be used to endorse or promote products derived from + this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE +FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ +package intervalstore.impl; + +import java.util.List; +import java.util.function.Function; + +/** + * Provides a method to perform binary search of an ordered list for the first + * entry that satisfies a supplied condition + * + * @author gmcarstairs + */ +public final class BinarySearcher +{ + private BinarySearcher() + { + } + + /** + * Performs a binary search of the list to find the index of the first entry + * for which the test returns true. Answers the length of the list if there is + * no such entry. + *

+ * For correct behaviour, the provided list must be ordered consistent with + * the test, that is, any entries returning false must precede any entries + * returning true. Note that this means that this method is not + * usable to search for equality (to find a specific entry), as all unequal + * entries will answer false to the test. To do that, use + * Collections.binarySearch instead. + * + * @param list + * @param test + * @return + * @see java.util.Collections#binarySearch(List, Object) + */ + public static int findFirst(List list, + Function test) + { + int start = 0; + int end = list.size() - 1; + int matched = list.size(); + + while (start <= end) + { + int mid = (start + end) / 2; + T entry = list.get(mid); + boolean itsTrue = test.apply(entry); + if (itsTrue) + { + matched = mid; + end = mid - 1; + } + else + { + start = mid + 1; + } + } + + return matched; + } +} diff --git a/src/intervalstore/impl/IntervalStore.java b/src/intervalstore/impl/IntervalStore.java new file mode 100644 index 0000000..8634ad4 --- /dev/null +++ b/src/intervalstore/impl/IntervalStore.java @@ -0,0 +1,543 @@ +/* +BSD 3-Clause License + +Copyright (c) 2018, Mungo Carstairs +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + +* Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + +* Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + +* Neither the name of the copyright holder nor the names of its + contributors may be used to endorse or promote products derived from + this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE +FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ +package intervalstore.impl; + +import java.util.AbstractCollection; +import java.util.ArrayList; +import java.util.Iterator; +import java.util.List; +import java.util.NoSuchElementException; + +import intervalstore.api.IntervalI; +import intervalstore.api.IntervalStoreI; + +/** + * A collection class to store interval-associated data, with O(log N) + * performance for overlap queries, insertion and deletion (where N is the size + * of the store). Accepts duplicate entries but not null values. + * + * @author gmcarstairs + * + * @param + * any type providing getBegin() and getEnd() + */ +public class IntervalStore + extends AbstractCollection implements IntervalStoreI +{ + /** + * An iterator over the intervals held in this store, with no particular + * ordering guaranteed. The iterator does not support the optional + * remove operation (throws + * UnsupportedOperationException if attempted). + * + * @author gmcarstairs + * + * @param + */ + private class IntervalIterator implements Iterator + { + /* + * iterator over top level non-nested intervals + */ + Iterator topLevelIterator; + + /* + * iterator over NCList (if any) + */ + Iterator nestedIterator; + + /** + * Constructor initialises iterators over the top level list and any nested + * NCList + * + * @param intervalStore + */ + public IntervalIterator( + IntervalStore intervalStore) + { + topLevelIterator = nonNested.iterator(); + if (nested != null) + { + nestedIterator = nested.iterator(); + } + } + + @Override + public boolean hasNext() + { + return topLevelIterator.hasNext() ? true + : (nestedIterator != null && nestedIterator.hasNext()); + } + + @SuppressWarnings("unchecked") + @Override + public V next() + { + if (topLevelIterator.hasNext()) + { + return (V) topLevelIterator.next(); + } + if (nestedIterator != null) + { + return (V) nestedIterator.next(); + } + throw new NoSuchElementException(); + } + + } + + private List nonNested; + + private NCList nested; + + /** + * Constructor + */ + public IntervalStore() + { + nonNested = new ArrayList<>(); + } + + /** + * Constructor given a list of intervals. Note that the list may get sorted as + * a side-effect of calling this constructor. + */ + public IntervalStore(List intervals) + { + this(); + + /* + * partition into subranges whose root intervals + * have no mutual containment (if no intervals are nested, + * each subrange is of length 1 i.e. a single interval) + */ + List sublists = new NCListBuilder() + .partitionNestedSublists(intervals); + + /* + * add all 'subrange root intervals' (and any co-located intervals) + * to our top level list of 'non-nested' intervals; + * put aside any left over for our NCList + */ + List nested = new ArrayList<>(); + + for (IntervalI subrange : sublists) + { + int listIndex = subrange.getBegin(); + IntervalI root = intervals.get(listIndex); + while (listIndex <= subrange.getEnd()) + { + T t = intervals.get(listIndex); + if (root.equalsInterval(t)) + { + nonNested.add(t); + } + else + { + nested.add(t); + } + listIndex++; + } + } + + if (!nested.isEmpty()) + { + this.nested = new NCList<>(nested); + } + } + + /** + * Adds one interval to the store. + * + * @param interval + */ + @Override + public boolean add(T interval) + { + if (interval == null) + { + return false; + } + if (!addNonNestedInterval(interval)) + { + /* + * detected a nested interval - put it in the NCList structure + */ + addNestedInterval(interval); + } + return true; + } + + @Override + public boolean contains(Object entry) + { + if (listContains(nonNested, entry)) + { + return true; + } + + return nested == null ? false : nested.contains(entry); + } + + protected boolean addNonNestedInterval(T entry) + { + synchronized (nonNested) + { + /* + * find the first stored interval which doesn't precede the new one + */ + int insertPosition = BinarySearcher.findFirst(nonNested, + val -> val.getBegin() >= entry.getBegin()); + /* + * fail if we detect interval enclosure + * - of the new interval by the one before or after it + * - of the next interval by the new one + */ + if (insertPosition > 0) + { + if (nonNested.get(insertPosition - 1).properlyContainsInterval(entry)) + { + return false; + } + } + if (insertPosition < nonNested.size()) + { + T following = nonNested.get(insertPosition); + if (entry.properlyContainsInterval(following) + || following.properlyContainsInterval(entry)) + { + return false; + } + } + + /* + * checks passed - add the interval + */ + nonNested.add(insertPosition, entry); + + return true; + } + } + + @Override + public List findOverlaps(long from, long to) + { + List result = new ArrayList<>(); + + findNonNestedOverlaps(from, to, result); + + if (nested != null) + { + result.addAll(nested.findOverlaps(from, to)); + } + + return result; + } + + @Override + public String prettyPrint() + { + String pp = nonNested.toString(); + if (nested != null) + { + pp += System.lineSeparator() + nested.prettyPrint(); + } + return pp; + } + + @Override + public boolean isValid() + { + for (int i = 0; i < nonNested.size() - 1; i++) + { + IntervalI i1 = nonNested.get(i); + IntervalI i2 = nonNested.get(i + 1); + + if (i2.getBegin() < i1.getBegin()) + { + System.err.println("nonNested wrong start order : " + i1.toString() + + ", " + i2.toString()); + return false; + } + if (i1.properlyContainsInterval(i2) + || i2.properlyContainsInterval(i1)) + { + System.err.println("nonNested invalid containment!: " + + i1.toString() + + ", " + i2.toString()); + return false; + } + } + return nested == null ? true : nested.isValid(); + } + + @Override + public int size() + { + int i = nonNested.size(); + if (nested != null) + { + i += nested.size(); + } + return i; + } + + @Override + public synchronized boolean remove(Object o) + { + if (o == null) + { + return false; + } + try + { + @SuppressWarnings("unchecked") + T entry = (T) o; + + /* + * try the non-nested positional intervals first + */ + boolean removed = removeNonNested(entry); + + /* + * if not found, try nested intervals + */ + if (!removed && nested != null) + { + removed = nested.remove(entry); + } + + return removed; + } catch (ClassCastException e) + { + return false; + } + } + + /** + * Removes the given entry from the list of non-nested entries, returning true + * if found and removed, or false if not found. Specifically, removes the + * first item in the list for which item.equals(entry). + * + * @param entry + * @return + */ + protected boolean removeNonNested(T entry) + { + /* + * find the first interval that might match, i.e. whose + * start position is not less than the target range start + * (NB inequality test ensures the first match if any is found) + */ + int startIndex = BinarySearcher.findFirst(nonNested, + val -> val.getBegin() >= entry.getBegin()); + + /* + * traverse intervals to look for a match + */ + int from = entry.getBegin(); + int i = startIndex; + int size = nonNested.size(); + while (i < size) + { + T sf = nonNested.get(i); + if (sf.getBegin() > from) + { + break; + } + if (sf.equals(entry)) + { + nonNested.remove(i); + return true; + } + i++; + } + return false; + } + + @Override + public int getDepth() + { + if (size() == 0) + { + return 0; + } + return (nonNested.isEmpty() ? 0 : 1) + + (nested == null ? 0 : nested.getDepth()); + } + + /** + * Adds one interval to the NCList that can manage nested intervals (creating + * the NCList if necessary) + */ + protected synchronized void addNestedInterval(T interval) + { + if (nested == null) + { + nested = new NCList<>(); + } + nested.add(interval); + } + + /** + * Answers true if the list contains the interval, else false. This method is + * optimised for the condition that the list is sorted on interval start + * position ascending, and will give unreliable results if this does not hold. + * + * @param intervals + * @param entry + * @return + */ + protected boolean listContains(List intervals, Object entry) + { + if (intervals == null || entry == null || !(entry instanceof IntervalI)) + { + return false; + } + + IntervalI interval = (IntervalI) entry; + + /* + * locate the first entry in the list which does not precede the interval + */ + int pos = BinarySearcher.findFirst(intervals, + val -> val.getBegin() >= interval.getBegin()); + int len = intervals.size(); + while (pos < len) + { + T sf = intervals.get(pos); + if (sf.getBegin() > interval.getBegin()) + { + return false; // no match found + } + if (sf.equals(interval)) + { + return true; + } + pos++; + } + return false; + } + + /** + * Answers an iterator over the intervals in the store, with no particular + * ordering guaranteed. The iterator does not support the optional + * remove operation (throws + * UnsupportedOperationException if attempted). + */ + @Override + public Iterator iterator() + { + return new IntervalIterator<>(this); + } + + @Override + public void clear() + { + this.nonNested.clear(); + this.nested = new NCList<>(); + } + + /** + * Adds non-nested intervals to the result list that lie within the target + * range + * + * @param from + * @param to + * @param result + */ + protected void findNonNestedOverlaps(long from, long to, + List result) + { + /* + * find the first interval whose end position is + * after the target range start + */ + int startIndex = BinarySearcher.findFirst(nonNested, + val -> val.getEnd() >= from); + + final int startIndex1 = startIndex; + int i = startIndex1; + while (i < nonNested.size()) + { + T sf = nonNested.get(i); + if (sf.getBegin() > to) + { + break; + } + if (sf.getBegin() <= to && sf.getEnd() >= from) + { + result.add(sf); + } + i++; + } + } + + @Override + public String toString() + { + String s = nonNested.toString(); + if (nested != null) + { + s = s + System.lineSeparator() + nested.toString(); + } + return s; + } + + @Override + public int getWidth() + { + // TODO Auto-generated method stub + return 0; + } + + @Override + public List findOverlaps(long start, long end, List result) + { + // TODO Auto-generated method stub + return null; + } + + @Override + public boolean revalidate() + { + // TODO Auto-generated method stub + return false; + } + + @Override + public IntervalI get(int i) + { + // TODO Auto-generated method stub + return null; + } +} diff --git a/src/intervalstore/impl/NCList.java b/src/intervalstore/impl/NCList.java new file mode 100644 index 0000000..0bf6e1b --- /dev/null +++ b/src/intervalstore/impl/NCList.java @@ -0,0 +1,752 @@ +/* +BSD 3-Clause License + +Copyright (c) 2018, Mungo Carstairs +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + +* Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + +* Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + +* Neither the name of the copyright holder nor the names of its + contributors may be used to endorse or promote products derived from + this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE +FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ +package intervalstore.impl; + +import java.util.AbstractCollection; +import java.util.ArrayList; +import java.util.Collections; +import java.util.Iterator; +import java.util.List; +import java.util.NoSuchElementException; + +import intervalstore.api.IntervalI; +import intervalstore.impl.Range; + +/** + * An adapted implementation of NCList as described in the paper + * + *

+ * Nested Containment List (NCList): a new algorithm for accelerating
+ * interval query of genome alignment and interval databases
+ * - Alexander V. Alekseyenko, Christopher J. Lee
+ * https://doi.org/10.1093/bioinformatics/btl647
+ * 
+ */ +public class NCList extends AbstractCollection +{ + /** + * A depth-first iterator over the elements stored in the NCList + */ + private class NCListIterator implements Iterator + { + int subrangeIndex; + + Iterator nodeIterator; + + /** + * Constructor bootstraps a pointer to an iterator over the first subrange + * (if any) + */ + NCListIterator() + { + subrangeIndex = nextSubrange(-1); + } + + /** + * Moves the subrange iterator to the next subrange, and answers its index + * in the list of subranges. If there are no more, sets the iterator to null + * and answers -1. + * + * @return + */ + private int nextSubrange(int after) + { + int nextIndex = after + 1; + if (nextIndex < subranges.size()) + { + nodeIterator = subranges.get(nextIndex).iterator(); + return nextIndex; + } + nodeIterator = null; + return -1; + } + + @Override + public boolean hasNext() + { + return nodeIterator != null && nodeIterator.hasNext(); + } + + /** + * Answers the next element returned by the current NCNode's iterator, and + * advances the iterator (to the next NCNode if necessary) + */ + @Override + public T next() + { + if (nodeIterator == null || !nodeIterator.hasNext()) + { + throw new NoSuchElementException(); + } + T result = nodeIterator.next(); + + if (!nodeIterator.hasNext()) + { + subrangeIndex = nextSubrange(subrangeIndex); + } + return result; + } + + } + + /* + * the number of interval instances represented + */ + private int size; + + /* + * a list, in start position order, of sublists of ranges ordered so + * that each contains (or is the same as) the one that follows it + */ + private List> subranges; + + /** + * Constructor given a list of things that are each located on a contiguous + * interval. Note that the constructor may reorder the list. + *

+ * We assume here that for each range, start <= end. Behaviour for reverse + * ordered ranges is undefined. + * + * @param ranges + */ + public NCList(List ranges) + { + this(); + build(ranges); + } + + /** + * Sorts and groups ranges into sublists where each sublist represents an + * interval and its contained subintervals + * + * @param ranges + */ + protected void build(List ranges) + { + /* + * sort and partition into subranges + * which have no mutual containment + */ + List sublists = partitionNestedSublists(ranges); + + /* + * convert each subrange to an NCNode consisting of a range and + * (possibly) its contained NCList + */ + for (IntervalI sublist : sublists) + { + subranges.add(new NCNode<>( + ranges.subList(sublist.getBegin(), sublist.getEnd() + 1))); + } + + size = ranges.size(); + } + + /** + * Default constructor + */ + public NCList() + { + subranges = new ArrayList<>(); + } + + /** + * Sorts and traverses the ranges to identify sublists, whose start intervals + * are overlapping or disjoint but not mutually contained. Answers a list of + * start-end indices of the sorted list of ranges. + * + * @param ranges + * @return + */ + protected List partitionNestedSublists(List ranges) + { + List sublists = new ArrayList<>(); + + if (ranges.isEmpty()) + { + return sublists; + } + + /* + * sort by start ascending, length descending, so that + * contained intervals follow their containing interval + */ + Collections.sort(ranges, new NCListBuilder<>().getComparator()); + + int listStartIndex = 0; + + IntervalI lastParent = ranges.get(0); + boolean first = true; + + for (int i = 0; i < ranges.size(); i++) + { + IntervalI nextInterval = ranges.get(i); + if (!first && !lastParent.properlyContainsInterval(nextInterval)) + { + /* + * this interval is not properly contained in the parent; + * close off the last sublist + */ + sublists.add(new Range(listStartIndex, i - 1)); + listStartIndex = i; + lastParent = nextInterval; + } + first = false; + } + + sublists.add(new Range(listStartIndex, ranges.size() - 1)); + return sublists; + } + + /** + * Adds one entry to the stored set + * + * @param entry + */ + @Override + public synchronized boolean add(final T entry) + { + final NCNode newNode = new NCNode<>(entry); + addNode(newNode); + return true; + } + + /** + * Adds one NCNode to this NCList + *

+ * This method does not update the size (interval count) of this + * NCList, as it may be used to rearrange nodes without changing their count. + * Callers should increment the count if needed. + * + * @param newNode + */ + protected void addNode(final NCNode newNode) + { + final long start = newNode.getBegin(); + final long end = newNode.getEnd(); + size += newNode.size(); + + /* + * cases: + * 1) precedes all subranges - add as NCNode on front of list + * 2) follows all subranges - add as NCNode on end of list + * 3) matches a subrange - add as a sibling in the list + * 4) properly enclosed by a subrange - add recursively to subrange + * 5) properly encloses one or more subranges - push them inside it + * 6) spans two subranges - insert between them + */ + + /* + * find the first subrange whose end does not precede entry's start + */ + int candidateIndex = findFirstOverlap(start); + + /* + * search for maximal span of subranges i-k that the new entry + * encloses; or a subrange that encloses the new entry + */ + boolean enclosing = false; + int firstEnclosed = 0; + int lastEnclosed = 0; + + for (int j = candidateIndex; j < subranges.size(); j++) + { + NCNode subrange = subranges.get(j); + + if (subrange.equalsInterval(newNode)) + { + /* + * matching interval - insert adjacent + */ + subranges.add(j, newNode); + return; + } + + if (end < subrange.getBegin() && !enclosing) + { + /* + * new entry lies between subranges j-1 j + */ + subranges.add(j, newNode); + return; + } + + if (subrange.properlyContainsInterval(newNode)) + { + /* + * push new entry inside this subrange as it encloses it + */ + subrange.addNode(newNode); + return; + } + + if (start <= subrange.getBegin()) + { + if (end >= subrange.getEnd()) + { + /* + * new entry encloses this subrange (and possibly preceding ones); + * continue to find the maximal list it encloses + */ + if (!enclosing) + { + firstEnclosed = j; + } + lastEnclosed = j; + enclosing = true; + continue; + } + else + { + /* + * entry spans from before this subrange to inside it + */ + if (enclosing) + { + /* + * entry encloses one or more preceding subranges + */ + push(newNode, firstEnclosed, lastEnclosed); + } + else + { + /* + * entry overlaps two subranges but doesn't enclose either + * so just add it + */ + subranges.add(j, newNode); + } + return; + } + } + } + + /* + * drops through to here if new range encloses all others + * or overlaps the last one + */ + if (enclosing) + { + push(newNode, firstEnclosed, lastEnclosed); + } + else + { + subranges.add(newNode); + } + } + + @Override + public boolean contains(Object entry) + { + if (!(entry instanceof IntervalI)) + { + return false; + } + IntervalI interval = (IntervalI) entry; + + /* + * find the first sublist that might overlap, i.e. + * the first whose end position is >= from + */ + int candidateIndex = findFirstOverlap(interval.getBegin()); + + int to = interval.getEnd(); + + for (int i = candidateIndex; i < subranges.size(); i++) + { + NCNode candidate = subranges.get(i); + if (candidate.getBegin() > to) + { + /* + * we are past the end of our target range + */ + break; + } + if (candidate.contains(interval)) + { + return true; + } + } + return false; + } + + /** + * Update the tree so that the new node encloses current subranges i to j + * (inclusive). That is, replace subranges i-j (inclusive) with a new subrange + * that contains them. + * + * @param node + * @param i + * @param j + * @throws IllegalArgumentException + * if any of the subranges is not contained by the node's start-end + * range + */ + protected synchronized void push(NCNode node, final int i, + final int j) + { + for (int k = i; k <= j; k++) + { + NCNode n = subranges.get(k); + if (!node.containsInterval(n)) { + throw new IllegalArgumentException("Can't push " + n.toString() + + " inside " + node.toString()); + } + node.addNode(n); + } + + for (int k = j; k >= i; k--) + { + subranges.remove(k); + } + subranges.add(i, node); + } + + /** + * Answers a list of contained intervals that overlap the given range + * + * @param from + * @param to + * @return + */ + public List findOverlaps(long from, long to) + { + List result = new ArrayList<>(); + + findOverlaps(from, to, result); + + return result; + } + + /** + * Recursively searches the NCList adding any items that overlap the from-to + * range to the result list + * + * @param from + * @param to + * @param result + */ + protected void findOverlaps(long from, long to, List result) + { + /* + * find the first sublist that might overlap, i.e. + * the first whose end position is >= from + */ + int candidateIndex = findFirstOverlap(from); + + for (int i = candidateIndex; i < subranges.size(); i++) + { + NCNode candidate = subranges.get(i); + if (candidate.getBegin() > to) + { + /* + * we are past the end of our target range + */ + break; + } + candidate.findOverlaps(from, to, result); + } + + } + + /** + * Search subranges for the first one whose end position is not before the + * target range's start position, i.e. the first one that may overlap the + * target range. Returns the index in the list of the first such range found, + * or the length of the list if none found. + * + * @param from + * @return + */ + protected int findFirstOverlap(final long from) + { + return BinarySearcher.findFirst(subranges, + val -> val.getEnd() >= from); + } + + /** + * Formats the tree as a bracketed list e.g. + * + *

+   * [1-100 [10-30 [10-20]], 15-30 [20-20]]
+   * 
+ */ + @Override + public String toString() + { + return subranges.toString(); + } + + /** + * Answers the NCList as an indented list + * + * @return + */ + public String prettyPrint() + { + StringBuilder sb = new StringBuilder(512); + int offset = 0; + int indent = 2; + prettyPrint(sb, offset, indent); + sb.append(System.lineSeparator()); + return sb.toString(); + } + + /** + * @param sb + * @param offset + * @param indent + */ + void prettyPrint(StringBuilder sb, int offset, int indent) + { + boolean first = true; + for (NCNode subrange : subranges) + { + if (!first) + { + sb.append(System.lineSeparator()); + } + first = false; + subrange.prettyPrint(sb, offset, indent); + } + } + + /** + * Answers true if the store's structure is valid (nesting containment rules + * are obeyed), else false. For use in testing and debugging. + * + * @return + */ + public boolean isValid() + { + int count = 0; + for (NCNode subrange : subranges) + { + count += subrange.size(); + } + if (count != size) + { + return false; + } + return isValid(Integer.MIN_VALUE, Integer.MAX_VALUE); + } + + /** + * Answers true if the data held satisfy the rules of construction of an + * NCList bounded within the given start-end range, else false. + *

+ * Each subrange must lie within start-end (inclusive). Subranges must be + * ordered by start position ascending, and within that by end position + * descending. + *

+ * + * @param start + * @param end + * @return + */ + boolean isValid(final int start, final int end) + { + NCNode lastRange = null; + + for (NCNode subrange : subranges) + { + if (subrange.getBegin() < start) + { + System.err.println("error in NCList: range " + subrange.toString() + + " starts before " + end); + return false; + } + if (subrange.getEnd() > end) + { + System.err.println("error in NCList: range " + subrange.toString() + + " ends after " + end); + return false; + } + + if (lastRange != null) + { + if (subrange.getBegin() < lastRange.getBegin()) + { + System.err.println("error in NCList: range " + subrange.toString() + + " starts before " + lastRange.toString()); + return false; + } + if (subrange.properlyContainsInterval(lastRange)) + { + System.err.println("error in NCList: range " + subrange.toString() + + " encloses preceding: " + lastRange.toString()); + return false; + } + if (lastRange.properlyContainsInterval(subrange)) + { + System.err.println("error in NCList: range " + subrange.toString() + + " enclosed by preceding: " + lastRange.toString()); + return false; + } + } + lastRange = subrange; + + if (!subrange.isValid()) + { + return false; + } + } + return true; + } + + /** + * Answers the number of intervals stored + * + * @return + */ + @Override + public int size() + { + return size; + } + + /** + * Answers a list of all entries stored, in no guaranteed order. This method + * is not synchronized, so is not thread-safe. + */ + public List getEntries() + { + List result = new ArrayList<>(); + getEntries(result); + return result; + } + + /** + * Adds all contained entries to the given list + * + * @param result + */ + void getEntries(List result) + { + for (NCNode subrange : subranges) + { + subrange.getEntries(result); + } + } + + /** + * Removes the first interval Ifound that is equal to T + * (I.equals(T)). Answers true if an interval is removed, false + * if no match is found. This method is synchronized so thread-safe. + * + * @param entry + * @return + */ + public synchronized boolean remove(T entry) + { + if (entry == null) + { + return false; + } + int i = findFirstOverlap(entry.getBegin()); + + for (; i < subranges.size(); i++) + { + NCNode subrange = subranges.get(i); + if (subrange.getBegin() > entry.getBegin()) + { + /* + * not found + */ + return false; + } + NCList subRegions = subrange.getSubRegions(); + + if (subrange.getRegion().equals(entry)) + { + /* + * if the subrange is rooted on this entry, remove it, + * and remove and promote its subregions (if any) + */ + subranges.remove(i); + size -= subrange.size(); + if (subRegions != null) + { + for (NCNode r : subRegions.subranges) + { + addNode(r); + } + } + return true; + } + else + { + if (subrange.remove(entry)) + { + size--; + return true; + } + } + } + return false; + } + + /** + * Answers the depth of interval nesting of this object, where 1 means there + * are no nested sub-intervals + * + * @return + */ + public int getDepth() + { + int subDepth = 0; + for (NCNode subrange : subranges) + { + subDepth = Math.max(subDepth, subrange.getDepth()); + } + + return subDepth; + } + + /** + * Answers an iterator over the contained intervals, with no particular order + * guaranteed. The iterator does not support the optional remove + * operation (throws UnsupportedOperationException if attempted). + */ + @Override + public Iterator iterator() + { + return new NCListIterator(); + } + + @Override + public synchronized void clear() + { + subranges.clear(); + size = 0; + } +} diff --git a/src/intervalstore/impl/NCListBuilder.java b/src/intervalstore/impl/NCListBuilder.java new file mode 100644 index 0000000..4c87306 --- /dev/null +++ b/src/intervalstore/impl/NCListBuilder.java @@ -0,0 +1,143 @@ +/* +BSD 3-Clause License + +Copyright (c) 2018, Mungo Carstairs +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + +* Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + +* Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + +* Neither the name of the copyright holder nor the names of its + contributors may be used to endorse or promote products derived from + this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE +FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ +package intervalstore.impl; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.Comparator; +import java.util.List; + +import intervalstore.api.IntervalI; +import intervalstore.impl.Range; + +/** + * A comparator that orders ranges by either start position ascending. If + * position matches, ordering is by length descending. This provides the + * canonical ordering of intervals into subranges in order to build a nested + * containment list. + * + * @author gmcarstairs + */ +public class NCListBuilder +{ + class NCListComparator implements Comparator + { + /** + * Compares two intervals in a way that will sort a list by start position + * ascending, then by length descending. Answers + *

    + *
  • a negative value if o1.begin < o2.begin
  • + *
  • else a positive value if o1.begin > o2.begin
  • + *
  • else a negative value if o1.end > o2.end
  • + *
  • else a positive value of o1.end < o2.end
  • + *
  • else zero
  • + */ + @Override + public int compare(V o1, V o2) + { + int order = Integer.compare(o1.getBegin(), o2.getBegin()); + if (order == 0) + { + /* + * if tied on start position, longer length sorts to left + * i.e. the negation of normal ordering by length + */ + order = Integer.compare(o2.getEnd(), o1.getEnd()); + } + return order; + } + } + + private Comparator comparator = new NCListComparator<>(); + + /** + * Default constructor + */ + public NCListBuilder() + { + } + + /** + * Answers a comparator which sorts items of type T by start position + * ascending, and within that by end position (length) descending) + * + * @return + */ + Comparator getComparator() + { + return comparator; + } + + /** + * Sorts and traverses the ranges to identify sublists, whose start intervals + * are overlapping or disjoint but not mutually contained. Answers a list of + * start-end indices of the sorted list of ranges. + * + * @param ranges + * @return + */ + List partitionNestedSublists(List ranges) + { + List sublists = new ArrayList<>(); + + /* + * sort by start ascending, length descending, so that + * contained intervals follow their containing interval + */ + Collections.sort(ranges, comparator); + + int listStartIndex = 0; + + IntervalI lastParent = ranges.get(0); + boolean first = true; + + for (int i = 0; i < ranges.size(); i++) + { + IntervalI nextInterval = ranges.get(i); + if (!first && !lastParent.properlyContainsInterval(nextInterval)) + { + /* + * this interval is not properly contained in the parent; + * close off the last sublist + */ + sublists.add(new Range(listStartIndex, i - 1)); + listStartIndex = i; + lastParent = nextInterval; + } + first = false; + } + + sublists.add(new Range(listStartIndex, ranges.size() - 1)); + return sublists; + } +} diff --git a/src/intervalstore/impl/NCNode.java b/src/intervalstore/impl/NCNode.java new file mode 100644 index 0000000..16ae0b7 --- /dev/null +++ b/src/intervalstore/impl/NCNode.java @@ -0,0 +1,381 @@ +/* +BSD 3-Clause License + +Copyright (c) 2018, Mungo Carstairs +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + +* Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + +* Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + +* Neither the name of the copyright holder nor the names of its + contributors may be used to endorse or promote products derived from + this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE +FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ +package intervalstore.impl; + +import java.util.Iterator; +import java.util.List; +import java.util.NoSuchElementException; + +import intervalstore.api.IntervalI; + +/** + * Each node of the NCList tree consists of a range, and (optionally) the NCList + * of ranges it encloses + * + * @param + */ +class NCNode implements IntervalI +{ + /** + * A depth-first iterator over the intervals stored in the NCNode. The + * optional remove operation is not supported. + * + * @author gmcarstairs + * + */ + private class NCNodeIterator implements Iterator + { + boolean first = true; + Iterator subregionIterator; + + @Override + public boolean hasNext() + { + return first + || (subregionIterator != null && subregionIterator.hasNext()); + } + + /** + * Answers the next interval - initially the top level interval for this + * node, thereafter the intervals returned by the NCList's iterator + */ + @Override + public T next() + { + if (first) + { + subregionIterator = subregions == null ? null + : subregions.iterator(); + first = false; + return region; + } + if (subregionIterator == null || !subregionIterator.hasNext()) + { + throw new NoSuchElementException(); + } + return subregionIterator.next(); + } + } + + private T region; + + /* + * null, or an object holding contained subregions of this nodes region + */ + private NCList subregions; + + /** + * Constructor given a list of ranges. The list not be empty, and should be + * ordered so that the first range contains all the others. If not, behaviour + * will likely be invalid. + * + * @param ranges + * @throws IllegalArgumentException + * if the list is empty + */ + NCNode(List ranges) + { + if (ranges.isEmpty()) + { + throw new IllegalArgumentException("List may not be empty"); + } + region = ranges.get(0); + + if (ranges.size() > 1) + { + subregions = new NCList<>(ranges.subList(1, ranges.size())); + } + } + + /** + * Constructor given a single range + * + * @param range + */ + NCNode(T range) + { + region = range; + } + + @Override + public int getBegin() + { + return region.getBegin(); + } + + @Override + public int getEnd() + { + return region.getEnd(); + } + + /** + * Formats the node as a bracketed list e.g. + * + *
    +   * [1-100 [10-30 [10-20]], 15-30 [20-20]]
    +   * 
    + * + * where the format for each interval is as given by T.toString() + */ + @Override + public String toString() + { + StringBuilder sb = new StringBuilder(10 * size()); + sb.append(region.toString()); + if (subregions != null) + { + sb.append(" ").append(subregions.toString()); + } + return sb.toString(); + } + + void prettyPrint(StringBuilder sb, int offset, int indent) + { + for (int i = 0; i < offset; i++) + { + sb.append(" "); + } + sb.append(region.toString()); + if (subregions != null) + { + sb.append(System.lineSeparator()); + subregions.prettyPrint(sb, offset + 2, indent); + } + } + + /** + * Add any ranges that overlap the from-to range to the result list + * + * @param from + * @param to + * @param result + */ + void findOverlaps(long from, long to, List result) + { + if (region.getBegin() <= to && region.getEnd() >= from) + { + result.add(region); + if (subregions != null) + { + subregions.findOverlaps(from, to, result); + } + } + } + + /** + * Add one node to this node's subregions. + * + * @param entry + * @throws IllegalArgumentException + * if the added node is not contained by the node's start-end range + */ + synchronized void addNode(NCNode entry) + { + if (!region.containsInterval(entry)) + { + throw new IllegalArgumentException( + String.format("adding improper subrange %d-%d to range %d-%d", + entry.getBegin(), entry.getEnd(), region.getBegin(), + region.getEnd())); + } + if (subregions == null) + { + subregions = new NCList<>(); + } + + subregions.addNode(entry); + } + + /** + * Answers true if the data held satisfy the rules of construction of an + * NCList, else false + * + * @return + */ + boolean isValid() + { + /* + * we don't handle reverse ranges + */ + if (region != null && region.getBegin() > region.getEnd()) + { + return false; + } + if (subregions == null) + { + return true; + } + if (subregions.isEmpty()) + { + /* + * we expect empty subregions to be nulled + */ + return false; + } + return subregions.isValid(getBegin(), getEnd()); + } + + /** + * Adds all contained entries to the given list + * + * @param entries + */ + void getEntries(List entries) + { + entries.add(region); + if (subregions != null) + { + subregions.getEntries(entries); + } + } + + /** + * Answers true if this object contains the given entry (by object equals + * test), else false + * + * @param entry + * @return + */ + boolean contains(IntervalI entry) + { + if (entry == null) + { + return false; + } + if (entry.equals(region)) + { + return true; + } + return subregions == null ? false : subregions.contains(entry); + } + + /** + * Answers the 'root' region modelled by this object + * + * @return + */ + T getRegion() + { + return region; + } + + /** + * Answers the (possibly null) contained regions within this object + * + * @return + */ + NCList getSubRegions() + { + return subregions; + } + + /** + * Answers the (deep) size of this node i.e. the number of intervals it models + * + * @return + */ + int size() + { + return subregions == null ? 1 : 1 + subregions.size(); + } + + /** + * Answers the depth of NCNode / NCList nesting in the data tree + * + * @return + */ + int getDepth() + { + return subregions == null ? 1 : 1 + subregions.getDepth(); + } + + /** + * Answers an iterator over the intervals stored in this node. The iterator + * does not support the optional remove operation (throws + * UnsupportedOperationException if attempted). + * + * @return + */ + public Iterator iterator() + { + return new NCNodeIterator(); + } + + /** + * Removes the first interval found equal to the given entry. Answers true if + * a matching interval is found and removed, else false. + * + * @param entry + * @return + */ + boolean remove(T entry) + { + if (region.equals(entry)) + { + /* + * this case must be handled by NCList, to allow any + * children of a deleted interval to be promoted + */ + throw new IllegalArgumentException("NCNode can't remove self"); + } + if (subregions == null) + { + return false; + } + if (subregions.remove(entry)) + { + if (subregions.isEmpty()) + { + subregions = null; + } + return true; + } + return false; + } + + @SuppressWarnings("unchecked") + @Override + public boolean equals(Object o) + { + return o != null && o instanceof NCNode + && equalsInterval((NCNode) o); + } + + @Override + public boolean equalsInterval(IntervalI i) + { + return getBegin() == i.getBegin() && getEnd() == i.getEnd(); + + } + +} diff --git a/src/intervalstore/nonc/IntervalStore.java b/src/intervalstore/nonc/IntervalStore.java new file mode 100644 index 0000000..55d29e8 --- /dev/null +++ b/src/intervalstore/nonc/IntervalStore.java @@ -0,0 +1,1053 @@ +/* +BSD 3-Clause License + +Copyright (c) 2018, Mungo Carstairs +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + +* Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + +* Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + +* Neither the name of the copyright holder nor the names of its + contributors may be used to endorse or promote products derived from + this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE +FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ +package intervalstore.nonc; + +import java.util.AbstractCollection; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.BitSet; +import java.util.Collections; +import java.util.Comparator; +import java.util.Iterator; +import java.util.List; +import java.util.NoSuchElementException; + +import intervalstore.api.IntervalI; +import intervalstore.api.IntervalStoreI; + +/** + * + * A second idea, doing a double binary sort for the full interval. Seemed like + * a good idea, but is 50% slower. + * + * A Collection class to store interval-associated data, with options for "lazy" + * sorting so as to speed incremental construction of the data prior to issuing + * a findOverlap call. + * + * + * Accepts duplicate entries but not null values. + * + * + * + * @author Bob Hanson 2019.08.06 + * + * @param + * any type providing getBegin(), getEnd() + * getContainedBy(), and setContainedBy() + */ +public class IntervalStore + extends AbstractCollection implements IntervalStoreI +{ + + /** + * Search for the last interval that starts before or at the specified from/to + * range and the first interval that starts after it. In the situation that + * there are multiple intervals starting at from, this method returns the + * first of those. + * + * @param a + * @param from + * @param to + * @param ret + * @return + */ + public int binaryLastIntervalSearch(long from, + long to, int[] ret) + { + int start = 0, start2 = 0; + int matched = 0; + int end = intervalCount - 1, end2 = intervalCount; + int mid, begin; + IntervalI e; + while (start <= end) + { + mid = (start + end) >>> 1; + e = intervals[mid]; + begin = e.getBegin(); + switch (Long.signum(begin - from)) + { + case -1: + matched = mid; + start = mid + 1; + break; + case 0: + case 1: + end = mid - 1; + if (begin > to) + { + end2 = mid; + } + else + { + start2 = mid; + } + break; + } + } + ret[0] = end2; + start = Math.max(start2, end); + end = end2 - 1; + + while (start <= end) + { + mid = (start + end) >>> 1; + e = intervals[mid]; + begin = e.getBegin(); + if (begin > to) + { + ret[0] = mid; + end = mid - 1; + } + else + { + start = mid + 1; + } + + } + return matched; + } + + /** + * My preference is for a bigendian comparison, but you may differ. + */ + private Comparator icompare; + + /** + * bigendian is what NCList does; change icompare to switch to that + */ + private boolean bigendian; + + private final boolean DO_PRESORT; + + private boolean isSorted; + + private int minStart = Integer.MAX_VALUE, maxStart = Integer.MIN_VALUE, + maxEnd = Integer.MAX_VALUE; + + // private Comparator icompare = new IntervalComparator(); + + private boolean isTainted; + + private int capacity = 8; + + private IntervalI[] intervals = new IntervalI[capacity]; + + private int[] offsets; + + private int[] ret = new int[1]; + + private int intervalCount; + + private int added; + + private int deleted; + + private BitSet bsDeleted; + + /** + * Constructor + */ + public IntervalStore() + { + this(true); + } + + public IntervalStore(boolean presort) + { + this(null, presort); + } + + /** + * Constructor given a list of intervals. Note that the list may get sorted as + * a side-effect of calling this constructor. + */ + public IntervalStore(List intervals) + { + this(intervals, true); + } + + /** + * Allows a presort option, which can speed up initial loading of individual + * features but will delay the first findOverlap if set to true. + * + * @param intervals + * @param presort + */ + public IntervalStore(List intervals, boolean presort) + { + this(intervals, presort, null, false); + } + + /** + * + * @param intervals + * intervals to initialize with (others may still be added) + * @param presort + * whether or not to presort the list as additions are made + * @param comparator + * IntervalI.COMPARATOR_LITTLEENDIAN or + * IntervalI.COMPARATOR_BIGENDIAN, but this could also be one that + * sorts by description as well, for example. + * @param bigendian + * true if the comparator sorts [10-30] before [10-20] + */ + public IntervalStore(List intervals, boolean presort, + Comparator comparator, boolean bigendian) + { + if (intervals != null) + { + intervals.toArray( + this.intervals = new IntervalI[capacity = intervalCount = intervals + .size()]); + } + DO_PRESORT = presort; + icompare = (comparator != null ? comparator + : bigendian ? IntervalI.COMPARATOR_BIGENDIAN + : IntervalI.COMPARATOR_LITTLEENDIAN); + this.bigendian = bigendian; + + if (DO_PRESORT && intervalCount > 1) + { + sort(); + } + isSorted = DO_PRESORT; + isTainted = true; + } + + /** + * Adds one interval to the store, allowing duplicates. + * + * @param interval + */ + @Override + public boolean add(T interval) + { + return add(interval, true); + } + + /** + * Adds one interval to the store, optionally checking for duplicates. + * + * @param interval + * @param allowDuplicates + */ + public boolean add(T interval, boolean allowDuplicates) + { + if (interval == null) + { + return false; + } + + if (deleted > 0) + { + finalizeDeletion(); + } + if (!isTainted) + { + offsets = null; + isTainted = true; + } + + synchronized (intervals) + { + int index = intervalCount; + int start = interval.getBegin(); + + if (intervalCount + added + 1 >= capacity) + { + intervals = finalizeAddition( + new IntervalI[capacity = capacity << 1]); + + } + + if (DO_PRESORT && isSorted) + { + if (intervalCount == 0) + { + // ignore + } + else + { + index = findInterval(interval); + if (!allowDuplicates && index >= 0) + { + return false; + } + if (index < 0) + { + index = -1 - index; + } + else + { + index++; + } + } + + } + else + { + if (!allowDuplicates && findInterval(interval) >= 0) + { + return false; + } + isSorted = false; + } + + if (index == intervalCount) + { + intervals[intervalCount++] = interval; + // System.out.println("added " + intervalCount + " " + interval); + } + else + { + int pt = capacity - ++added; + intervals[pt] = interval; + // System.out.println("stashed " + pt + " " + interval + " for " + // + index + " " + intervals[index]); + if (offsets == null) + { + offsets = new int[capacity]; + } + + offsets[pt] = offsets[index]; + + offsets[index] = pt; + } + + minStart = Math.min(minStart, start); + maxStart = Math.max(maxStart, start); + return true; + } + } + + private IntervalI[] finalizeAddition(IntervalI[] dest) + { + if (dest == null) + { + dest = intervals; + } + if (added == 0) + { + if (intervalCount > 0 && dest != intervals) + { + System.arraycopy(intervals, 0, dest, 0, intervalCount); + } + capacity = dest.length; + return dest; + } + + // array is [(intervalCount)...null...(added)] + + int ntotal = intervalCount + added; + for (int ptShift = intervalCount + added, pt = intervalCount; pt >= 0;) + { + int pt0 = pt; + while (--pt >= 0 && offsets[pt] == 0) + { + ; + } + if (pt < 0) + { + pt = 0; + } + int nOK = pt0 - pt; + // shift upper intervals right + ptShift -= nOK; + if (nOK > 0) + { + System.arraycopy(intervals, pt, dest, ptShift, nOK); + } + if (added == 0) + { + break; + } + for (int offset = offsets[pt]; offset > 0; offset = offsets[offset]) + { + dest[--ptShift] = intervals[offset]; + --added; + } + } + offsets = null; + intervalCount = ntotal; + capacity = dest.length; + return dest; + } + + public int binaryIdentitySearch(IntervalI interval) + { + return binaryIdentitySearch(interval, null); + } + /** + * for remove() and contains() + * + * @param list + * @param interval + * @param bsIgnore + * for deleted + * @return index or, if not found, -1 - "would be here" + */ + public int binaryIdentitySearch(IntervalI interval, BitSet bsIgnore) + { + int start = 0; + int r0 = interval.getBegin(); + int r1 = interval.getEnd(); + int end = intervalCount - 1; + if (end < 0 || r0 < minStart) + { + return -1; + } + if (r0 > maxStart) + { + return -1 - intervalCount; + } + while (start <= end) + { + int mid = (start + end) >>> 1; + IntervalI r = intervals[mid]; + switch (compareRange(r, r0, r1)) + { + case -1: + start = mid + 1; + continue; + case 1: + end = mid - 1; + continue; + case 0: + IntervalI iv = intervals[mid]; + if ((bsIgnore == null || !bsIgnore.get(mid)) + && iv.equalsInterval(interval)) + { + return mid; + // found one; just scan up and down now, first checking the range, but + // also checking other possible aspects of equivalence. + } + + for (int i = mid; ++i <= end;) + { + if ((iv = intervals[i]).getBegin() != r0 || iv.getEnd() != r1) + { + break; + } + if ((bsIgnore == null || !bsIgnore.get(i)) + && iv.equalsInterval(interval)) + { + return i; + } + } + for (int i = mid; --i >= start;) + { + if ((iv = intervals[i]).getBegin() != r0 || iv.getEnd() < r1) + { + return -1 - ++i; + } + if ((bsIgnore == null || !bsIgnore.get(i)) + && iv.equalsInterval(interval)) + { + return i; + } + } + return -1 - start; + } + } + return -1 - start; + } + + // private int binaryInsertionSearch(long from, long to) + // { + // int matched = intervalCount; + // int end = matched - 1; + // int start = matched; + // if (end < 0 || from > intervals[end].getEnd() + // || from < intervals[start = 0].getBegin()) + // return start; + // while (start <= end) + // { + // int mid = (start + end) >>> 1; + // switch (compareRange(intervals[mid], from, to)) + // { + // case 0: + // return mid; + // case 1: + // matched = mid; + // end = mid - 1; + // continue; + // case -1: + // start = mid + 1; + // continue; + // } + // + // } + // return matched; + // } + + + @Override + public void clear() + { + intervalCount = added = 0; + isSorted = true; + isTainted = true; + offsets = null; + minStart = maxEnd = Integer.MAX_VALUE; + maxStart = Integer.MIN_VALUE; + } + /** + * Compare an interval t to a from/to range for insertion purposes + * + * @param t + * @param from + * @param to + * @return 0 if same, 1 if start is after from, or start equals from and + * [bigendian: end is before to | littleendian: end is after to], else + * -1 + */ + private int compareRange(IntervalI t, long from, long to) + { + if (t == null) + { + System.out.println("???"); + } + int order = Long.signum(t.getBegin() - from); + return (order == 0 + ? Long.signum(bigendian ? to - t.getEnd() : t.getEnd() - to) + : order); + } + + @Override + public boolean contains(Object entry) + { + if (entry == null || intervalCount == 0) + { + return false; + } + if (!isSorted || deleted > 0) + { + sort(); + } + return (findInterval((IntervalI) entry) >= 0); + } + + public boolean containsInterval(IntervalI outer, IntervalI inner) + { + ensureFinalized(); + int index = binaryIdentitySearch(inner, null); + if (index >= 0) + { + while ((index = index - Math.abs(offsets[index])) >= 0) + { + if (intervals[index] == outer) + { + return true; + } + } + } + return false; + } + + private void ensureFinalized() + { + if (isTainted) + { + if (!isSorted || added > 0 || deleted > 0) + { + sort(); + } + if (offsets == null || offsets.length < intervalCount) + { + offsets = new int[intervalCount]; + } + linkFeatures(); + isTainted = false; + } + } + + /** + * Find all overlaps within the given range, inclusively. + * + * @return a list sorted in ascending order of start position + * + */ + @Override + public List findOverlaps(long from, long to) + { + List list = findOverlaps(from, to, null); + Collections.reverse(list); + return list; + } + + /** + * Find all overlaps within the given range, inclusively. + * + * @return a list sorted in descending order of start position + * + */ + + @SuppressWarnings("unchecked") + @Override + public List findOverlaps(long from, long to, List result) + { + if (result == null) + { + result = new ArrayList<>(); + } + switch (intervalCount + added) + { + case 0: + return result; + case 1: + IntervalI sf = intervals[0]; + if (sf.getBegin() <= to && sf.getEnd() >= from) + { + result.add((T) sf); + } + return result; + } + + ensureFinalized(); + + if (from > maxEnd || to < minStart) + { + return result; + } + int index = binaryLastIntervalSearch(from, to, ret); + int index1 = ret[0]; + if (index1 < 0) + { + return result; + } + + if (index1 > index + 1) + { + while (--index1 > index) + { + result.add((T) intervals[index1]); + } + } + boolean isMonotonic = false; + while (index >= 0) + { + IntervalI sf = intervals[index]; + if (sf.getEnd() >= from) + { + result.add((T) sf); + } + else if (isMonotonic) + { + break; + } + int offset = offsets[index]; + isMonotonic = (offset < 0); + index -= (isMonotonic ? -offset : offset); + } + return result; + } + + @Override + public IntervalI get(int i) + { + if (i < 0 || i >= intervalCount + added) + { + return null; + } + ensureFinalized(); + return intervals[i]; + } + + private int getContainedBy(int index, int begin) + { + while (index >= 0) + { + IntervalI sf = intervals[index]; + if (sf.getEnd() >= begin) + { + // System.out.println("\nIS found " + sf0.getIndex1() + ":" + sf0 + // + "\nFS in " + sf.getIndex1() + ":" + sf); + return index; + } + index -= Math.abs(offsets[index]); + } + return IntervalI.NOT_CONTAINED; + } + + @Override + public int getDepth() + { + ensureFinalized(); + if (intervalCount < 2) + { + return intervalCount; + } + int maxDepth = 1; + IntervalI root = null; + for (int i = 0; i < intervalCount; i++) + { + IntervalI element = intervals[i]; + if (offsets[i] == IntervalI.NOT_CONTAINED) + { + root = element; + } + int depth = 1; + int index = i; + int offset; + while ((index = index - Math.abs(offset = offsets[index])) >= 0) + { + element = intervals[index]; + if (++depth > maxDepth && (element == root || offset < 0)) + { + maxDepth = depth; + break; + } + } + } + return maxDepth; + } + + @Override + public int getWidth() + { + ensureFinalized(); + int w = 0; + for (int i = offsets.length; --i >= 0;) + { + if (offsets[i] > 0) + { + w++; + } + } + return w; + } + + @Override + public boolean isValid() + { + ensureFinalized(); + return true; + } + + /** + * Answers an iterator over the intervals in the store, with no particular + * ordering guaranteed. The iterator does not support the optional + * remove operation (throws + * UnsupportedOperationException if attempted). + */ + @Override + public Iterator iterator() + { + ensureFinalized(); + return new Iterator() + { + + private int next; + + @Override + public boolean hasNext() + { + return next < intervalCount; + } + + @SuppressWarnings("unchecked") + @Override + public T next() + { + if (next >= intervalCount) + { + throw new NoSuchElementException(); + } + return (T) intervals[next++]; + } + + }; + } + + private void linkFeatures() + { + if (intervalCount == 0) + { + return; + } + maxEnd = intervals[0].getEnd(); + offsets[0] = IntervalI.NOT_CONTAINED; + if (intervalCount == 1) + { + return; + } + boolean isMonotonic = true; + for (int i = 1; i < intervalCount; i++) + { + IntervalI sf = intervals[i]; + int begin = sf.getBegin(); + int index = (begin <= maxEnd ? getContainedBy(i - 1, begin) : -1); + // System.out.println(sf + " is contained by " + // + (index < 0 ? null : starts[index])); + + offsets[i] = (index < 0 ? IntervalI.NOT_CONTAINED + : isMonotonic ? index - i : i - index); + isMonotonic = (sf.getEnd() > maxEnd); + if (isMonotonic) + { + maxEnd = sf.getEnd(); + } + } + + } + + @Override + public String prettyPrint() + { + switch (intervalCount + added) + { + case 0: + return ""; + case 1: + return intervals[0] + "\n"; + } + ensureFinalized(); + String sep = "\t"; + StringBuffer sb = new StringBuffer(); + for (int i = 0; i < intervalCount; i++) + { + IntervalI range = intervals[i]; + int index = i; + while ((index = index - Math.abs(offsets[index])) >= 0) + { + sb.append(sep); + } + sb.append(range.toString()).append('\n'); + } + return sb.toString(); + } + + @Override + public synchronized boolean remove(Object o) + { + // if (o == null) + // { + // throw new NullPointerException(); + // } + return (o != null && intervalCount > 0 + && removeInterval((IntervalI) o)); + } + + /** + * Find the interval or return where it should go, possibly into the add + * buffer + * + * @param interval + * @return index (nonnegative) or index where it would go (negative) + */ + + private int findInterval(IntervalI interval) + { + + if (isSorted) + { + int pt = binaryIdentitySearch(interval, null); + // if (addPt == intervalCount || offsets[pt] == 0) + // return pt; + if (pt >= 0 || added == 0 || pt == -1 - intervalCount) + { + return pt; + } + pt = -1 - pt; + int start = interval.getBegin(); + int end = interval.getEnd(); + + int match = pt; + + while ((pt = offsets[pt]) != 0) + { + IntervalI iv = intervals[pt]; + switch (compareRange(iv, start, end)) + { + case -1: + break; + case 0: + if (iv.equalsInterval(interval)) + { + return pt; + } + // fall through + case 1: + match = pt; + continue; + } + } + return -1 - match; + } + else + { + int i = intervalCount; + while (--i >= 0 && !intervals[i].equalsInterval(interval)) + { + ; + } + return i; + } + } + + /** + * Uses a binary search to find the entry and removes it if found. + * + * @param interval + * @return + */ + protected boolean removeInterval(IntervalI interval) + { + + if (!isSorted || added > 0) + { + sort(); + } + int i = binaryIdentitySearch(interval, bsDeleted); + if (i < 0) + { + return false; + } + if (deleted == 0) + { + if (bsDeleted == null) + { + bsDeleted = new BitSet(intervalCount); + } + else + { + bsDeleted.clear(); + } + } + bsDeleted.set(i); + deleted++; + return (isTainted = true); + } + + private void finalizeDeletion() + { + if (deleted == 0) + { + return; + } + + // ......xxx.....xxxx.....xxxxx.... + // ......^i,pt + // ...... ....... + // ............ + for (int i = bsDeleted.nextSetBit(0), pt = i; i >= 0;) + { + i = bsDeleted.nextClearBit(i + 1); + int pt1 = bsDeleted.nextSetBit(i + 1); + if (pt1 < 0) + { + pt1 = intervalCount; + } + int n = pt1 - i; + System.arraycopy(intervals, i, intervals, pt, n); + pt += n; + if (pt1 == intervalCount) + { + for (i = pt1; --i >= pt;) + { + intervals[i] = null; + } + intervalCount -= deleted; + deleted = 0; + bsDeleted.clear(); + break; + } + i = pt1; + } + + + } + + @Override + public boolean revalidate() + { + isTainted = true; + isSorted = false; + ensureFinalized(); + return true; + } + + @Override + public int size() + { + return intervalCount + added - deleted; + } + + @Override + public Object[] toArray() + { + ensureFinalized(); + return super.toArray(); + } + + /** + * Sort intervals by start (lowest first) and end (highest first). + */ + private void sort() + { + if (added > 0) + { + intervals = finalizeAddition(new IntervalI[intervalCount + added]); + } + else if (deleted > 0) + { + finalizeDeletion(); + } + else + { + Arrays.sort(intervals, 0, intervalCount, icompare); + } + updateMinMaxStart(); + isSorted = true; + } + + private void updateMinMaxStart() + { + if (intervalCount > 0) + { + minStart = intervals[0].getBegin(); + maxStart = intervals[intervalCount - 1].getBegin(); + } + else + { + minStart = Integer.MAX_VALUE; + maxStart = Integer.MIN_VALUE; + } + } + + @Override + public String toString() + { + return prettyPrint(); + } + +} diff --git a/src/jalview/analysis/AlignmentSorter.java b/src/jalview/analysis/AlignmentSorter.java index b88ef3a..8634db6 100755 --- a/src/jalview/analysis/AlignmentSorter.java +++ b/src/jalview/analysis/AlignmentSorter.java @@ -22,6 +22,8 @@ package jalview.analysis; import jalview.analysis.scoremodels.PIDModel; import jalview.analysis.scoremodels.SimilarityParams; +import jalview.bin.ApplicationSingletonProvider; +import jalview.bin.ApplicationSingletonProvider.ApplicationSingletonI; import jalview.datamodel.AlignmentAnnotation; import jalview.datamodel.AlignmentI; import jalview.datamodel.AlignmentOrder; @@ -51,40 +53,65 @@ import java.util.List; * from the first tobesorted position in the alignment. e.g. (a,tb2,b,tb1,c,tb3 * becomes a,tb1,tb2,tb3,b,c) */ -public class AlignmentSorter +public class AlignmentSorter implements ApplicationSingletonI { + + private AlignmentSorter() + { + // private singleton + } + + private static AlignmentSorter getInstance() + { + return (AlignmentSorter) ApplicationSingletonProvider + .getInstance(AlignmentSorter.class); + } + + /** + * types of feature ordering: Sort by score : average score - or total score - + * over all features in region Sort by feature label text: (or if null - + * feature type text) - numerical or alphabetical Sort by feature density: + * based on counts - ignoring individual text or scores for each feature + */ + public static final String FEATURE_SCORE = "average_score"; + + public static final String FEATURE_LABEL = "text"; + + public static final String FEATURE_DENSITY = "density"; + /* * todo: refactor searches to follow a basic pattern: (search property, last * search state, current sort direction) */ - static boolean sortIdAscending = true; + boolean sortIdAscending = true; - static int lastGroupHash = 0; + int lastGroupHash = 0; - static boolean sortGroupAscending = true; + boolean sortGroupAscending = true; - static AlignmentOrder lastOrder = null; + AlignmentOrder lastOrder = null; - static boolean sortOrderAscending = true; + boolean sortOrderAscending = true; - static TreeModel lastTree = null; + TreeModel lastTree = null; - static boolean sortTreeAscending = true; + boolean sortTreeAscending = true; - /* + + /** * last Annotation Label used for sort by Annotation score */ - private static String lastSortByAnnotation; + private String lastSortByAnnotation; - /* - * string hash of last arguments to sortByFeature - * (sort order toggles if this is unchanged between sorts) + /** + * string hash of last arguments to sortByFeature (sort order toggles if this + * is unchanged between sorts) */ - private static String sortByFeatureCriteria; + private String sortByFeatureCriteria; - private static boolean sortByFeatureAscending = true; + private boolean sortByFeatureAscending = true; - private static boolean sortLengthAscending; + private boolean sortLengthAscending; /** * Sorts sequences in the alignment by Percentage Identity with the given @@ -222,7 +249,8 @@ public class AlignmentSorter QuickSort.sort(ids, seqs); - if (sortIdAscending) + AlignmentSorter as = getInstance(); + if (as.sortIdAscending) { setReverseOrder(align, seqs); } @@ -231,7 +259,7 @@ public class AlignmentSorter setOrder(align, seqs); } - sortIdAscending = !sortIdAscending; + as.sortIdAscending = !as.sortIdAscending; } /** @@ -255,7 +283,9 @@ public class AlignmentSorter QuickSort.sort(length, seqs); - if (sortLengthAscending) + AlignmentSorter as = getInstance(); + + if (as.sortLengthAscending) { setReverseOrder(align, seqs); } @@ -264,7 +294,7 @@ public class AlignmentSorter setOrder(align, seqs); } - sortLengthAscending = !sortLengthAscending; + as.sortLengthAscending = !as.sortLengthAscending; } /** @@ -281,14 +311,16 @@ public class AlignmentSorter // ORDERS BY GROUP SIZE List groups = new ArrayList<>(); - if (groups.hashCode() != lastGroupHash) + AlignmentSorter as = getInstance(); + + if (groups.hashCode() != as.lastGroupHash) { - sortGroupAscending = true; - lastGroupHash = groups.hashCode(); + as.sortGroupAscending = true; + as.lastGroupHash = groups.hashCode(); } else { - sortGroupAscending = !sortGroupAscending; + as.sortGroupAscending = !as.sortGroupAscending; } // SORTS GROUPS BY SIZE @@ -328,7 +360,7 @@ public class AlignmentSorter } } - if (sortGroupAscending) + if (as.sortGroupAscending) { setOrder(align, seqs); } @@ -401,16 +433,18 @@ public class AlignmentSorter // Get an ordered vector of sequences which may also be present in align List tmp = order.getOrder(); - if (lastOrder == order) + AlignmentSorter as = getInstance(); + + if (as.lastOrder == order) { - sortOrderAscending = !sortOrderAscending; + as.sortOrderAscending = !as.sortOrderAscending; } else { - sortOrderAscending = true; + as.sortOrderAscending = true; } - if (sortOrderAscending) + if (as.sortOrderAscending) { setOrder(align, tmp); } @@ -473,18 +507,20 @@ public class AlignmentSorter { List tmp = getOrderByTree(align, tree); + AlignmentSorter as = getInstance(); + // tmp should properly permute align with tree. - if (lastTree != tree) + if (as.lastTree != tree) { - sortTreeAscending = true; - lastTree = tree; + as.sortTreeAscending = true; + as.lastTree = tree; } else { - sortTreeAscending = !sortTreeAscending; + as.sortTreeAscending = !as.sortTreeAscending; } - if (sortTreeAscending) + if (as.sortTreeAscending) { setOrder(align, tmp); } @@ -586,7 +622,7 @@ public class AlignmentSorter for (int i = 0; i < alignment.length; i++) { - ids[i] = (Float.valueOf(alignment[i].getName().substring(8))) + ids[i] = (new Float(alignment[i].getName().substring(8))) .floatValue(); } @@ -658,9 +694,12 @@ public class AlignmentSorter } jalview.util.QuickSort.sort(scores, seqs); - if (lastSortByAnnotation != scoreLabel) + + AlignmentSorter as = getInstance(); + + if (as.lastSortByAnnotation != scoreLabel) { - lastSortByAnnotation = scoreLabel; + as.lastSortByAnnotation = scoreLabel; setOrder(alignment, seqs); } else @@ -670,18 +709,6 @@ public class AlignmentSorter } /** - * types of feature ordering: Sort by score : average score - or total score - - * over all features in region Sort by feature label text: (or if null - - * feature type text) - numerical or alphabetical Sort by feature density: - * based on counts - ignoring individual text or scores for each feature - */ - public static String FEATURE_SCORE = "average_score"; - - public static String FEATURE_LABEL = "text"; - - public static String FEATURE_DENSITY = "density"; - - /** * Sort sequences by feature score or density, optionally restricted by * feature types, feature groups, or alignment start/end positions. *

    @@ -809,6 +836,8 @@ public class AlignmentSorter } } + boolean doSort = false; + if (FEATURE_SCORE.equals(method)) { if (hasScores == 0) @@ -834,7 +863,7 @@ public class AlignmentSorter } } } - QuickSort.sortByDouble(scores, seqs, sortByFeatureAscending); + doSort = true; } else if (FEATURE_DENSITY.equals(method)) { @@ -846,9 +875,12 @@ public class AlignmentSorter // System.err.println("Sorting on Density: seq "+seqs[i].getName()+ // " Feats: "+featureCount+" Score : "+scores[i]); } - QuickSort.sortByDouble(scores, seqs, sortByFeatureAscending); + doSort = true; + } + if (doSort) + { + QuickSort.sortByDouble(scores, seqs, getInstance().sortByFeatureAscending); } - setOrder(alignment, seqs); } @@ -883,16 +915,17 @@ public class AlignmentSorter /* * if resorting on the same criteria, toggle sort order */ - if (sortByFeatureCriteria == null - || !scoreCriteria.equals(sortByFeatureCriteria)) + AlignmentSorter as = getInstance(); + if (as.sortByFeatureCriteria == null + || !scoreCriteria.equals(as.sortByFeatureCriteria)) { - sortByFeatureAscending = true; + as.sortByFeatureAscending = true; } else { - sortByFeatureAscending = !sortByFeatureAscending; + as.sortByFeatureAscending = !as.sortByFeatureAscending; } - sortByFeatureCriteria = scoreCriteria; + as.sortByFeatureCriteria = scoreCriteria; } } diff --git a/src/jalview/analysis/Conservation.java b/src/jalview/analysis/Conservation.java index ff38c08..bd87ee8 100755 --- a/src/jalview/analysis/Conservation.java +++ b/src/jalview/analysis/Conservation.java @@ -698,7 +698,7 @@ public class Conservation max = Math.max(max, bigtot); - quality.addElement(Double.valueOf(bigtot)); + quality.addElement(new Double(bigtot)); } double newmax = -Double.MAX_VALUE; @@ -710,7 +710,7 @@ public class Conservation tmp = ((max - tmp) * (size - cons2GapCounts[j])) / size; // System.out.println(tmp+ " " + j); - quality.setElementAt(Double.valueOf(tmp), j); + quality.setElementAt(new Double(tmp), j); if (tmp > newmax) { diff --git a/src/jalview/analysis/CrossRef.java b/src/jalview/analysis/CrossRef.java index 00bb63a..dbad53e 100644 --- a/src/jalview/analysis/CrossRef.java +++ b/src/jalview/analysis/CrossRef.java @@ -31,13 +31,14 @@ import jalview.datamodel.SequenceFeature; import jalview.datamodel.SequenceI; import jalview.util.DBRefUtils; import jalview.util.MapList; -import jalview.ws.SequenceFetcherFactory; -import jalview.ws.seqfetcher.ASequenceFetcher; +import jalview.ws.SequenceFetcher; import java.util.ArrayList; import java.util.Iterator; import java.util.List; +import intervalstore.api.IntervalI; + /** * Functions for cross-referencing sequence databases. * @@ -402,7 +403,6 @@ public class CrossRef private void retrieveCrossRef(List sourceRefs, SequenceI seq, List xrfs, boolean fromDna, AlignedCodonFrame cf) { - ASequenceFetcher sftch = SequenceFetcherFactory.getSequenceFetcher(); SequenceI[] retrieved = null; SequenceI dss = seq.getDatasetSequence() == null ? seq : seq.getDatasetSequence(); @@ -418,7 +418,8 @@ public class CrossRef } try { - retrieved = sftch.getSequences(sourceRefs, !fromDna); + retrieved = SequenceFetcher.getInstance() + .getSequences(sourceRefs, !fromDna); } catch (Exception e) { System.err.println( @@ -483,7 +484,7 @@ public class CrossRef private void removeAlreadyRetrievedSeqs(List sourceRefs, boolean fromDna) { - List dbrSourceSet = new ArrayList(sourceRefs); + List dbrSourceSet = new ArrayList<>(sourceRefs); List dsSeqs = dataset.getSequences(); for (int ids = 0, nds = dsSeqs.size(); ids < nds; ids++) { @@ -638,12 +639,23 @@ public class CrossRef */ SequenceFeature newFeature = new SequenceFeature(feat) { + // BH 2019.08.15 We must override equalsInterval, not + // equals, because that is part of the IntervalI interface, + // and IntervalStore may need that for proper, faster + // processing. + // @Override + // public boolean equals(Object o) + // { + // return super.equals(o, true); + // } + // @Override - public boolean equals(Object o) + public boolean equalsInterval(IntervalI sf) { - return super.equals(o, true); + return equals((SequenceFeature) sf, true); } }; + matched.addSequenceFeature(newFeature); } } diff --git a/src/jalview/analysis/Finder.java b/src/jalview/analysis/Finder.java index 3cbef6d..3ee5be4 100644 --- a/src/jalview/analysis/Finder.java +++ b/src/jalview/analysis/Finder.java @@ -31,6 +31,7 @@ import jalview.datamodel.SequenceGroup; import jalview.datamodel.SequenceI; import jalview.datamodel.VisibleContigsIterator; import jalview.util.Comparison; +import jalview.util.Platform; import java.util.List; import java.util.Vector; @@ -129,7 +130,7 @@ public class Finder implements FinderI { String searchString = matchCase ? theSearchString : theSearchString.toUpperCase(); - Regex searchPattern = new Regex(searchString); + Regex searchPattern = Platform.newRegex(searchString, null); searchPattern.setIgnoreCase(!matchCase); searchResults = new SearchResults(); diff --git a/src/jalview/analysis/GeneticCodes.java b/src/jalview/analysis/GeneticCodes.java index 137b7f8..69a3846 100644 --- a/src/jalview/analysis/GeneticCodes.java +++ b/src/jalview/analysis/GeneticCodes.java @@ -12,13 +12,30 @@ import java.util.Map; import java.util.StringTokenizer; /** - * A singleton that provides instances of genetic code translation tables + * A static class that provides instances of genetic code translation tables * * @author gmcarstairs * @see https://www.ncbi.nlm.nih.gov/Taxonomy/Utils/wprintgc.cgi */ public final class GeneticCodes { + + /** + * As implemented, this has to be the first table defined in the data file. + */ + private static GeneticCodeI standardTable; + + /** + * + * @return the standard code table (table 1) + */ + public static GeneticCodeI getStandardCodeTable() + { + return (standardTable == null + ? standardTable = codeTables.values().iterator().next() + : standardTable); + } + private static final int CODON_LENGTH = 3; private static final String QUOTE = "\""; @@ -39,42 +56,31 @@ public final class GeneticCodes private static final String RESOURCE_FILE = "/GeneticCodes.dat"; - private static GeneticCodes instance = new GeneticCodes(); - - private Map ambiguityCodes; + private static final Map ambiguityCodes; /* * loaded code tables, with keys in order of loading */ - private Map codeTables; + private static final Map codeTables; - /** - * Private constructor enforces singleton - */ - private GeneticCodes() + static { - if (instance == null) - { - ambiguityCodes = new HashMap<>(); + ambiguityCodes = new HashMap<>(); - /* - * LinkedHashMap preserves order of addition of entries, - * so we can assume the Standard Code Table is the first - */ - codeTables = new LinkedHashMap<>(); - loadAmbiguityCodes(AMBIGUITY_CODES_FILE); - loadCodes(RESOURCE_FILE); - } + /* + * LinkedHashMap preserves order of addition of entries, + * so we can assume the Standard Code Table is the first + */ + codeTables = new LinkedHashMap<>(); + loadAmbiguityCodes(AMBIGUITY_CODES_FILE); + loadCodes(RESOURCE_FILE); } /** - * Returns the singleton instance of this class - * - * @return + * Private constructor enforces no instantiation */ - public static GeneticCodes getInstance() + private GeneticCodes() { - return instance; } /** @@ -82,41 +88,30 @@ public final class GeneticCodes * * @return */ - public Iterable getCodeTables() + public static Iterable getCodeTables() { return codeTables.values(); } /** - * Answers the code table with the given id + * Answers the code table with the given id -- test suite only * * @param id * @return */ - public GeneticCodeI getCodeTable(String id) + public static GeneticCodeI getCodeTable(String id) { return codeTables.get(id); } /** - * A convenience method that returns the standard code table (table 1). As - * implemented, this has to be the first table defined in the data file. - * - * @return - */ - public GeneticCodeI getStandardCodeTable() - { - return codeTables.values().iterator().next(); - } - - /** * Loads the code tables from a data file */ - protected void loadCodes(String fileName) + private static void loadCodes(String fileName) { try { - InputStream is = getClass().getResourceAsStream(fileName); + InputStream is = GeneticCodes.class.getResourceAsStream(fileName); if (is == null) { System.err.println("Resource file not found: " + fileName); @@ -163,11 +158,11 @@ public final class GeneticCodes * * @param fileName */ - protected void loadAmbiguityCodes(String fileName) + private static void loadAmbiguityCodes(String fileName) { try { - InputStream is = getClass().getResourceAsStream(fileName); + InputStream is = GeneticCodes.class.getResourceAsStream(fileName); if (is == null) { System.err.println("Resource file not found: " + fileName); @@ -209,7 +204,7 @@ public final class GeneticCodes * @return * @throws IOException */ - protected String readLine(BufferedReader dataIn) throws IOException + private static String readLine(BufferedReader dataIn) throws IOException { String line = dataIn.readLine(); while (line != null && line.startsWith("#")) @@ -247,7 +242,8 @@ public final class GeneticCodes * @return * @throws IOException */ - protected String loadOneTable(BufferedReader dataIn) throws IOException + private static String loadOneTable(BufferedReader dataIn) + throws IOException { String name = null; String id = null; @@ -307,7 +303,7 @@ public final class GeneticCodes * @param name * @param codons */ - protected void registerCodeTable(final String id, final String name, + private static void registerCodeTable(final String id, final String name, final Map codons) { codeTables.put(id, new GeneticCodeI() @@ -365,7 +361,7 @@ public final class GeneticCodes * @param codeTable * @return */ - protected String getAmbiguousTranslation(String codon, + protected static String getAmbiguousTranslation(String codon, Map ambiguous, GeneticCodeI codeTable) { if (codon.length() != CODON_LENGTH) @@ -423,4 +419,5 @@ public final class GeneticCodes ambiguous.put(codon, peptide); return peptide; } + } diff --git a/src/jalview/analysis/ParseProperties.java b/src/jalview/analysis/ParseProperties.java index 4b68d93..9937a47 100644 --- a/src/jalview/analysis/ParseProperties.java +++ b/src/jalview/analysis/ParseProperties.java @@ -23,6 +23,7 @@ package jalview.analysis; import jalview.datamodel.AlignmentAnnotation; import jalview.datamodel.AlignmentI; import jalview.datamodel.SequenceI; +import jalview.util.Platform; import com.stevesoft.pat.Regex; @@ -90,7 +91,7 @@ public class ParseProperties String[] ScoreDescriptions, String regex, boolean repeat) { int count = 0; - Regex pattern = new Regex(regex); + Regex pattern = Platform.newRegex(regex, null); if (pattern.numSubs() > ScoreNames.length) { // Check that we have enough labels and descriptions for any parsed @@ -134,7 +135,7 @@ public class ParseProperties double score = Double.NaN; try { - score = Double.valueOf(sstring).doubleValue(); + score = new Double(sstring).doubleValue(); } catch (Exception e) { // don't try very hard to parse if regex was wrong. diff --git a/src/jalview/analysis/SeqsetUtils.java b/src/jalview/analysis/SeqsetUtils.java index fdca89d..fabd0c6 100755 --- a/src/jalview/analysis/SeqsetUtils.java +++ b/src/jalview/analysis/SeqsetUtils.java @@ -45,8 +45,8 @@ public class SeqsetUtils { Hashtable sqinfo = new Hashtable(); sqinfo.put("Name", seq.getName()); - sqinfo.put("Start", Integer.valueOf(seq.getStart())); - sqinfo.put("End", Integer.valueOf(seq.getEnd())); + sqinfo.put("Start", new Integer(seq.getStart())); + sqinfo.put("End", new Integer(seq.getEnd())); if (seq.getDescription() != null) { sqinfo.put("Description", seq.getDescription()); diff --git a/src/jalview/analysis/StructureFrequency.java b/src/jalview/analysis/StructureFrequency.java index c04df6c..cc97be0 100644 --- a/src/jalview/analysis/StructureFrequency.java +++ b/src/jalview/analysis/StructureFrequency.java @@ -226,14 +226,14 @@ public class StructureFrequency maxResidue = "{"; } } - residueHash.put(MAXCOUNT, Integer.valueOf(count)); + residueHash.put(MAXCOUNT, new Integer(count)); residueHash.put(MAXRESIDUE, maxResidue); percentage = ((float) count * 100) / jSize; - residueHash.put(PID_GAPS, Float.valueOf(percentage)); + residueHash.put(PID_GAPS, new Float(percentage)); percentage = ((float) count * 100) / nongap; - residueHash.put(PID_NOGAPS, Float.valueOf(percentage)); + residueHash.put(PID_NOGAPS, new Float(percentage)); if (result[i] == null) { @@ -260,14 +260,14 @@ public class StructureFrequency residueHash.put(PAIRPROFILE, pairs); } - residueHash.put(MAXCOUNT, Integer.valueOf(count)); + residueHash.put(MAXCOUNT, new Integer(count)); residueHash.put(MAXRESIDUE, maxResidue); percentage = ((float) count * 100) / jSize; - residueHash.put(PID_GAPS, Float.valueOf(percentage)); + residueHash.put(PID_GAPS, new Float(percentage)); percentage = ((float) count * 100) / nongap; - residueHash.put(PID_NOGAPS, Float.valueOf(percentage)); + residueHash.put(PID_NOGAPS, new Float(percentage)); result[bpEnd] = residueHash; } diff --git a/src/jalview/analysis/scoremodels/FeatureDistanceModel.java b/src/jalview/analysis/scoremodels/FeatureDistanceModel.java index 8545e94..38217e9 100644 --- a/src/jalview/analysis/scoremodels/FeatureDistanceModel.java +++ b/src/jalview/analysis/scoremodels/FeatureDistanceModel.java @@ -55,20 +55,17 @@ public class FeatureDistanceModel extends DistanceScoreModel @Override public ScoreModelI getInstance(AlignmentViewPanel view) { - FeatureDistanceModel instance; + FeatureDistanceModel model; try { - instance = this.getClass().getDeclaredConstructor().newInstance(); - instance.configureFromAlignmentView(view); - return instance; + model = this.getClass().newInstance(); + model.configureFromAlignmentView(view); + return model; } catch (InstantiationException | IllegalAccessException e) { System.err.println("Error in " + getClass().getName() + ".getInstance(): " + e.getMessage()); return null; - } catch (ReflectiveOperationException roe) - { - return null; } } @@ -191,7 +188,7 @@ public class FeatureDistanceModel extends DistanceScoreModel protected Map> findFeatureTypesAtColumn( SeqCigar[] seqs, int columnPosition) { - Map> sfap = new HashMap<>(); + Map> sfap = new HashMap>(); for (SeqCigar seq : seqs) { int spos = seq.findPosition(columnPosition); @@ -200,7 +197,7 @@ public class FeatureDistanceModel extends DistanceScoreModel /* * position is not a gap */ - Set types = new HashSet<>(); + Set types = new HashSet(); List sfs = fr.findFeaturesAtResidue( seq.getRefSeq(), spos); for (SequenceFeature sf : sfs) diff --git a/src/jalview/analysis/scoremodels/ScoreMatrix.java b/src/jalview/analysis/scoremodels/ScoreMatrix.java index b206339..c53ecdb 100644 --- a/src/jalview/analysis/scoremodels/ScoreMatrix.java +++ b/src/jalview/analysis/scoremodels/ScoreMatrix.java @@ -54,7 +54,8 @@ public class ScoreMatrix extends SimilarityScoreModel * score matrix (JAL-2397) * Set this flag to true (via Groovy) for 2.10.1 behaviour */ - private static boolean scoreGapAsAny = false; + // BH 2019.05.08 was static but not ever set + private boolean scoreGapAsAny = false; public static final short UNMAPPED = (short) -1; diff --git a/src/jalview/analysis/scoremodels/ScoreModels.java b/src/jalview/analysis/scoremodels/ScoreModels.java index ebc9a26..8700ec0 100644 --- a/src/jalview/analysis/scoremodels/ScoreModels.java +++ b/src/jalview/analysis/scoremodels/ScoreModels.java @@ -22,6 +22,8 @@ package jalview.analysis.scoremodels; import jalview.api.AlignmentViewPanel; import jalview.api.analysis.ScoreModelI; +import jalview.bin.ApplicationSingletonProvider; +import jalview.bin.ApplicationSingletonProvider.ApplicationSingletonI; import jalview.io.DataSourceType; import jalview.io.FileParse; import jalview.io.ScoreMatrixFile; @@ -33,18 +35,8 @@ import java.util.Map; /** * A class that can register and serve instances of ScoreModelI */ -public class ScoreModels +public class ScoreModels implements ApplicationSingletonI { - private final ScoreMatrix BLOSUM62; - - private final ScoreMatrix PAM250; - - private final ScoreMatrix DNA; - - private static ScoreModels instance; - - private Map models; - /** * Answers the singleton instance of this class, with lazy initialisation * (built-in score models are loaded on the first call to this method) @@ -53,11 +45,7 @@ public class ScoreModels */ public static ScoreModels getInstance() { - if (instance == null) - { - instance = new ScoreModels(); - } - return instance; + return (ScoreModels) ApplicationSingletonProvider.getInstance(ScoreModels.class); } /** @@ -84,6 +72,14 @@ public class ScoreModels registerScoreModel(new FeatureDistanceModel()); } + private final ScoreMatrix BLOSUM62; + + private final ScoreMatrix PAM250; + + private final ScoreMatrix DNA; + + private Map models; + /** * Tries to load a score matrix from the given resource file, and if * successful, registers it. @@ -153,7 +149,7 @@ public class ScoreModels */ public void reset() { - instance = new ScoreModels(); + ApplicationSingletonProvider.removeInstance(this.getClass()); } /** diff --git a/src/jalview/analysis/scoremodels/SimilarityParams.java b/src/jalview/analysis/scoremodels/SimilarityParams.java index 5c47703..69ca4035 100644 --- a/src/jalview/analysis/scoremodels/SimilarityParams.java +++ b/src/jalview/analysis/scoremodels/SimilarityParams.java @@ -104,6 +104,7 @@ public class SimilarityParams implements SimilarityParamsI private boolean denominateByShortestLength; + /** * Constructor * @@ -124,6 +125,19 @@ public class SimilarityParams implements SimilarityParamsI denominateByShortestLength = shortestLength; } + /** + * BH added a non-Groovy "standard" set for JalviewJS + * + * @param isPCA + */ + public SimilarityParams(boolean isPCA) + { + includeGappedColumns = true; + matchGaps = !isPCA; + includeGaps = true; + denominateByShortestLength = false; + } + @Override public boolean includeGaps() { diff --git a/src/jalview/api/AlignFrameI.java b/src/jalview/api/AlignFrameI.java new file mode 100644 index 0000000..c675a6e --- /dev/null +++ b/src/jalview/api/AlignFrameI.java @@ -0,0 +1,13 @@ +package jalview.api; + +/** + * Common methods for jalview.appletgui.AlignFrame and jalview.gui.AlignFrame in + * relation to JalviewJS and the JalviewLiteJSApi + * + * @author hansonr + * + */ +public interface AlignFrameI +{ + +} diff --git a/src/jalview/api/AlignViewportI.java b/src/jalview/api/AlignViewportI.java index dcd3258..cec61f4 100644 --- a/src/jalview/api/AlignViewportI.java +++ b/src/jalview/api/AlignViewportI.java @@ -200,6 +200,12 @@ public interface AlignViewportI extends ViewStyleI * sub-groups, which may have their own colour schemes). A null value is used * for no residue colour (white). * + * BH Note: It is critical that any call to + * AlignViewportI.setGlobalColourScheme is followed closely, if not + * immediately, by a call to AlignPanel.repaint(true, true) so that the + * overview is updated. When that happens, the sequence overview color caches + * are cleared. + * * @param cs */ void setGlobalColourScheme(ColourSchemeI cs); diff --git a/src/jalview/api/AlignmentColsCollectionI.java b/src/jalview/api/AlignmentColsCollectionI.java index 06b1675..70dda87 100644 --- a/src/jalview/api/AlignmentColsCollectionI.java +++ b/src/jalview/api/AlignmentColsCollectionI.java @@ -20,6 +20,8 @@ */ package jalview.api; +import java.util.BitSet; + public interface AlignmentColsCollectionI extends Iterable { /** @@ -37,4 +39,20 @@ public interface AlignmentColsCollectionI extends Iterable * @return true if there is at least 1 hidden column */ public boolean hasHidden(); + + /** + * Get the visible-column bitset, possibly containing hidden columns (which + * may or may not be hidden in the overview). + * + * @return a BitSet + */ + public BitSet getOverviewBitSet(); + + /** + * Get the hidden-column bitset, (which may or may not be hidden in the + * overview). + * + * @return + */ + BitSet getHiddenBitSet(); } diff --git a/src/jalview/api/AlignmentViewPanel.java b/src/jalview/api/AlignmentViewPanel.java index 0b1ca21..9593a5b 100644 --- a/src/jalview/api/AlignmentViewPanel.java +++ b/src/jalview/api/AlignmentViewPanel.java @@ -23,6 +23,8 @@ package jalview.api; import jalview.datamodel.AlignmentI; import jalview.structure.StructureSelectionManager; +import java.awt.image.BufferedImage; + /** * abstract interface implemented by alignment panels holding an alignment view * @@ -63,4 +65,9 @@ public interface AlignmentViewPanel extends OOMHandlerI * @return displayed name for the view */ String getViewName(); + + SequenceRenderer getSequenceRenderer(); + + void overviewDone(BufferedImage miniMe); + } diff --git a/src/jalview/api/FeatureColourI.java b/src/jalview/api/FeatureColourI.java index 7bfd8a8..c5f6727 100644 --- a/src/jalview/api/FeatureColourI.java +++ b/src/jalview/api/FeatureColourI.java @@ -64,10 +64,9 @@ public interface FeatureColourI Color getNoColour(); /** - * Answers true if the feature has a single colour, i.e. if isColourByLabel() - * and isGraduatedColour() both answer false + * Answers true if the feature has a single colour * - * @return + * @return true iff not (isColourByLabel() || isGraduatedColour()) */ boolean isSimpleColour(); diff --git a/src/jalview/api/FeatureRenderer.java b/src/jalview/api/FeatureRenderer.java index 404c497..6caa1c7 100644 --- a/src/jalview/api/FeatureRenderer.java +++ b/src/jalview/api/FeatureRenderer.java @@ -125,7 +125,7 @@ public interface FeatureRenderer List getFeatureGroups(); /** - * get groups that are visible/invisible + * get groups that are visible/invisible -- JalviewLite only? * * @param visible * @return @@ -133,7 +133,7 @@ public interface FeatureRenderer List getGroups(boolean visible); /** - * Set visibility for a list of groups + * Set visibility for a list of groups -- JalviewLite only? * * @param toset * @param visible diff --git a/src/jalview/api/JalviewApp.java b/src/jalview/api/JalviewApp.java new file mode 100644 index 0000000..0548c85 --- /dev/null +++ b/src/jalview/api/JalviewApp.java @@ -0,0 +1,82 @@ +package jalview.api; + +import jalview.datamodel.ColumnSelection; +import jalview.datamodel.HiddenColumns; +import jalview.datamodel.PDBEntry; +import jalview.datamodel.SequenceGroup; +import jalview.datamodel.SequenceI; +import jalview.io.DataSourceType; +import jalview.io.NewickFile; +import jalview.javascript.JSFunctionExec; +import jalview.javascript.MouseOverStructureListener; +import jalview.structure.SelectionSource; +import jalview.structure.VamsasSource; + +import java.applet.AppletContext; +import java.io.IOException; +import java.net.URL; +import java.util.Hashtable; +import java.util.Vector; + +import netscape.javascript.JSObject; + +public interface JalviewApp +{ + public String getParameter(String name); + + public boolean getDefaultParameter(String name, boolean def); + + public URL getDocumentBase(); + + public URL getCodeBase(); + + public void setAlignPdbStructures(boolean defaultParameter); + + public void newStructureView(PDBEntry pdb, SequenceI[] seqs, + String[] chains, DataSourceType protocol); + + public void alignedStructureView(PDBEntry[] pdb, SequenceI[][] seqs, + String[][] chains, String[] protocols); + + public void updateForAnnotations(); + + public AlignViewportI getViewport(); + + public void setFeatureGroupState(String[] groups, boolean state); + + public boolean parseFeaturesFile(String param, DataSourceType protocol); + + public void newFeatureSettings(); + + public boolean loadScoreFile(String sScoreFile) throws IOException; + + public void loadTree(NewickFile fin, String treeFile) throws IOException; + + public Vector getJsExecQueue(JSFunctionExec jsFunctionExec); + + public AppletContext getAppletContext(); + + public boolean isJsfallbackEnabled(); + + public JSObject getJSObject(); + + public StructureSelectionManagerProvider getStructureSelectionManagerProvider(); + + public void updateColoursFromMouseOver(Object source, + MouseOverStructureListener mouseOverStructureListener); + + public Object[] getSelectionForListener(SequenceGroup seqsel, ColumnSelection colsel, + HiddenColumns hidden, SelectionSource source, Object alignFrame); + + public String arrayToSeparatorList(String[] array); + + public Hashtable getJSHashes(); + + Hashtable> getJSMessages(); + + public Object getFrameForSource(VamsasSource source); + + public jalview.renderer.seqfeatures.FeatureRenderer getNewFeatureRenderer( + AlignViewportI vp); + +} diff --git a/src/jalview/appletgui/AlignFrame.java b/src/jalview/appletgui/AlignFrame.java index f3fdd67..062dbf8 100644 --- a/src/jalview/appletgui/AlignFrame.java +++ b/src/jalview/appletgui/AlignFrame.java @@ -25,6 +25,7 @@ import jalview.analysis.AnnotationSorter.SequenceAnnotationOrder; import jalview.analysis.TreeBuilder; import jalview.analysis.scoremodels.PIDModel; import jalview.analysis.scoremodels.ScoreModels; +import jalview.api.AlignFrameI; import jalview.api.AlignViewControllerGuiI; import jalview.api.AlignViewControllerI; import jalview.api.AlignViewportI; @@ -106,7 +107,6 @@ import java.awt.event.KeyListener; import java.awt.event.WindowAdapter; import java.awt.event.WindowEvent; import java.io.IOException; -import java.io.UnsupportedEncodingException; import java.net.URL; import java.net.URLEncoder; import java.util.Arrays; @@ -119,7 +119,8 @@ import java.util.Vector; import org.jmol.viewer.Viewer; -public class AlignFrame extends EmbmenuFrame implements ActionListener, +public class AlignFrame extends EmbmenuFrame implements AlignFrameI, + ActionListener, ItemListener, KeyListener, AlignViewControllerGuiI { public AlignViewControllerI avc; @@ -881,7 +882,7 @@ public class AlignFrame extends EmbmenuFrame implements ActionListener, } else if (source == autoCalculate) { - viewport.autoCalculateConsensus = autoCalculate.getState(); + viewport.setAutoCalculateConsensusAndConservation(autoCalculate.getState()); } else if (source == sortByTree) { @@ -1570,7 +1571,7 @@ public class AlignFrame extends EmbmenuFrame implements ActionListener, try { new URL(url); - url = URLEncoder.encode(url, "UTF-8"); + url = URLEncoder.encode(url); } /* * When we finally deprecate 1.1 compatibility, we can start to use @@ -1583,13 +1584,6 @@ public class AlignFrame extends EmbmenuFrame implements ActionListener, { url = viewport.applet.getCodeBase() + url; } - catch (UnsupportedEncodingException ex) - { - System.err.println( - "WARNING = IMPLEMENTATION ERROR - UNSUPPORTED ENCODING EXCEPTION FOR " - + url); - ex.printStackTrace(); - } return url; } diff --git a/src/jalview/appletgui/AlignViewport.java b/src/jalview/appletgui/AlignViewport.java index 0727673..2bead46 100644 --- a/src/jalview/appletgui/AlignViewport.java +++ b/src/jalview/appletgui/AlignViewport.java @@ -71,7 +71,7 @@ public class AlignViewport extends AlignmentViewport { try { - widthScale = Float.valueOf(param).floatValue(); + widthScale = new Float(param).floatValue(); } catch (Exception e) { } @@ -94,7 +94,7 @@ public class AlignViewport extends AlignmentViewport { try { - heightScale = Float.valueOf(param).floatValue(); + heightScale = new Float(param).floatValue(); } catch (Exception e) { } diff --git a/src/jalview/appletgui/AlignmentPanel.java b/src/jalview/appletgui/AlignmentPanel.java index 58569cd..df8fe87 100644 --- a/src/jalview/appletgui/AlignmentPanel.java +++ b/src/jalview/appletgui/AlignmentPanel.java @@ -43,6 +43,7 @@ import java.awt.event.AdjustmentEvent; import java.awt.event.AdjustmentListener; import java.awt.event.ComponentAdapter; import java.awt.event.ComponentEvent; +import java.awt.image.BufferedImage; import java.beans.PropertyChangeEvent; import java.util.List; @@ -178,6 +179,7 @@ public class AlignmentPanel extends Panel return av; } + @Override public SequenceRenderer getSequenceRenderer() { return seqPanel.seqCanvas.sr; @@ -1158,4 +1160,10 @@ public class AlignmentPanel extends Panel } + @Override + public void overviewDone(BufferedImage miniMe) + { + overviewPanel.canvas.finalizeDraw(miniMe); + } + } diff --git a/src/jalview/appletgui/AnnotationColourChooser.java b/src/jalview/appletgui/AnnotationColourChooser.java index 9456986..6eca05e 100644 --- a/src/jalview/appletgui/AnnotationColourChooser.java +++ b/src/jalview/appletgui/AnnotationColourChooser.java @@ -22,6 +22,7 @@ package jalview.appletgui; import jalview.datamodel.AlignmentAnnotation; import jalview.datamodel.SequenceGroup; +import jalview.gui.Preferences; import jalview.schemes.AnnotationColourGradient; import jalview.schemes.ColourSchemeI; import jalview.util.MessageManager; @@ -217,9 +218,9 @@ public class AnnotationColourChooser extends Panel implements private void setDefaultMinMax() { minColour.setBackground(av.applet.getDefaultColourParameter( - "ANNOTATIONCOLOUR_MIN", Color.orange)); + Preferences.ANNOTATIONCOLOUR_MIN, Color.orange)); maxColour.setBackground(av.applet - .getDefaultColourParameter("ANNOTATIONCOLOUR_MAX", Color.red)); + .getDefaultColourParameter(Preferences.ANNOTATIONCOLOUR_MAX, Color.red)); } @@ -350,7 +351,7 @@ public class AnnotationColourChooser extends Panel implements { try { - float f = Float.valueOf(thresholdValue.getText()).floatValue(); + float f = new Float(thresholdValue.getText()).floatValue(); slider.setValue((int) (f * 1000)); adjustmentValueChanged(null); } catch (NumberFormatException ex) diff --git a/src/jalview/appletgui/AnnotationLabels.java b/src/jalview/appletgui/AnnotationLabels.java index a0102b9..1366f31 100755 --- a/src/jalview/appletgui/AnnotationLabels.java +++ b/src/jalview/appletgui/AnnotationLabels.java @@ -457,8 +457,8 @@ public class AnnotationLabels extends Panel .getAlignmentAnnotation(); // DETECT RIGHT MOUSE BUTTON IN AWT - if ((evt.getModifiersEx() - & InputEvent.BUTTON3_DOWN_MASK) == InputEvent.BUTTON3_DOWN_MASK) + if ((evt.getModifiers() + & InputEvent.BUTTON3_MASK) == InputEvent.BUTTON3_MASK) { PopupMenu popup = new PopupMenu( diff --git a/src/jalview/appletgui/AnnotationPanel.java b/src/jalview/appletgui/AnnotationPanel.java index 3dae998..26d3a3b 100755 --- a/src/jalview/appletgui/AnnotationPanel.java +++ b/src/jalview/appletgui/AnnotationPanel.java @@ -354,8 +354,8 @@ public class AnnotationPanel extends Panel } } - if ((evt.getModifiersEx() - & InputEvent.BUTTON3_DOWN_MASK) == InputEvent.BUTTON3_DOWN_MASK + if ((evt.getModifiers() + & InputEvent.BUTTON3_MASK) == InputEvent.BUTTON3_MASK && activeRow != -1) { if (av.getColumnSelection() == null diff --git a/src/jalview/appletgui/EmbmenuFrame.java b/src/jalview/appletgui/EmbmenuFrame.java index 0edb8c0..b6b81fa 100644 --- a/src/jalview/appletgui/EmbmenuFrame.java +++ b/src/jalview/appletgui/EmbmenuFrame.java @@ -52,8 +52,7 @@ import java.util.Map; * */ @SuppressWarnings("serial") -public class EmbmenuFrame extends Frame - implements MouseListener, AutoCloseable +public class EmbmenuFrame extends Frame implements MouseListener { protected static final Font FONT_ARIAL_PLAIN_11 = new Font("Arial", Font.PLAIN, 11); @@ -63,7 +62,7 @@ public class EmbmenuFrame extends Frame /** * map from labels to popup menus for the embedded menubar */ - protected Map embeddedPopup = new HashMap<>(); + protected Map embeddedPopup = new HashMap(); /** * the embedded menu is built on this and should be added to the frame at the @@ -203,7 +202,6 @@ public class EmbmenuFrame extends Frame return embeddedMenu; } - @Override public void mousePressed(MouseEvent evt) { PopupMenu popup = null; @@ -228,22 +226,18 @@ public class EmbmenuFrame extends Frame return embeddedPopup.get(source); } - @Override public void mouseClicked(MouseEvent evt) { } - @Override public void mouseReleased(MouseEvent evt) { } - @Override public void mouseEntered(MouseEvent evt) { } - @Override public void mouseExited(MouseEvent evt) { } @@ -271,13 +265,11 @@ public class EmbmenuFrame extends Frame /** * calls destroyMenus() */ - @Override - public void close() + public void finalize() throws Throwable { destroyMenus(); embeddedPopup = null; embeddedMenu = null; - // no close for Frame - // super.finalize(); + super.finalize(); } } diff --git a/src/jalview/appletgui/FeatureColourChooser.java b/src/jalview/appletgui/FeatureColourChooser.java index 0d70660..5569ab0 100644 --- a/src/jalview/appletgui/FeatureColourChooser.java +++ b/src/jalview/appletgui/FeatureColourChooser.java @@ -311,7 +311,7 @@ public class FeatureColourChooser extends Panel implements ActionListener, { try { - float f = Float.valueOf(thresholdValue.getText()).floatValue(); + float f = new Float(thresholdValue.getText()).floatValue(); slider.setValue((int) (f * SCALE_FACTOR_1K)); adjustmentValueChanged(null); diff --git a/src/jalview/appletgui/FeatureSettings.java b/src/jalview/appletgui/FeatureSettings.java index 489cbb1..a60aacd 100755 --- a/src/jalview/appletgui/FeatureSettings.java +++ b/src/jalview/appletgui/FeatureSettings.java @@ -703,7 +703,7 @@ public class FeatureSettings extends Panel public void mouseClicked(MouseEvent evt) { MyCheckbox check = (MyCheckbox) evt.getSource(); - if ((evt.getModifiersEx() & InputEvent.BUTTON3_DOWN_MASK) != 0) + if ((evt.getModifiers() & InputEvent.BUTTON3_MASK) != 0) { this.popupSort(check, fr.getMinMax(), evt.getX(), evt.getY()); } diff --git a/src/jalview/appletgui/FontChooser.java b/src/jalview/appletgui/FontChooser.java index 8b74e32..443ebce 100644 --- a/src/jalview/appletgui/FontChooser.java +++ b/src/jalview/appletgui/FontChooser.java @@ -31,9 +31,9 @@ import java.awt.FlowLayout; import java.awt.Font; import java.awt.FontMetrics; import java.awt.Frame; -import java.awt.GraphicsEnvironment; import java.awt.Label; import java.awt.Panel; +import java.awt.Toolkit; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.awt.event.ItemEvent; @@ -144,9 +144,7 @@ public class FontChooser extends Panel implements ItemListener */ void init() { - // String fonts[] = Toolkit.getDefaultToolkit().getFontList(); - String fonts[] = GraphicsEnvironment.getLocalGraphicsEnvironment() - .getAvailableFontFamilyNames(); + String fonts[] = Toolkit.getDefaultToolkit().getFontList(); for (int i = 0; i < fonts.length; i++) { fontName.addItem(fonts[i]); diff --git a/src/jalview/appletgui/IdPanel.java b/src/jalview/appletgui/IdPanel.java index 1d37d08..af1c47b 100755 --- a/src/jalview/appletgui/IdPanel.java +++ b/src/jalview/appletgui/IdPanel.java @@ -279,8 +279,8 @@ public class IdPanel extends Panel int seq = alignPanel.seqPanel.findSeq(e); - if ((e.getModifiersEx() - & InputEvent.BUTTON3_DOWN_MASK) == InputEvent.BUTTON3_DOWN_MASK) + if ((e.getModifiers() + & InputEvent.BUTTON3_MASK) == InputEvent.BUTTON3_MASK) { SequenceI sq = av.getAlignment().getSequenceAt(seq); diff --git a/src/jalview/appletgui/OverviewCanvas.java b/src/jalview/appletgui/OverviewCanvas.java index 07f5919..7f4e962 100644 --- a/src/jalview/appletgui/OverviewCanvas.java +++ b/src/jalview/appletgui/OverviewCanvas.java @@ -30,7 +30,9 @@ import java.awt.Dimension; import java.awt.Frame; import java.awt.Graphics; import java.awt.Image; +import java.awt.image.BufferedImage; +@SuppressWarnings("serial") public class OverviewCanvas extends Component { // This is set true if the alignment view changes whilst @@ -49,13 +51,23 @@ public class OverviewCanvas extends Component private AlignViewport av; + private boolean showSequenceFeatures; + + private boolean showAnnotation; + + private jalview.api.FeatureRenderer featureRenderer; + private jalview.renderer.seqfeatures.FeatureRenderer fr; private Frame nullFrame; - public OverviewCanvas(OverviewDimensions overviewDims, + private OverviewPanel panel; + + public OverviewCanvas(OverviewPanel panel, + OverviewDimensions overviewDims, AlignViewport alignvp) { + this.panel = panel; od = overviewDims; av = alignvp; @@ -101,46 +113,23 @@ public class OverviewCanvas extends Component } public void draw(boolean showSequenceFeatures, boolean showAnnotation, - FeatureRenderer transferRenderer) + jalview.api.FeatureRenderer featureRenderer) { - miniMe = null; + this.showSequenceFeatures = showSequenceFeatures; + this.showAnnotation = showAnnotation; + this.featureRenderer = featureRenderer; if (showSequenceFeatures) { - fr.transferSettings(transferRenderer); + fr.transferSettings(featureRenderer); } setPreferredSize(new Dimension(od.getWidth(), od.getHeight())); - or = new OverviewRenderer(fr, od, av.getAlignment(), + or = new OverviewRenderer(panel.ap, fr, od, av.getAlignment(), av.getResidueShading(), new OverviewResColourFinder()); - miniMe = nullFrame.createImage(od.getWidth(), od.getHeight()); offscreen = nullFrame.createImage(od.getWidth(), od.getHeight()); - - miniMe = or.draw(od.getRows(av.getAlignment()), - od.getColumns(av.getAlignment())); - - Graphics mg = miniMe.getGraphics(); - - // checks for conservation annotation to make sure overview works for DNA - // too - if (showAnnotation) - { - mg.translate(0, od.getSequencesHeight()); - or.drawGraph(mg, av.getAlignmentConservationAnnotation(), - od.getGraphHeight(), od.getColumns(av.getAlignment())); - mg.translate(0, -od.getSequencesHeight()); - } - - if (restart) - { - restart = false; - draw(showSequenceFeatures, showAnnotation, transferRenderer); - } - else - { - updaterunning = false; - } + or.drawMiniMe(); } @Override @@ -152,13 +141,14 @@ public class OverviewCanvas extends Component @Override public void paint(Graphics g) { - Graphics og = offscreen.getGraphics(); if (miniMe != null) { + Graphics og = offscreen.getGraphics(); og.drawImage(miniMe, 0, 0, this); og.setColor(Color.red); od.drawBox(og); g.drawImage(offscreen, 0, 0, this); + og.dispose(); } } @@ -170,4 +160,25 @@ public class OverviewCanvas extends Component od = null; } + public void finalizeDraw(BufferedImage miniMe) + { + if (restart) + { + restart = false; + draw(showSequenceFeatures, showAnnotation, featureRenderer); + } + else + { + this.miniMe = miniMe; + // checks for conservation annotation to make sure overview works for DNA + // too + if (showAnnotation) + { + or.drawGraph(av.getAlignmentConservationAnnotation()); + } + updaterunning = false; + repaint(); + } + } + } diff --git a/src/jalview/appletgui/OverviewPanel.java b/src/jalview/appletgui/OverviewPanel.java index ddb49f1..328841c 100755 --- a/src/jalview/appletgui/OverviewPanel.java +++ b/src/jalview/appletgui/OverviewPanel.java @@ -46,16 +46,17 @@ import java.beans.PropertyChangeEvent; import javax.swing.SwingUtilities; +@SuppressWarnings("serial") public class OverviewPanel extends Panel implements Runnable, MouseMotionListener, MouseListener, ViewportListenerI { - private OverviewDimensions od; + OverviewDimensions od; - private OverviewCanvas oviewCanvas; + OverviewCanvas canvas; private AlignViewport av; - private AlignmentPanel ap; + AlignmentPanel ap; private boolean showHidden = true; @@ -73,9 +74,9 @@ public class OverviewPanel extends Panel implements Runnable, (av.isShowAnnotation() && av.getSequenceConsensusHash() != null)); - oviewCanvas = new OverviewCanvas(od, av); + canvas = new OverviewCanvas(this, od, av); setLayout(new BorderLayout()); - add(oviewCanvas, BorderLayout.CENTER); + add(canvas, BorderLayout.CENTER); setSize(new Dimension(od.getWidth(), od.getHeight())); @@ -116,8 +117,8 @@ public class OverviewPanel extends Panel implements Runnable, @Override public void mouseClicked(MouseEvent evt) { - if ((evt.getModifiersEx() - & InputEvent.BUTTON3_DOWN_MASK) == InputEvent.BUTTON3_DOWN_MASK) + if ((evt.getModifiers() + & InputEvent.BUTTON3_MASK) == InputEvent.BUTTON3_MASK) { showPopupMenu(evt); } @@ -142,8 +143,8 @@ public class OverviewPanel extends Panel implements Runnable, @Override public void mousePressed(MouseEvent evt) { - if ((evt.getModifiersEx() - & InputEvent.BUTTON3_DOWN_MASK) == InputEvent.BUTTON3_DOWN_MASK) + if ((evt.getModifiers() + & InputEvent.BUTTON3_MASK) == InputEvent.BUTTON3_MASK) { if (!Platform.isMac()) // BH was excluding JavaScript { @@ -187,14 +188,10 @@ public class OverviewPanel extends Panel implements Runnable, @Override public void mouseDragged(MouseEvent evt) { - if (Platform.isWinRightButton(evt)) + if (Platform.isWinRightButton(evt)) { - if ((evt.getModifiersEx() - & InputEvent.BUTTON3_DOWN_MASK) == InputEvent.BUTTON3_DOWN_MASK) - { - showPopupMenu(evt); - return; - } + showPopupMenu(evt); + return; } if (SwingUtilities.isRightMouseButton(evt)) @@ -224,7 +221,7 @@ public class OverviewPanel extends Panel implements Runnable, */ public void updateOverviewImage() { - if (oviewCanvas == null) + if (canvas == null) { /* * panel has been disposed @@ -243,7 +240,7 @@ public class OverviewPanel extends Panel implements Runnable, { if (updateRunning) { - oviewCanvas.restartDraw(); + canvas.restartDraw(); return; } @@ -258,11 +255,11 @@ public class OverviewPanel extends Panel implements Runnable, @Override public void run() { - oviewCanvas.draw(av.isShowSequenceFeatures(), + setBoxPosition(); + canvas.draw(av.isShowSequenceFeatures(), (av.isShowAnnotation() && av.getAlignmentConservationAnnotation() != null), ap.seqPanel.seqCanvas.getFeatureRenderer()); - setBoxPosition(); } /** @@ -325,7 +322,7 @@ public class OverviewPanel extends Panel implements Runnable, (av.isShowAnnotation() && av.getAlignmentConservationAnnotation() != null)); } - oviewCanvas.resetOviewDims(od); + canvas.resetOviewDims(od); updateOverviewImage(); } @@ -343,11 +340,11 @@ public class OverviewPanel extends Panel implements Runnable, } finally { av = null; - if (oviewCanvas != null) + if (canvas != null) { - oviewCanvas.dispose(); + canvas.dispose(); } - oviewCanvas = null; + canvas = null; ap = null; od = null; } diff --git a/src/jalview/appletgui/ScalePanel.java b/src/jalview/appletgui/ScalePanel.java index d3f4a69..c91449f 100755 --- a/src/jalview/appletgui/ScalePanel.java +++ b/src/jalview/appletgui/ScalePanel.java @@ -96,8 +96,8 @@ public class ScalePanel extends Panel min = res; max = res; - if ((evt.getModifiersEx() - & InputEvent.BUTTON3_DOWN_MASK) == InputEvent.BUTTON3_DOWN_MASK) + if ((evt.getModifiers() + & InputEvent.BUTTON3_MASK) == InputEvent.BUTTON3_MASK) { rightMouseButtonPressed(evt, res); } diff --git a/src/jalview/appletgui/SeqPanel.java b/src/jalview/appletgui/SeqPanel.java index 5becbc1..32f0abb 100644 --- a/src/jalview/appletgui/SeqPanel.java +++ b/src/jalview/appletgui/SeqPanel.java @@ -500,6 +500,7 @@ public class SeqPanel extends Panel implements MouseMotionListener, // For now, ignore the mouseWheel font resizing on Macs // As the Button2_mask always seems to be true + if (Platform.isWinMiddleButton(evt)) { mouseWheelPressed = true; @@ -1431,8 +1432,8 @@ public class SeqPanel extends Panel implements MouseMotionListener, } // DETECT RIGHT MOUSE BUTTON IN AWT - if ((evt.getModifiersEx() - & InputEvent.BUTTON3_DOWN_MASK) == InputEvent.BUTTON3_DOWN_MASK) + if ((evt.getModifiers() + & InputEvent.BUTTON3_MASK) == InputEvent.BUTTON3_MASK) { List allFeatures = findFeaturesAtColumn(sequence, sequence.findPosition(column + 1)); diff --git a/src/jalview/appletgui/TreePanel.java b/src/jalview/appletgui/TreePanel.java index 671fee1..b5e3342 100644 --- a/src/jalview/appletgui/TreePanel.java +++ b/src/jalview/appletgui/TreePanel.java @@ -46,7 +46,7 @@ import java.awt.event.ItemEvent; import java.awt.event.ItemListener; public class TreePanel extends EmbmenuFrame - implements ActionListener, ItemListener, AutoCloseable + implements ActionListener, ItemListener { SequenceI[] seq; @@ -72,11 +72,11 @@ public class TreePanel extends EmbmenuFrame } @Override - public void close() + public void finalize() throws Throwable { ap = null; av = null; - super.close(); + super.finalize(); } /** diff --git a/src/jalview/bin/AppletParams.java b/src/jalview/bin/AppletParams.java new file mode 100644 index 0000000..6a23c39 --- /dev/null +++ b/src/jalview/bin/AppletParams.java @@ -0,0 +1,447 @@ +package jalview.bin; + +import jalview.gui.Preferences; + +import java.util.HashMap; +import java.util.Map; +import java.util.Vector; + +/** + * Collection of all known applet tags from JalviewLite + * + * @author hansonr + * + */ +@SuppressWarnings("serial") +public class AppletParams extends HashMap +{ + + private final static String[] params = { "alignpdbfiles", + Preferences.ANNOTATIONCOLOUR_MAX, Preferences.ANNOTATIONCOLOUR_MIN, + "annotations", + "APPLICATION_URL", "automaticScrolling", "centrecolumnlabels", + "debug", "defaultColour", "defaultColourNuc", "defaultColourProt", + "embedded", "enableSplitFrame", "externalstructureviewer", "features", + "file", "file2", "format", "heightScale", "hidefeaturegroups", + "jalviewhelpurl", "jnetfile", "jpredfile", "label", "linkLabel_", + "linkLabel_1", "linkURL_", "nojmol", "normaliseLogo", + "normaliseSequenceLogo", "oninit", "PDBFILE", "PDBSEQ", + "relaxedidmatch", "resolvetocodebase", "RGB", "scaleProteinAsCdna", + "scoreFile", "separator", "sequence", "showAnnotation", "showbutton", + "showConsensus", "showConsensusHistogram", "showConservation", + "showfeaturegroups", "showFeatureSettings", "showFullId", + "showGroupConsensus", "showGroupConservation", "showOccupancy", + "showQuality", "showSequenceLogo", "showTreeBootstraps", + "showTreeDistances", "showUnconserved", "showUnlinkedTreeNodes", + "sortBy", "sortByTree", "tree", "treeFile", "upperCase", + "userDefinedColour", "widthScale", "windowHeight", "windowWidth", + "wrap", }; + + public AppletParams(Map info) + { + for (int i = params.length; --i >= 0;) + { + put(params[i], info.get(params[i])); + } + } + + public String getParam(String param, String def) + { + String val = get(param); + return (val != null ? val : def); + } + + // + // + // + // + // + // + // + // + // + // + // + // + // + // + // + // + public AppletParams(String outerHTML) + { + String[] tokens = outerHTML.split(" 0;) + { + String param = tokens[i]; + String key = getAttr(param, "name"); + if (key != null) + { + String value = getAttr(param, "value"); + System.out.println("AppletParams " + key + " = \"" + value + "\""); + put(key, value); + } + } + put("_width", getAttr(outerHTML, "width")); + put("_height", getAttr(outerHTML, "height")); + put("_id", getAttr(outerHTML, "id")); + put("_name", getAttr(outerHTML, "name")); + put("_archive", getAttr(outerHTML, "archive")); + put("_code", code); + } + + public AppletParams() + { + // TODO Auto-generated constructor stub + } + + public static AppletParams getAppletParams(String[] args, + Vector vargs) + { + AppletParams appletParams = new AppletParams(); + String resourcePath = null; + for (int i = args.length; --i > 0;) // > 0 is correct, not >=0 + { + if (args[i].startsWith("name=\"Info.resourcePath\"")) + { + resourcePath = getAttr(args[i], "value"); + if (resourcePath.length() > 0 && !resourcePath.endsWith("/")) + { + resourcePath += "/"; + } + break; + } + } + for (int i = 1; i < args.length; i++) + { + String arg = args[i].trim(); + if (arg.startsWith("name=")) + { + String prefName = getAttr(arg, "name"); + String appletName = prefName.toLowerCase(); + String argName = prefName; + String value = getAttr(arg, "value"); + + // note that Application arguments ARE case-sensitive, but + // Applet.getParameter() is not. + + switch (appletName) + { + + case "file": + argName = "open"; + appletName = null; + value = resourcePath + value; + break; + case "file2": + argName = "open2"; + prefName = null; + value = resourcePath + value; + break; + case "features": + case "jnetfile": + case "jpredfile": + case "pdbfile": + case "scorefile": + case "sequence": + // setting argName to null indicates that we want + // JalviewAppLoader to take care of this. + prefName = argName = null; + value = resourcePath + value; + break; + case "tree": + case "treefile": + // setting appletName to null indicates that we want + // Jalview.doMain to taken care of this as Jalview args + argName = "tree"; + appletName = null; + value = resourcePath + value; + break; + + // non-loading preferences + + case "defaultcolour": + prefName = Preferences.DEFAULT_COLOUR; + break; + case "defaultcolournuc": + prefName = Preferences.DEFAULT_COLOUR_NUC; + break; + case "defaultcolourprot": + prefName = Preferences.DEFAULT_COLOUR_PROT; + break; + case "annotationcolour_max": + prefName = Preferences.ANNOTATIONCOLOUR_MAX; + break; + case "annotationcolour_min": + prefName = Preferences.ANNOTATIONCOLOUR_MIN; + break; + case "enablesplitframe": + prefName = Preferences.ENABLE_SPLIT_FRAME; + break; + case "centrecolumnlabels": + prefName = Preferences.CENTRE_COLUMN_LABELS; + break; + case "sortby": + prefName = Preferences.SORT_ALIGNMENT; // id, etc. + break; + case "normalisesequencelogo": + prefName = Preferences.NORMALISE_CONSENSUS_LOGO; + break; + case "relaxedidmatch": + prefName = Preferences.RELAXEDSEQIDMATCHING; + break; + case "scaleproteinascdna": + prefName = Preferences.SCALE_PROTEIN_TO_CDNA; + break; + case "userdefinedcolour": + argName = "colour"; + prefName = Preferences.USER_DEFINED_COLOURS; + break; + case "wrap": + prefName = Preferences.WRAP_ALIGNMENT; + break; + + // implemented; not tested: + + case "oninit": + prefName = null; + break; + case "annotations": + value = resourcePath + value; + argName = null; + break; + case "hidefeaturegroups": + // TODO + break; + case "pdbseq": + argName = prefName = null; + break; + case "sortbytree": + prefName = Preferences.SORT_BY_TREE; + value = checkTF(value); + appletName = null; // taken care of by Jalview + break; + case "format": + break; + case "alignpdbfiles": + argName = prefName = null; + break; + case "separator": + break; + + // TODO: probably not relevant? + + case "rgb": + prefName = null; // TODO no background for application? + break; + case "externalstructureviewer": + break; + case "application_url": + break; + case "automaticscrolling": + break; + case "heightscale": + break; + case "jalviewhelpurl": + break; + case "label": + break; + case "linklabel_": + prefName = "linkLabel_"; + break; + case "linklabel_1": + prefName = "linkLabel_1"; + break; + case "linkurl_": + prefName = "linkURL_"; + break; + + // unknown: + + case "nojmol": + case "normaliselogo": + case "resolvetocodebase": + case "uppercase": + case "widthscale": + case "windowheight": + case "windowwidth": + argName = prefName = null; + break; + + // TRUE/FALSE + + case "debug": + value = checkTF(value); + break; + case "embedded": + value = checkTF(value); + break; + case "showbutton": + value = checkTF(value); + break; + case "showannotation": + prefName = Preferences.SHOW_ANNOTATIONS; + value = checkTF(value); + break; + case "showconsensus": + prefName = Preferences.SHOW_CONSENSUS_LOGO; + value = checkTF(value); + break; + case "showconsensushistogram": + prefName = Preferences.SHOW_CONSENSUS_HISTOGRAM; + value = checkTF(value); + break; + case "showconservation": + prefName = Preferences.SHOW_CONSERVATION; + value = checkTF(value); + break; + case "showgroupconsensus": + prefName = Preferences.SHOW_GROUP_CONSENSUS; + value = checkTF(value); + break; + case "showgroupconservation": + prefName = Preferences.SHOW_GROUP_CONSERVATION; + value = checkTF(value); + break; + case "showoccupancy": + prefName = Preferences.SHOW_OCCUPANCY; + value = checkTF(value); + break; + case "showquality": + prefName = Preferences.SHOW_QUALITY; + value = checkTF(value); + break; + case "showsequencelogo": + prefName = Preferences.SHOW_CONSENSUS_LOGO; + value = checkTF(value); + break; + case "showfeaturegroups": + value = checkTF(value); + break; + case "showfeaturesettings": + value = checkTF(value); + break; + case "showfullid": + value = checkTF(value); + break; + case "showtreebootstraps": + value = checkTF(value); + break; + case "showtreedistances": + value = checkTF(value); + break; + case "showunconserved": + prefName = Preferences.SHOW_UNCONSERVED; + value = checkTF(value); + break; + case "showunlinkedtreenodes": + value = checkTF(value); + break; + default: + if (appletName.startsWith("pdbfile") + || appletName.startsWith("sequence") && Character.isDigit( + appletName.charAt(appletName.length() - 1))) + { + // could be pdbFile2, for example + prefName = argName = null; + value = resourcePath + value; + break; + } + // or one of the app preference names + break; + } + // put name and value into application args + if (value != null && argName != null) + { + vargs.add(argName); + if (value != "true") + { + vargs.add(value); + } + } + if (value == null) + { + value = "false"; + } + System.out.println("AppletParams propName=" + prefName + " argName=" + + argName + " appletName=" + + appletName + " value=" + value); + if (appletName != null) + { + appletParams.put(appletName, value); + } + if (prefName != null) + { + Cache.setPropertyNoSave(prefName, value); + } + } + } + return appletParams; + } + + /** + * Check for a single-argument option. + * + * @param value + * @return "true" or null + */ + private static String checkTF(String value) + { + return (value.toLowerCase() == "true" ? "true" : null); + } + + /** + * Crude applet innerHTML parser + * + * @param tag + * @param attr + * @return + */ + private static String getAttr(String tag, String attr) + { + int pt = tag.indexOf(attr + "=\""); + if (pt < 0) + { + System.out + .println("AppletParams did not read " + attr + " in " + tag); + return null; + } + // + int pt1 = pt + attr.length() + 2; + int pt2 = tag.indexOf("\"", pt1); + return (pt < 0 ? null : tag.substring(pt1, pt2)); + } + + public static void main(String[] args) + { + new AppletParams(" \r\n" + + " \r\n" + + " \r\n" + + " \r\n" + + " \r\n" + + " \r\n" + + " \r\n" + + " \r\n" + + " \r\n" + + " \r\n" + + " \r\n" + + " \r\n" + + " \r\n" + + " \r\n" + + " "); + } + +} \ No newline at end of file diff --git a/src/jalview/bin/ApplicationSingletonProvider.java b/src/jalview/bin/ApplicationSingletonProvider.java new file mode 100644 index 0000000..eb82104 --- /dev/null +++ b/src/jalview/bin/ApplicationSingletonProvider.java @@ -0,0 +1,164 @@ +/* + * Jalview - A Sequence Alignment Editor and Viewer ($$Version-Rel$$) + * Copyright (C) $$Year-Rel$$ The Jalview Authors + * + * This file is part of Jalview. + * + * Jalview is free software: you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, either version 3 + * of the License, or (at your option) any later version. + * + * Jalview is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty + * of MERCHANTABILITY or FITNESS FOR A PARTICULAR + * PURPOSE. See the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Jalview. If not, see . + * The Jalview Authors are detailed in the 'AUTHORS' file. + */ +package jalview.bin; + +import jalview.util.Platform; + +import java.lang.reflect.Constructor; +import java.lang.reflect.InvocationTargetException; +import java.util.HashMap; +import java.util.Map; + +/** + * A class to hold singleton objects, whose scope (context) is + *

      + *
    • the Java runtime (JVM) when running as Java
    • + *
    • one 'applet', when running as JalviewJS
    • + *
    + * This allows separation of multiple JS applets running on the same browser + * page, each with their own 'singleton' instances. + *

    + * Instance objects are held in a separate Map (keyed by Class) for each + * context. For Java, this is just a single static Map. For SwingJS, the map is + * stored as a field {@code _swingjsSingletons} of + * {@code Thread.currentThread.getThreadGroup()}, as a proxy for the applet. + *

    + * Note that when an applet is stopped, its ThreadGroup is removed, allowing any + * singleton references to be garbage collected. + * + * @author hansonr + */ +public class ApplicationSingletonProvider +{ + /** + * A tagging interface to mark classes whose singleton instances may be served + * by {@code ApplicationSingletonProvider}, giving a distinct instance per JS + * 'applet'. + *

    + * A class whose singleton should have global scope (be shared across all + * applets on a page) should not use this mechanism, but just provide + * a single instance (class static member) in the normal way. + */ + public interface ApplicationSingletonI + { + } + + /* + * Map used to hold singletons in JVM context + */ + private static Map, ApplicationSingletonI> singletons = new HashMap<>(); + + /** + * private constructor for non-instantiable class + */ + private ApplicationSingletonProvider() + { + } + + /** + * Returns the singletons map for the current context (JVM for Java, + * ThreadGroup for JS), creating the map on the first request for each JS + * ThreadGroup + * + * @return + */ + private static Map, ApplicationSingletonI> getContextMap() + { + @SuppressWarnings("unused") + ThreadGroup g = (Platform.isJS() + ? Thread.currentThread().getThreadGroup() + : null); + Map, ApplicationSingletonI> map = singletons; + /** @j2sNative map = g._swingjsSingletons; */ + if (map == null) + { + map = new HashMap<>(); + /** @j2sNative g._swingjsSingletons = map; */ + } + + return map; + } + + /** + * Answers the singleton instance of the given class for the current context + * (JVM or SwingJS 'applet'). If no instance yet exists, one is created, by + * calling the class's no-argument constructor. Answers null if any error + * occurs (or occurred previously for the same class). + * + * @param c + * @return + */ + public static ApplicationSingletonI getInstance(Class c) + { + Map, ApplicationSingletonI> map = getContextMap(); + if (map.containsKey(c)) + { + /* + * singleton already created _or_ creation failed (null value stored) + */ + return map.get(c); + } + + /* + * create and save the singleton + */ + ApplicationSingletonI o = map.get(c); + try + { + Constructor con = c + .getDeclaredConstructor(); + con.setAccessible(true); + o = con.newInstance(); + } catch (IllegalAccessException | InstantiationException + | IllegalArgumentException | InvocationTargetException + | NoSuchMethodException | SecurityException e) + { + Cache.log.error("Failed to create singleton for " + c.toString() + + ", error was: " + e.toString()); + e.printStackTrace(); + } + + /* + * store the new singleton; note that a + * null value is saved if construction failed + */ + getContextMap().put(c, o); + + return o; + } + + /** + * Removes the current singleton instance of the given class from the current + * application context. This has the effect of ensuring that a new instance is + * created the next time one is requested. + * + * @param c + */ + public static void removeInstance( + Class c) + { + Map, ApplicationSingletonI> map = getContextMap(); + if (map != null) + { + map.remove(c); + } + } +} diff --git a/src/jalview/bin/ArgsParser.java b/src/jalview/bin/ArgsParser.java index c927f1f..91c8838 100644 --- a/src/jalview/bin/ArgsParser.java +++ b/src/jalview/bin/ArgsParser.java @@ -34,19 +34,98 @@ import java.util.Vector; */ public class ArgsParser { - Vector vargs = null; + + // BH 2019 - new + + public static final String NOCALCULATION = "nocalculation"; + + public static final String NOMENUBAR = "nomenubar"; + + public static final String NOSTATUS = "nostatus"; + + public static final String SHOWOVERVIEW = "showoverview"; + + // + public static final String ANNOTATIONS = "annotations"; + + public static final String COLOUR = "colour"; + + public static final String FEATURES = "features"; + + public static final String GROOVY = "groovy"; + + public static final String GROUPS = "groups"; + + public static final String HEADLESS = "headless"; + + public static final String JABAWS = "jabaws"; + + public static final String NOANNOTATION = "no-annotation"; + + public static final String NOANNOTATION2 = "noannotation"; // BH 2019.05.07 + + public static final String NODISPLAY = "nodisplay"; + + public static final String NOGUI = "nogui"; + + public static final String NONEWS = "nonews"; + + public static final String NOQUESTIONNAIRE = "noquestionnaire"; + + public static final String NOSORTBYTREE = "nosortbytree"; + + public static final String NOUSAGESTATS = "nousagestats"; + + public static final String OPEN = "open"; + + public static final String OPEN2 = "open2"; // BH added -- for applet + // compatibility; not fully + // implemented + + public static final String PROPS = "props"; + + public static final String QUESTIONNAIRE = "questionnaire"; + + public static final String SETPROP = "setprop"; + + public static final String SORTBYTREE = "sortbytree"; + + public static final String TREE = "tree"; + + public static final String VDOC = "vdoc"; + + public static final String VSESS = "vsess"; + + private Vector vargs = null; + + private boolean isApplet; + + private AppletParams appletParams; + + public boolean isApplet() + { + return isApplet; + } public ArgsParser(String[] args) { - vargs = new Vector(); - for (int i = 0; i < args.length; i++) + vargs = new Vector<>(); + isApplet = (args.length > 0 && args[0].startsWith(" 0); + return (vamsasJarsArePresent == TRUE); } /** * internal vamsas class discovery state */ - private static int groovyJarsArePresent = -1; + private static int groovyJarsArePresent = (Platform.isJS() ? FALSE + : UNTESTED); /** * Searches for vamsas client classes on class path. @@ -759,7 +852,7 @@ public class Cache */ public static boolean groovyJarsPresent() { - if (groovyJarsArePresent == -1) + if (groovyJarsArePresent == UNTESTED) { try { @@ -768,7 +861,7 @@ public class Cache { jalview.bin.Cache.log.debug( "Found Groovy (groovy.lang.GroovyObject can be loaded)"); - groovyJarsArePresent = 1; + groovyJarsArePresent = TRUE; Logger lgclient = Logger.getLogger("groovy"); lgclient.setLevel(Level.toLevel(Cache .getDefault("logs.Groovy.Level", Level.INFO.toString()))); @@ -779,15 +872,15 @@ public class Cache } } catch (Error e) { - groovyJarsArePresent = 0; + groovyJarsArePresent = FALSE; jalview.bin.Cache.log.debug("Groovy Classes are not present", e); } catch (Exception e) { - groovyJarsArePresent = 0; + groovyJarsArePresent = FALSE; jalview.bin.Cache.log.debug("Groovy Classes are not present"); } } - return (groovyJarsArePresent > 0); + return (groovyJarsArePresent == TRUE); } /** @@ -796,15 +889,18 @@ public class Cache */ protected static Object tracker = null; - protected static Class trackerfocus = null; + protected static Class trackerfocus = null; - protected static Class jgoogleanalyticstracker = null; + protected static Class jgoogleanalyticstracker = null; /** * Initialise the google tracker if it is not done already. */ public static void initGoogleTracker() { + + // TODO: SwingJS JavaScript tracker? + if (tracker == null) { if (jgoogleanalyticstracker == null) @@ -839,8 +935,7 @@ public class Cache .newInstance(new Object[] { "Jalview Desktop", (vrs = jalview.bin.Cache.getProperty("VERSION") + "_" - + jalview.bin.Cache.getDefault("BUILD_DATE", - "unknown")), + + getDefault("BUILD_DATE", "unknown")), "UA-9060947-1" }); jgoogleanalyticstracker .getMethod("trackAsynchronously", new Class[] @@ -1028,11 +1123,11 @@ public class Cache } if (value == null || value.trim().length() < 1) { - Cache.applicationProperties.remove(propName); + getInstance().applicationProperties.remove(propName); } else { - Cache.applicationProperties.setProperty(propName, value); + getInstance().applicationProperties.setProperty(propName, value); } } @@ -1077,13 +1172,13 @@ public class Cache { if (coloursFound.toString().length() > 1) { - setProperty(UserDefinedColours.USER_DEFINED_COLOURS, + setProperty(Preferences.USER_DEFINED_COLOURS, coloursFound.toString()); } else { - applicationProperties - .remove(UserDefinedColours.USER_DEFINED_COLOURS); + getInstance().applicationProperties + .remove(Preferences.USER_DEFINED_COLOURS); } } } diff --git a/src/jalview/bin/Jalview.java b/src/jalview/bin/Jalview.java index 652b259..f59c37f 100755 --- a/src/jalview/bin/Jalview.java +++ b/src/jalview/bin/Jalview.java @@ -20,27 +20,50 @@ */ package jalview.bin; +import jalview.api.AlignCalcWorkerI; +import jalview.api.AlignFrameI; +import jalview.api.AlignViewportI; +import jalview.api.JalviewApp; +import jalview.api.StructureSelectionManagerProvider; +import jalview.bin.ApplicationSingletonProvider.ApplicationSingletonI; +import jalview.datamodel.ColumnSelection; +import jalview.datamodel.HiddenColumns; +import jalview.datamodel.PDBEntry; +import jalview.datamodel.SequenceGroup; +import jalview.datamodel.SequenceI; import jalview.ext.so.SequenceOntology; import jalview.gui.AlignFrame; +import jalview.gui.AlignViewport; +import jalview.gui.AlignmentPanel; +import jalview.gui.CalculationChooser; import jalview.gui.Desktop; +import jalview.gui.Preferences; import jalview.gui.PromptUserConfig; +import jalview.gui.StructureViewer; import jalview.io.AppletFormatAdapter; import jalview.io.BioJsHTMLOutput; import jalview.io.DataSourceType; import jalview.io.FileFormat; import jalview.io.FileFormatException; import jalview.io.FileFormatI; +import jalview.io.FileFormats; import jalview.io.FileLoader; import jalview.io.HtmlSvgOutput; import jalview.io.IdentifyFile; import jalview.io.NewickFile; import jalview.io.gff.SequenceOntologyFactory; +import jalview.javascript.JSFunctionExec; +import jalview.javascript.MouseOverStructureListener; +import jalview.renderer.seqfeatures.FeatureRenderer; import jalview.schemes.ColourSchemeI; import jalview.schemes.ColourSchemeProperty; +import jalview.structure.SelectionSource; +import jalview.structure.VamsasSource; import jalview.util.MessageManager; import jalview.util.Platform; import jalview.ws.jws2.Jws2Discoverer; +import java.applet.AppletContext; import java.io.BufferedReader; import java.io.File; import java.io.FileOutputStream; @@ -58,19 +81,16 @@ import java.security.PermissionCollection; import java.security.Permissions; import java.security.Policy; import java.util.HashMap; +import java.util.Hashtable; import java.util.Map; import java.util.Vector; -import java.util.logging.ConsoleHandler; -import java.util.logging.Level; -import java.util.logging.Logger; import javax.swing.LookAndFeel; import javax.swing.UIManager; -import com.threerings.getdown.util.LaunchUtil; - import groovy.lang.Binding; import groovy.util.GroovyScriptEngine; +import netscape.javascript.JSObject; /** * Main class for Jalview Application
    @@ -87,20 +107,76 @@ import groovy.util.GroovyScriptEngine; * @author $author$ * @version $Revision$ */ -public class Jalview +public class Jalview implements ApplicationSingletonI, JalviewJSApi { + + public static Jalview getInstance() + { + return (Jalview) ApplicationSingletonProvider + .getInstance(Jalview.class); + } + + private Jalview() + { + } + static { Platform.getURLCommandArguments(); } - // singleton instance of this class + private boolean headless; - private static Jalview instance; + public static boolean isHeadlessMode() + { + return getInstance().headless; + } private Desktop desktop; - public static AlignFrame currentAlignFrame; + private AlignFrame currentAlignFrame; + + public boolean isJavaAppletTag; + + public String appletResourcePath; + + JalviewAppLoader appLoader; + + protected JSFunctionExec jsFunctionExec; + + private boolean noCalculation, noMenuBar, noStatus; + + private boolean noAnnotation; + + public boolean getStartCalculations() + { + return !noCalculation; + } + + public boolean getAllowMenuBar() + { + return !noMenuBar; + } + + public boolean getShowStatus() + { + return !noStatus; + } + + public boolean getShowAnnotation() + { + return !noAnnotation; + } + + public static AlignFrame getCurrentAlignFrame() + { + return getInstance().currentAlignFrame; + } + + public static void setCurrentAlignFrame(AlignFrame currentAlignFrame) + { + getInstance().currentAlignFrame = currentAlignFrame; + } static { @@ -112,21 +188,21 @@ public class Jalview */ { // grab all the rights we can for the JVM - Policy.setPolicy(new Policy() - { - @Override - public PermissionCollection getPermissions(CodeSource codesource) - { - Permissions perms = new Permissions(); - perms.add(new AllPermission()); - return (perms); - } - - @Override - public void refresh() - { - } - }); + Policy.setPolicy(new Policy() + { + @Override + public PermissionCollection getPermissions(CodeSource codesource) + { + Permissions perms = new Permissions(); + perms.add(new AllPermission()); + return (perms); + } + + @Override + public void refresh() + { + } + }); } } @@ -189,11 +265,6 @@ public class Jalview } - public static Jalview getInstance() - { - return instance; - } - /** * main class for Jalview application * @@ -202,61 +273,24 @@ public class Jalview */ public static void main(String[] args) { -// setLogging(); // BH - for event debugging in JavaScript - instance = new Jalview(); - instance.doMain(args); -} - - private static void logClass(String name) - { - // BH - for event debugging in JavaScript - ConsoleHandler consoleHandler = new ConsoleHandler(); - consoleHandler.setLevel(Level.ALL); - Logger logger = Logger.getLogger(name); - logger.setLevel(Level.ALL); - logger.addHandler(consoleHandler); - } - - @SuppressWarnings("unused") - private static void setLogging() - { - - /** - * @j2sIgnore - * - */ - { - System.out.println("not in js"); - } - - // BH - for event debugging in JavaScript (Java mode only) - if (!Platform.isJS()) - /** - * Java only - * - * @j2sIgnore - */ - { - Logger.getLogger("").setLevel(Level.ALL); - logClass("java.awt.EventDispatchThread"); - logClass("java.awt.EventQueue"); - logClass("java.awt.Component"); - logClass("java.awt.focus.Component"); - logClass("java.awt.focus.DefaultKeyboardFocusManager"); - } - + // Platform.startJavaLogging(); + getInstance().doMain(args); } - - + @SuppressWarnings("unused") /** * @param args */ void doMain(String[] args) { - if (!Platform.isJS()) + boolean isJS = Platform.isJS(); + if (isJS) + { + Platform.setAppClass(this); + } + else { System.setSecurityManager(null); } @@ -267,60 +301,60 @@ public class Jalview + System.getProperty("os.name") + " " + System.getProperty("os.version")); - String appdirString = System.getProperty("getdownappdir"); - if (appdirString != null && appdirString.length() > 0) - { - final File appdir = new File(appdirString); - new Thread() - { - @Override - public void run() - { - LaunchUtil.upgradeGetdown( - new File(appdir, "getdown-launcher-old.jar"), - new File(appdir, "getdown-launcher.jar"), - new File(appdir, "getdown-launcher-new.jar")); - } - }.start(); + ArgsParser aparser = new ArgsParser(args); + + String usrPropsFile = aparser.getValue(ArgsParser.PROPS); + Cache.loadProperties(usrPropsFile); + if (aparser.contains(ArgsParser.NODISPLAY) + || aparser.contains(ArgsParser.NOGUI) + || aparser.contains(ArgsParser.HEADLESS) + || "true".equals(System.getProperty("java.awt.headless"))) + { + headless = true; } - ArgsParser aparser = new ArgsParser(args); - boolean headless = false; - String usrPropsFile = aparser.getValue("props"); - Cache.loadProperties(usrPropsFile); // must do this before - if (usrPropsFile != null) + if (isJS) { + isJavaAppletTag = aparser.isApplet(); + if (isJavaAppletTag) + { + Preferences.setAppletDefaults(); + Cache.loadProperties(usrPropsFile); // again, because we + // might be changing defaults here? + } System.out.println( - "CMD [-props " + usrPropsFile + "] executed successfully!"); + " found: " + aparser.getValue("Info.j2sAppletID")); + appletResourcePath = aparser.getValue("Info.resourcePath"); } - - if (!Platform.isJS()) + else /** * Java only * * @j2sIgnore */ { + if (usrPropsFile != null) + { + System.out.println( + "CMD [-props " + usrPropsFile + "] executed successfully!"); + } + if (aparser.contains("help") || aparser.contains("h")) { showUsage(); System.exit(0); } - if (aparser.contains("nodisplay") || aparser.contains("nogui") - || aparser.contains("headless")) - { - System.setProperty("java.awt.headless", "true"); - headless = true; - } + + // anything else! - final String jabawsUrl = aparser.getValue("jabaws"); + final String jabawsUrl = aparser.getValue(ArgsParser.JABAWS); if (jabawsUrl != null) { try { - Jws2Discoverer.getDiscoverer().setPreferredUrl(jabawsUrl); + Jws2Discoverer.getInstance().setPreferredUrl(jabawsUrl); System.out.println( "CMD [-jabaws " + jabawsUrl + "] executed successfully!"); } catch (MalformedURLException e) @@ -331,7 +365,8 @@ public class Jalview } } - String defs = aparser.getValue("setprop"); + // check for property setting + String defs = aparser.getValue(ArgsParser.SETPROP); while (defs != null) { int p = defs.indexOf('='); @@ -342,17 +377,12 @@ public class Jalview else { System.out.println("Executing setprop argument: " + defs); - if (Platform.isJS()) + if (isJS) { - Cache.setProperty(defs.substring(0,p), defs.substring(p+1)); + Cache.setProperty(defs.substring(0, p), defs.substring(p + 1)); } } - defs = aparser.getValue("setprop"); - } - if (System.getProperty("java.awt.headless") != null - && System.getProperty("java.awt.headless").equals("true")) - { - headless = true; + defs = aparser.getValue(ArgsParser.SETPROP); } System.setProperty("http.agent", "Jalview Desktop/" + Cache.getDefault("VERSION", "Unknown")); @@ -371,7 +401,13 @@ public class Jalview try { - UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName()); + if (!isJS && Platform.isWin()) + { + UIManager.setLookAndFeel( + headless ? "javax.swing.plaf.metal.MetalLookAndFeel" + : UIManager.getSystemLookAndFeelClassName()); +// UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName()); + } } catch (Exception ex) { System.err.println("Unexpected Look and Feel Exception"); @@ -396,8 +432,9 @@ public class Jalview "Failed to set QuaQua look and feel: " + e.toString()); } } - if (lookAndFeel == null || !(lookAndFeel.getClass() - .isAssignableFrom(UIManager.getLookAndFeel().getClass())) + if (lookAndFeel == null + || !(lookAndFeel.getClass().isAssignableFrom( + UIManager.getLookAndFeel().getClass())) || !UIManager.getLookAndFeel().getClass().toString() .toLowerCase().contains("quaqua")) { @@ -418,49 +455,18 @@ public class Jalview * configure 'full' SO model if preferences say to, * else use the default (SO Lite) */ - if (Cache.getDefault("USE_FULL_SO", false)) + if (Cache.getDefault(Preferences.USE_FULL_SO, false)) { - SequenceOntologyFactory.setInstance(new SequenceOntology()); + SequenceOntologyFactory.setSequenceOntology(new SequenceOntology()); } if (!headless) { - desktop = new Desktop() -// { -// // BH testing -// @Override -// protected void processEvent(AWTEvent e) { -// System.out.println("Jalview.java " + e); -// super.processEvent(e); -// } -// } - ; + desktop = Desktop.getInstance(); desktop.setInBatchMode(true); // indicate we are starting up - - try - { - if (! Platform.isJS()) - /** - * Java only - * - * @j2sIgnore - */ - { - JalviewTaskbar.setTaskbar(this); - } - } catch (Exception e) - { - System.out.println("Cannot set Taskbar"); - // e.printStackTrace(); - } catch (Throwable t) - { - System.out.println("Cannot set Taskbar"); - // t.printStackTrace(); - } - desktop.setVisible(true); - if (!Platform.isJS()) + if (!isJS) /** * Java only * @@ -468,7 +474,7 @@ public class Jalview */ { desktop.startServiceDiscovery(); - if (!aparser.contains("nousagestats")) + if (!aparser.contains(ArgsParser.NOUSAGESTATS)) { startUsageStats(desktop); } @@ -477,9 +483,9 @@ public class Jalview System.err.println("CMD [-nousagestats] executed successfully!"); } - if (!aparser.contains("noquestionnaire")) + if (!aparser.contains(ArgsParser.NOQUESTIONNAIRE)) { - String url = aparser.getValue("questionnaire"); + String url = aparser.getValue(ArgsParser.QUESTIONNAIRE); if (url != null) { // Start the desktop questionnaire prompter with the specified @@ -491,7 +497,7 @@ public class Jalview } else { - if (Cache.getProperty("NOQUESTIONNAIRES") == null) + if (Cache.getProperty(Preferences.NOQUESTIONNAIRES) == null) { // Start the desktop questionnaire prompter with the specified // questionnaire @@ -511,7 +517,7 @@ public class Jalview .println("CMD [-noquestionnaire] executed successfully!"); } - if (!aparser.contains("nonews")) + if (!aparser.contains(ArgsParser.NONEWS)) { desktop.checkForNews(); } @@ -520,111 +526,84 @@ public class Jalview } } - String file = null, data = null; - FileFormatI format = null; - DataSourceType protocol = null; - FileLoader fileLoader = new FileLoader(!headless); + parseArguments(aparser, true); + } + + /** + * Allow an outside entity to initiate the second half of argument parsing + * (only). + * + * @param args + * @return null is good + */ + @Override + public Object parseArguments(String[] args) + { + + try + { + ArgsParser aparser = new ArgsParser(args); + return parseArguments(aparser, false); + } catch (Throwable t) + { + return t; + } + } + + /** + * + * @param aparser + * @param isStartup + * @return + */ + private Object parseArguments(ArgsParser aparser, boolean isStartup) + { + boolean isJS = Platform.isJS(); - String groovyscript = null; // script to execute after all loading is + Desktop desktop = (headless ? null : Desktop.getInstance()); + // script to execute after all loading is // completed one way or another // extract groovy argument and execute if necessary - groovyscript = aparser.getValue("groovy", true); - file = aparser.getValue("open", true); + String groovyscript = (isJS ? null + : aparser.getValue(ArgsParser.GROOVY, true)); + String file = aparser.getValue(ArgsParser.OPEN, true); + // BH this here to allow split frame; not working as of 5/17/2019 + String file2 = aparser.getValue(ArgsParser.OPEN2, true); + String fileFormat = (isJavaAppletTag + ? aparser.getAppletValue("format", null) + : null); + FileFormatI format = null; + DataSourceType protocol = null; if (file == null && desktop == null) { System.out.println("No files to open!"); System.exit(1); } - String vamsasImport = aparser.getValue("vdoc"); - String vamsasSession = aparser.getValue("vsess"); - if (vamsasImport != null || vamsasSession != null) + boolean haveImport = checkStartVamas(aparser); + // Finally, deal with the remaining input data. + long progress = -1; + if (file == null && isJavaAppletTag) { - if (desktop == null || headless) + // Maybe the sequences are added as parameters + StringBuffer data = new StringBuffer("PASTE"); + int i = 1; + while ((file = aparser.getAppletValue("sequence" + i, null)) != null) { - System.out.println( - "Headless vamsas sessions not yet supported. Sorry."); - System.exit(1); - } - // if we have a file, start a new session and import it. - boolean inSession = false; - if (vamsasImport != null) - { - try - { - DataSourceType viprotocol = AppletFormatAdapter - .checkProtocol(vamsasImport); - if (viprotocol == DataSourceType.FILE) - { - inSession = desktop.vamsasImport(new File(vamsasImport)); - } - else if (viprotocol == DataSourceType.URL) - { - inSession = desktop.vamsasImport(new URL(vamsasImport)); - } - - } catch (Exception e) - { - System.err.println("Exeption when importing " + vamsasImport - + " as a vamsas document."); - e.printStackTrace(); - } - if (!inSession) - { - System.err.println("Failed to import " + vamsasImport - + " as a vamsas document."); - } - else - { - System.out.println("Imported Successfully into new session " - + desktop.getVamsasApplication().getCurrentSession()); - } + data.append(file.toString() + "\n"); + i++; } - if (vamsasSession != null) + if (data.length() > 5) { - if (vamsasImport != null) - { - // close the newly imported session and import the Jalview specific - // remnants into the new session later on. - desktop.vamsasStop_actionPerformed(null); - } - // now join the new session - try - { - if (desktop.joinVamsasSession(vamsasSession)) - { - System.out.println( - "Successfully joined vamsas session " + vamsasSession); - } - else - { - System.err.println("WARNING: Failed to join vamsas session " - + vamsasSession); - } - } catch (Exception e) - { - System.err.println( - "ERROR: Failed to join vamsas session " + vamsasSession); - e.printStackTrace(); - } - if (vamsasImport != null) - { - // the Jalview specific remnants can now be imported into the new - // session at the user's leisure. - Cache.log.info( - "Skipping Push for import of data into existing vamsas session."); // TODO: - // enable - // this - // when - // debugged - // desktop.getVamsasApplication().push_update(); - } + file = data.toString(); } } - long progress = -1; - // Finally, deal with the remaining input data. + + String data; + if (file != null) { + if (!headless) { desktop.setProgressBar( @@ -632,14 +611,14 @@ public class Jalview .getString("status.processing_commandline_args"), progress = System.currentTimeMillis()); } - System.out.println("CMD [-open " + file + "] executed successfully!"); - if (!Platform.isJS()) - /** - * ignore in JavaScript -- can't just file existence - could load it? - * - * @j2sIgnore - */ + if (!isJS) + /** + * ignore in JavaScript -- can't just check file existence - could load + * it? + * + * @j2sIgnore + */ { if (!file.startsWith("http://") && !file.startsWith("https://")) // BH 2019 added https check for Java @@ -655,33 +634,94 @@ public class Jalview } } - protocol = AppletFormatAdapter.checkProtocol(file); + protocol = AppletFormatAdapter.checkProtocol(file); try { - format = new IdentifyFile().identify(file, protocol); + format = (isJavaAppletTag && fileFormat != null + ? FileFormats.getInstance().forName(fileFormat) + : null); + if (format == null) + { + format = new IdentifyFile().identify(file, protocol); + } } catch (FileFormatException e1) { // TODO ? } - AlignFrame af = fileLoader.LoadFileWaitTillLoaded(file, protocol, - format); + if (aparser.contains(ArgsParser.NOMENUBAR)) + { + noMenuBar = true; + System.out.println("CMD [nomenu] executed successfully!"); + } + + if (aparser.contains(ArgsParser.NOSTATUS)) + { + noStatus = true; + System.out.println("CMD [nostatus] executed successfully!"); + } + + if (aparser.contains(ArgsParser.NOANNOTATION) + || aparser.contains(ArgsParser.NOANNOTATION2)) + { + noAnnotation = true; + System.out.println("CMD no-annotation executed successfully!"); + } + if (aparser.contains(ArgsParser.NOCALCULATION)) + { + noCalculation = true; + System.out.println("CMD [nocalculation] executed successfully!"); + } + + AlignFrame af = new FileLoader(!headless).loadFileWaitTillLoaded(file, + protocol, format); if (af == null) { System.out.println("error"); } else { + System.out + .println("CMD [-open " + file + "] executed successfully!"); + if (file2 != null) + { + protocol = AppletFormatAdapter.checkProtocol(file2); + try + { + format = new IdentifyFile().identify(file2, protocol); + } catch (FileFormatException e1) + { + // TODO ? + } + AlignFrame af2 = new FileLoader(!headless) + .loadFileWaitTillLoaded(file2, protocol, format); + if (af2 == null) + { + System.out.println("error"); + } + else + { + AlignViewport.openLinkedAlignmentAs(af, + af.getViewport().getAlignment(), + af2.getViewport().getAlignment(), "", + AlignViewport.SPLIT_FRAME); + System.out.println( + "CMD [-open2 " + file2 + "] executed successfully!"); + } + } + setCurrentAlignFrame(af); - data = aparser.getValue("colour", true); + + // TODO: file2 How to implement file2 for the applet spit screen? + + data = aparser.getValue(ArgsParser.COLOUR, true); if (data != null) { data.replaceAll("%20", " "); - ColourSchemeI cs = ColourSchemeProperty - .getColourScheme(af.getViewport(), - af.getViewport().getAlignment(), data); + ColourSchemeI cs = ColourSchemeProperty.getColourScheme( + af.getViewport(), af.getViewport().getAlignment(), data); if (cs != null) { @@ -692,7 +732,7 @@ public class Jalview } // Must maintain ability to use the groups flag - data = aparser.getValue("groups", true); + data = aparser.getValue(ArgsParser.GROUPS, true); if (data != null) { af.parseFeaturesFile(data, @@ -701,7 +741,7 @@ public class Jalview System.out.println( "CMD groups[-" + data + "] executed successfully!"); } - data = aparser.getValue("features", true); + data = aparser.getValue(ArgsParser.FEATURES, true); if (data != null) { af.parseFeaturesFile(data, @@ -711,7 +751,7 @@ public class Jalview "CMD [-features " + data + "] executed successfully!"); } - data = aparser.getValue("annotations", true); + data = aparser.getValue(ArgsParser.ANNOTATIONS, true); if (data != null) { af.loadJalviewDataFile(data, null, null, null); @@ -719,8 +759,15 @@ public class Jalview System.out.println( "CMD [-annotations " + data + "] executed successfully!"); } + + if (aparser.contains(ArgsParser.SHOWOVERVIEW)) + { + af.overviewMenuItem_actionPerformed(null); + System.out.println("CMD [showoverview] executed successfully!"); + } + // set or clear the sortbytree flag. - if (aparser.contains("sortbytree")) + if (aparser.contains(ArgsParser.SORTBYTREE)) { af.getViewport().setSortByTree(true); if (af.getViewport().getSortByTree()) @@ -728,24 +775,48 @@ public class Jalview System.out.println("CMD [-sortbytree] executed successfully!"); } } - if (aparser.contains("no-annotation")) + + boolean doUpdateAnnotation = false; + + /** + * we do this earlier in JalviewJS because of a complication with + * SHOWOVERVIEW + * + * For now, just fixing this in JalviewJS. + * + * + * @j2sIgnore + * + */ { - af.getViewport().setShowAnnotation(false); - if (!af.getViewport().isShowAnnotation()) + if (aparser.contains(ArgsParser.NOANNOTATION) + || aparser.contains(ArgsParser.NOANNOTATION2)) { - System.out.println("CMD no-annotation executed successfully!"); + af.getViewport().setShowAnnotation(false); + if (!af.getViewport().isShowAnnotation()) + { + doUpdateAnnotation = true; + System.out + .println("CMD no-annotation executed successfully!"); + } } } - if (aparser.contains("nosortbytree")) + if (aparser.contains(ArgsParser.NOSORTBYTREE)) { af.getViewport().setSortByTree(false); if (!af.getViewport().getSortByTree()) { + doUpdateAnnotation = true; System.out .println("CMD [-nosortbytree] executed successfully!"); } } - data = aparser.getValue("tree", true); + if (doUpdateAnnotation) + { // BH 2019.07.24 + af.setMenusForViewport(); + af.alignPanel.updateLayout(); + } + data = aparser.getValue(ArgsParser.TREE, true); if (data != null) { try @@ -765,110 +836,42 @@ public class Jalview // TODO - load PDB structure(s) to alignment JAL-629 // (associate with identical sequence in alignment, or a specified // sequence) - if (groovyscript != null) + if (isJavaAppletTag) { - // Execute the groovy script after we've done all the rendering stuff - // and before any images or figures are generated. - System.out.println("Executing script " + groovyscript); - executeGroovyScript(groovyscript, af); - System.out.println("CMD groovy[" + groovyscript - + "] executed successfully!"); - groovyscript = null; + loadAppletParams(aparser, af); } - String imageName = "unnamed.png"; - while (aparser.getSize() > 1) + else if (!isJS) + /** + * Java only + * + * @j2sIgnore + */ { - String outputFormat = aparser.nextValue(); - file = aparser.nextValue(); - - if (outputFormat.equalsIgnoreCase("png")) - { - af.createPNG(new File(file)); - imageName = (new File(file)).getName(); - System.out.println("Creating PNG image: " + file); - continue; - } - else if (outputFormat.equalsIgnoreCase("svg")) + if (groovyscript != null) { - File imageFile = new File(file); - imageName = imageFile.getName(); - af.createSVG(imageFile); - System.out.println("Creating SVG image: " + file); - continue; + // Execute the groovy script after we've done all the rendering + // stuff + // and before any images or figures are generated. + System.out.println("Executing script " + groovyscript); + executeGroovyScript(groovyscript, af); + System.out.println("CMD groovy[" + groovyscript + + "] executed successfully!"); + groovyscript = null; } - else if (outputFormat.equalsIgnoreCase("html")) - { - File imageFile = new File(file); - imageName = imageFile.getName(); - HtmlSvgOutput htmlSVG = new HtmlSvgOutput(af.alignPanel); - htmlSVG.exportHTML(file); + } + checkOutputFile(aparser, af, format); + while (aparser.getSize() > 0) + { + System.out.println("Unknown arg: " + aparser.nextValue()); + } + } + } + AlignFrame startUpAlframe = null; + // We'll only open the default file if the desktop is visible. + // And the user + // //////////////////// - System.out.println("Creating HTML image: " + file); - continue; - } - else if (outputFormat.equalsIgnoreCase("biojsmsa")) - { - if (file == null) - { - System.err.println("The output html file must not be null"); - return; - } - try - { - BioJsHTMLOutput.refreshVersionInfo( - BioJsHTMLOutput.BJS_TEMPLATES_LOCAL_DIRECTORY); - } catch (URISyntaxException e) - { - e.printStackTrace(); - } - BioJsHTMLOutput bjs = new BioJsHTMLOutput(af.alignPanel); - bjs.exportHTML(file); - System.out - .println("Creating BioJS MSA Viwer HTML file: " + file); - continue; - } - else if (outputFormat.equalsIgnoreCase("imgMap")) - { - af.createImageMap(new File(file), imageName); - System.out.println("Creating image map: " + file); - continue; - } - else if (outputFormat.equalsIgnoreCase("eps")) - { - File outputFile = new File(file); - System.out.println( - "Creating EPS file: " + outputFile.getAbsolutePath()); - af.createEPS(outputFile); - continue; - } - - af.saveAlignment(file, format); - if (af.isSaveAlignmentSuccessful()) - { - System.out.println("Written alignment in " + format - + " format to " + file); - } - else - { - System.out.println("Error writing file " + file + " in " - + format + " format!!"); - } - - } - - while (aparser.getSize() > 0) - { - System.out.println("Unknown arg: " + aparser.nextValue()); - } - } - } - AlignFrame startUpAlframe = null; - // We'll only open the default file if the desktop is visible. - // And the user - // //////////////////// - - if (!Platform.isJS() && !headless && file == null - && vamsasImport == null + if (!isJS && !headless && file == null && !haveImport && jalview.bin.Cache.getDefault("SHOW_STARTUP_FILE", true)) /** * Java only @@ -911,8 +914,8 @@ public class Jalview } } - startUpAlframe = fileLoader.LoadFileWaitTillLoaded(file, protocol, - format); + startUpAlframe = new FileLoader(!headless) + .loadFileWaitTillLoaded(file, protocol, format); // extract groovy arguments before anything else. } @@ -940,6 +943,190 @@ public class Jalview } desktop.setInBatchMode(false); } + + return null; + } + + private boolean checkStartVamas(ArgsParser aparser) + { + String vamsasImport = aparser.getValue(ArgsParser.VDOC); + String vamsasSession = aparser.getValue(ArgsParser.VSESS); + if (vamsasImport == null && vamsasSession == null) + { + return false; + } + if (desktop == null || headless) + { + System.out.println( + "Headless vamsas sessions not yet supported. Sorry."); + System.exit(1); + } + boolean haveImport = (vamsasImport != null); + if (haveImport) + { + // if we have a file, start a new session and import it. + boolean inSession = false; + try + { + DataSourceType viprotocol = AppletFormatAdapter + .checkProtocol(vamsasImport); + if (viprotocol == DataSourceType.FILE) + { + inSession = desktop.vamsasImport(new File(vamsasImport)); + } + else if (viprotocol == DataSourceType.URL) + { + inSession = desktop.vamsasImport(new URL(vamsasImport)); + } + + } catch (Exception e) + { + System.err.println("Exeption when importing " + vamsasImport + + " as a vamsas document."); + e.printStackTrace(); + } + if (!inSession) + { + System.err.println("Failed to import " + vamsasImport + + " as a vamsas document."); + } + else + { + System.out.println("Imported Successfully into new session " + + desktop.getVamsasApplication().getCurrentSession()); + } + } + if (vamsasSession != null) + { + if (vamsasImport != null) + { + // close the newly imported session and import the Jalview specific + // remnants into the new session later on. + desktop.vamsasStop_actionPerformed(null); + } + // now join the new session + try + { + if (desktop.joinVamsasSession(vamsasSession)) + { + System.out.println( + "Successfully joined vamsas session " + vamsasSession); + } + else + { + System.err.println("WARNING: Failed to join vamsas session " + + vamsasSession); + } + } catch (Exception e) + { + System.err.println( + "ERROR: Failed to join vamsas session " + vamsasSession); + e.printStackTrace(); + } + if (vamsasImport != null) + { + // the Jalview specific remnants can now be imported into the new + // session at the user's leisure. + Cache.log.info( + "Skipping Push for import of data into existing vamsas session."); + // TODO: + // enable + // this + // when + // debugged + // desktop.getVamsasApplication().push_update(); + } + } + return haveImport; + } + + private void checkOutputFile(ArgsParser aparser, AlignFrame af, + FileFormatI format) + { + String imageName = "unnamed.png"; + while (aparser.getSize() > 1) + { + // PNG filename + // SVG filename + // HTML filename + // biojsmsa filename + String outputFormat = aparser.nextValue(); + String file = aparser.nextValue(); + System.out.println("format " + outputFormat); + + if (outputFormat.equalsIgnoreCase("png")) + { + af.createPNG(new File(file)); + imageName = (new File(file)).getName(); + System.out.println("Creating PNG image: " + file); + continue; + } + else if (outputFormat.equalsIgnoreCase("svg")) + { + File imageFile = new File(file); + imageName = imageFile.getName(); + af.createSVG(imageFile); + System.out.println("Creating SVG image: " + file); + continue; + } + else if (outputFormat.equalsIgnoreCase("html")) + { + File imageFile = new File(file); + imageName = imageFile.getName(); + HtmlSvgOutput htmlSVG = new HtmlSvgOutput(af.alignPanel); + htmlSVG.exportHTML(file); + + System.out.println("Creating HTML image: " + file); + continue; + } + else if (outputFormat.equalsIgnoreCase("biojsmsa")) + { + if (file == null) + { + System.err.println("The output html file must not be null"); + return; + } + try + { + BioJsHTMLOutput.refreshVersionInfo( + BioJsHTMLOutput.BJS_TEMPLATES_LOCAL_DIRECTORY); + } catch (URISyntaxException e) + { + e.printStackTrace(); + } + BioJsHTMLOutput bjs = new BioJsHTMLOutput(af.alignPanel); + bjs.exportHTML(file); + System.out.println("Creating BioJS MSA Viwer HTML file: " + file); + continue; + } + else if (outputFormat.equalsIgnoreCase("imgMap")) + { + af.createImageMap(new File(file), imageName); + System.out.println("Creating image map: " + file); + continue; + } + else if (outputFormat.equalsIgnoreCase("eps")) + { + File outputFile = new File(file); + System.out.println( + "Creating EPS file: " + outputFile.getAbsolutePath()); + af.createEPS(outputFile); + continue; + } + + af.saveAlignment(file, format); + if (af.isSaveAlignmentSuccessful()) + { + System.out.println( + "Written alignment in " + format + " format to " + file); + } + else + { + System.out.println("Error writing file " + file + " in " + format + + " format!!"); + } + + } } private static void showUsage() @@ -992,8 +1179,9 @@ public class Jalview /** * start a User Config prompt asking if we can log usage statistics. */ - PromptUserConfig prompter = new PromptUserConfig(Desktop.desktop, - "USAGESTATS", "Jalview Usage Statistics", + PromptUserConfig prompter = new PromptUserConfig( + Desktop.getDesktopPane(), "USAGESTATS", + "Jalview Usage Statistics", "Do you want to help make Jalview better by enabling " + "the collection of usage statistics with Google Analytics ?" + "\n\n(you can enable or disable usage tracking in the preferences)", @@ -1112,7 +1300,7 @@ public class Jalview } try { - Map vbinding = new HashMap<>(); + Map vbinding = new HashMap<>(); vbinding.put("Jalview", this); if (af != null) { @@ -1136,16 +1324,6 @@ public class Jalview } } - public static boolean isHeadlessMode() - { - String isheadless = System.getProperty("java.awt.headless"); - if (isheadless != null && isheadless.equalsIgnoreCase("true")) - { - return true; - } - return false; - } - public AlignFrame[] getAlignFrames() { return desktop == null ? new AlignFrame[] { getCurrentAlignFrame() } @@ -1159,6 +1337,12 @@ public class Jalview */ public void quit() { + if (jsFunctionExec != null) + { + jsFunctionExec.tidyUp(); + jsFunctionExec = null; + } + if (desktop != null) { desktop.quit(); @@ -1169,13 +1353,719 @@ public class Jalview } } - public static AlignFrame getCurrentAlignFrame() + /** + * Get the SwingJS applet ID and combine that with the frameType + * + * @param frameType + * "alignment", "desktop", etc., or null + * @return + */ + public static String getAppID(String frameType) { - return Jalview.currentAlignFrame; + String id = Cache.getProperty("Info.j2sAppletID"); + if (id == null) + { + id = "jalview"; + } + return id + (frameType == null ? "" : "-" + frameType); } - public static void setCurrentAlignFrame(AlignFrame currentAlignFrame) + /** + * Handle all JalviewLite applet parameters + * + * @param aparser + * @param af + */ + private void loadAppletParams(ArgsParser aparser, AlignFrame af) { - Jalview.currentAlignFrame = currentAlignFrame; + JalviewApp app = new JalviewApp() + { + + // TODO BH 2019 + // + // These are methods that are in JalviewLite that various classes call + // but are not in JalviewLiteJsApi. Or, even if they are, other classes + // call + // them to JalviewLite directly. Some may not be necessary, but they have + // to + // be at least mentioned here, or the classes calling them should + // reference + // JalviewLite itself. + + private boolean alignPDBStructures; // From JalviewLite; not implemented + + private Hashtable> jsmessages; + + private Hashtable jshashes; + + @Override + public String getParameter(String name) + { + return aparser.getAppletValue(name, null); + } + + @Override + public boolean getDefaultParameter(String name, boolean def) + { + String stn; + return ((stn = getParameter(name)) == null ? def + : "true".equalsIgnoreCase(stn)); + } + + /** + * Get the applet-like document base even though this is an application. + */ + @Override + public URL getDocumentBase() + { + return Platform.getDocumentBase(); + } + + /** + * Get the applet-like code base even though this is an application. + */ + @Override + public URL getCodeBase() + { + return Platform.getCodeBase(); + } + + @Override + public AlignViewportI getViewport() + { + return af.getViewport(); + } + + /** + * features + * + */ + @Override + public boolean parseFeaturesFile(String filename, + DataSourceType protocol) + { + return af.parseFeaturesFile(filename, protocol); + } + + /** + * scorefile + * + */ + @Override + public boolean loadScoreFile(String sScoreFile) throws IOException + { + af.loadJalviewDataFile(sScoreFile, null, null, null); + return true; + } + + /** + * annotations, jpredfile, jnetfile + * + */ + @Override + public void updateForAnnotations() + { + af.updateForAnnotations(); + } + + @Override + public void loadTree(NewickFile fin, String treeFile) + throws IOException + { + // n/a -- already done by standard Jalview command line processing + } + + @Override + public void setAlignPdbStructures(boolean defaultParameter) + { + alignPDBStructures = true; + } + + @Override + public void newStructureView(PDBEntry pdb, SequenceI[] seqs, + String[] chains, DataSourceType protocol) + { + StructureViewer.launchStructureViewer(af.alignPanel, pdb, seqs); + } + + @Override + public void setFeatureGroupState(String[] groups, boolean state) + { + af.setFeatureGroupState(groups, state); + } + + @Override + public void alignedStructureView(PDBEntry[] pdb, SequenceI[][] seqs, + String[][] chains, String[] protocols) + { + System.err.println( + "Jalview applet interface alignedStructureView not implemented"); + } + + @Override + public void newFeatureSettings() + { + System.err.println( + "Jalview applet interface newFeatureSettings not implemented"); + } + + private Vector jsExecQueue; + + @Override + public Vector getJsExecQueue(JSFunctionExec exec) + { + jsFunctionExec = exec; + return (jsExecQueue == null ? (jsExecQueue = new Vector<>()) + : jsExecQueue); + } + + @Override + public AppletContext getAppletContext() + { + // TODO Auto-generated method stub + return null; + } + + @Override + public boolean isJsfallbackEnabled() + { + // TODO Auto-generated method stub + return false; + } + + @Override + public JSObject getJSObject() + { + // TODO Auto-generated method stub + return null; + } + + @Override + public StructureSelectionManagerProvider getStructureSelectionManagerProvider() + { + // TODO Q: what exactly is this? BH + return null; + } + + @Override + public void updateColoursFromMouseOver(Object source, + MouseOverStructureListener mouseOverStructureListener) + { + // TODO Auto-generated method stub + + } + + @Override + public Object[] getSelectionForListener(SequenceGroup seqsel, + ColumnSelection colsel, HiddenColumns hidden, + SelectionSource source, Object alignFrame) + { + return appLoader.getSelectionForListener(getCurrentAlignFrame(), + seqsel, colsel, hidden, source, alignFrame); + } + + @Override + public String arrayToSeparatorList(String[] array) + { + return appLoader.arrayToSeparatorList(array); + } + + @Override + public Hashtable getJSHashes() + { + return (jshashes == null ? (jshashes = new Hashtable<>()) + : jshashes); + } + + @Override + public Hashtable> getJSMessages() + { + return (jsmessages == null ? (jsmessages = new Hashtable<>()) + : jsmessages); + } + + @Override + public Object getFrameForSource(VamsasSource source) + { + if (source != null) + { + AlignFrame af; + if (source instanceof jalview.gui.AlignViewport + && source == (af = getCurrentAlignFrame()).getViewport()) + { + // should be valid if it just generated an event! + return af; + } + // TODO: ensure that if '_af' is specified along with a handler + // function, then only events from that alignFrame are sent to that + // function + } + return null; + } + + @Override + public FeatureRenderer getNewFeatureRenderer(AlignViewportI vp) + { + return new jalview.gui.FeatureRenderer((AlignmentPanel) vp); + } + + }; + + appLoader = new JalviewAppLoader(true); + appLoader.load(app); + } + + /** + * + * @see jalview.bin.JalviewLiteJsApi#getSelectedSequences() + */ + @Override + public String getSelectedSequences() + { + return getSelectedSequencesFrom(getCurrentAlignFrame()); + } + + /** + * + * @see jalview.bin.JalviewLiteJsApi#getSelectedSequences(java.lang.String) + */ + @Override + public String getSelectedSequences(String sep) + { + return getSelectedSequencesFrom(getCurrentAlignFrame(), sep); + } + + /** + * + * @see jalview.bin.JalviewLiteJsApi#getSelectedSequencesFrom(jalview.appletgui + * .AlignFrame) + */ + @Override + public String getSelectedSequencesFrom(AlignFrameI alf) + { + return getSelectedSequencesFrom(alf, null); + } + + /** + * + * @see jalview.bin.JalviewLiteJsApi#getSelectedSequencesFrom(jalview.appletgui + * .AlignFrame, java.lang.String) + */ + @Override + public String getSelectedSequencesFrom(AlignFrameI alf, String sep) + { + return appLoader.getSelectedSequencesFrom(alf, sep); + } + + /** + * + * @see jalview.bin.JalviewLiteJsApi#getSelectedSequencesFrom(jalview.appletgui + * .AlignFrame, java.lang.String) + */ + @Override + public void highlight(String sequenceId, String position, + String alignedPosition) + { + highlightIn(getCurrentAlignFrame(), sequenceId, position, + alignedPosition); + } + + @Override + public void highlightIn(AlignFrameI alf, String sequenceId, + String position, String alignedPosition) + { + appLoader.highlightIn(alf, sequenceId, position, alignedPosition); + } + + @Override + public void select(String sequenceIds, String columns) + { + selectIn(getCurrentAlignFrame(), sequenceIds, columns, null); + } + + @Override + public void select(String sequenceIds, String columns, String sep) + { + selectIn(getCurrentAlignFrame(), sequenceIds, columns, sep); + } + + @Override + public void selectIn(AlignFrameI alf, String sequenceIds, String columns) + { + selectIn(alf, sequenceIds, columns, null); + } + + @Override + public void selectIn(AlignFrameI alf, String sequenceIds, String columns, + String sep) + { + appLoader.selectIn(alf, sequenceIds, columns, sep); + } + + @Override + public String getSelectedSequencesAsAlignment(String format, + String suffix) + { + return getSelectedSequencesAsAlignmentFrom(getCurrentAlignFrame(), + format, suffix); + } + + @Override + public String getSelectedSequencesAsAlignmentFrom(AlignFrameI alf, + String format, String sep) + { + return appLoader.getSelectedSequencesAsAlignmentFrom(alf, format, sep); + } + + @Override + public String getAlignmentOrder() + { + return getAlignmentFrom(getCurrentAlignFrame(), null); + } + + @Override + public String getAlignmentOrderFrom(AlignFrameI alf) + { + return getAlignmentFrom(alf, null); + } + + @Override + public String getAlignmentOrderFrom(AlignFrameI alf, String sep) + { + return appLoader.getAlignmentOrderFrom(alf, sep); + } + + @Override + public String orderBy(String order, String undoName) + { + return orderBy(order, undoName, null); + } + + @Override + public String orderBy(String order, String undoName, String sep) + { + return orderAlignmentBy(getCurrentAlignFrame(), order, undoName, sep); + } + + @Override + public String orderAlignmentBy(AlignFrameI alf, String order, + String undoName, String sep) + { + return appLoader.orderAlignmentBy(alf, order, undoName, sep); + } + + @Override + public String getAlignment(String format) + { + return getAlignmentFrom(null, format, null); + } + + @Override + public String getAlignmentFrom(AlignFrameI alf, String format) + { + return getAlignmentFrom(alf, format, null); + } + + @Override + public String getAlignment(String format, String suffix) + { + return getAlignmentFrom(getCurrentAlignFrame(), format, suffix); + } + + @Override + public String getAlignmentFrom(AlignFrameI alf, String format, + String suffix) + { + return appLoader.getAlignmentFrom(alf, format, suffix); + } + + @Override + public void loadAnnotation(String annotation) + { + loadAnnotationFrom(getCurrentAlignFrame(), annotation); + } + + @Override + public void loadAnnotationFrom(AlignFrameI alf, String annotation) + { + appLoader.loadAnnotationFrom(alf, annotation); + } + + @Override + public void loadFeatures(String features, boolean autoenabledisplay) + { + loadFeaturesFrom(currentAlignFrame, features, autoenabledisplay); + } + + @Override + public boolean loadFeaturesFrom(AlignFrameI alf, String features, + boolean autoenabledisplay) + { + return appLoader.loadFeaturesFrom(alf, features, autoenabledisplay); + } + + @Override + public String getFeatures(String format) + { + return getFeaturesFrom(getCurrentAlignFrame(), format); + } + + @Override + public String getFeaturesFrom(AlignFrameI alf, String format) + { + return appLoader.getFeaturesFrom(alf, format); + } + + @Override + public String getAnnotation() + { + return getAnnotationFrom(getCurrentAlignFrame()); + } + + @Override + public String getAnnotationFrom(AlignFrameI alf) + { + return appLoader.getAnnotationFrom(alf); + } + + @Override + public AlignFrameI newView() + { + return newViewFrom(getCurrentAlignFrame(), null); + } + + @Override + public AlignFrameI newView(String name) + { + return newViewFrom(getCurrentAlignFrame(), name); + } + + @Override + public AlignFrameI newViewFrom(AlignFrameI alf) + { + return newViewFrom(alf, null); + } + + @Override + public AlignFrameI newViewFrom(AlignFrameI alf, String name) + { + return appLoader.newViewFrom(alf, name); + } + + @Override + public AlignFrameI loadAlignment(String text, String title) + { + return appLoader.loadAlignment(text, AlignFrame.DEFAULT_WIDTH, + AlignFrame.DEFAULT_HEIGHT, title); + } + + @Override + public boolean addPdbFile(AlignFrameI alFrame, String sequenceId, + String pdbEntryString, String pdbFile) + { + return appLoader.addPdbFile(alFrame, sequenceId, pdbEntryString, + pdbFile); + } + + @Override + public void scrollViewToIn(AlignFrameI alf, String topRow, + String leftHandColumn) + { + appLoader.scrollViewToIn(alf, topRow, leftHandColumn); + } + + @Override + public void scrollViewToRowIn(AlignFrameI alf, String topRow) + { + appLoader.scrollViewToRowIn(alf, topRow); + } + + @Override + public void scrollViewToColumnIn(AlignFrameI alf, String leftHandColumn) + { + appLoader.scrollViewToColumnIn(alf, leftHandColumn); + } + + @Override + public String getFeatureGroups() + { + return getFeatureGroupsOn(getCurrentAlignFrame()); + } + + @Override + public String getFeatureGroupsOn(AlignFrameI alf) + { + return appLoader.getFeatureGroupsOn(alf); + } + + @Override + public String getFeatureGroupsOfState(boolean visible) + { + return getFeatureGroupsOfStateOn(getCurrentAlignFrame(), visible); + } + + @Override + public String getFeatureGroupsOfStateOn(AlignFrameI alf, boolean visible) + { + return appLoader.getFeatureGroupsOfStateOn(alf, visible); + } + + @Override + public void setFeatureGroupStateOn(AlignFrameI alf, String groups, + boolean state) + { + setFeatureGroupStateOn(alf, groups, state); + } + + @Override + public void setFeatureGroupState(String groups, boolean state) + { + appLoader.setFeatureGroupStateOn(getCurrentAlignFrame(), groups, state); + } + + @Override + public String getSeparator() + { + return appLoader.getSeparator(); + } + + @Override + public void setSeparator(String separator) + { + appLoader.setSeparator(separator); + } + + @Override + public String getJsMessage(String messageclass, String viewId) + { + // see http://www.jalview.org/examples/jalviewLiteJs.html + return null; + } + + /** + * Open a new Tree panel on the desktop statically. Params are standard (not + * set by Groovy). No dialog is opened. + * + * @param af + * @param treeType + * @param modelName + * @return null, or the string "label.you_need_at_least_n_sequences" if number + * of sequences selected is inappropriate + */ + @Override + public Object openTreePanel(AlignFrame af, String treeType, + String modelName) + { + return CalculationChooser.openTreePanel(af, treeType, modelName, null); + } + + /** + * public static method for JalviewJS API to open a PCAPanel without + * necessarily using a dialog. + * + * @param af + * @param modelName + * @return the PCAPanel, or the string "label.you_need_at_least_n_sequences" + * if number of sequences selected is inappropriate + */ + @Override + public Object openPcaPanel(AlignFrame af, String modelName) + { + return CalculationChooser.openPcaPanel(af, modelName, null); + } + + @Override + public String getSelectedSequencesAsAlignment(String format, + boolean suffix) + { + return getSelectedSequencesAsAlignmentFrom(getCurrentAlignFrame(), + format, suffix); + } + + @Override + public String getSelectedSequencesAsAlignmentFrom(AlignFrameI alf, + String format, boolean suffix) + { + return appLoader.getSelectedSequencesAsAlignmentFrom(alf, format, + "" + suffix); + } + + @Override + public String arrayToSeparatorList(String[] array) + { + return appLoader.arrayToSeparatorList(array); + } + + @Override + public String[] separatorListToArray(String list) + { + return appLoader.separatorListToArray(list); + } + + //// probably not needed in JalviewJS -- From when Jmol and Jalview did not + //// have a direct connection? + + @Override + public void setMouseoverListener(String listener) + { + // TODO Auto-generated method stub + + } + + @Override + public void setMouseoverListener(AlignFrameI af, String listener) + { + // TODO Auto-generated method stub + } + + @Override + public void setSelectionListener(String listener) + { + // TODO Auto-generated method stub + + } + + @Override + public void setSelectionListener(AlignFrameI af, String listener) + { + // TODO Auto-generated method stub + + } + + @Override + public void setStructureListener(String listener, String modelSet) + { + // TODO Auto-generated method stub + + } + + @Override + public void removeJavascriptListener(AlignFrameI af, String listener) + { + // TODO Auto-generated method stub + + } + + @Override + public void mouseOverStructure(String pdbResNum, String chain, + String pdbfile) + { + // TODO Auto-generated method stub + + } + + @Override + public void showOverview() + { + currentAlignFrame.overviewMenuItem_actionPerformed(null); + } + + public void notifyWorker(AlignCalcWorkerI worker, String status) + { + // System.out.println("Jalview worker " + worker.getClass().getSimpleName() + // + " " + status); + } + } + diff --git a/src/jalview/bin/JalviewAppLoader.java b/src/jalview/bin/JalviewAppLoader.java new file mode 100644 index 0000000..51a0330 --- /dev/null +++ b/src/jalview/bin/JalviewAppLoader.java @@ -0,0 +1,1483 @@ +package jalview.bin; + +import jalview.api.AlignFrameI; +import jalview.api.JalviewApp; +import jalview.api.StructureSelectionManagerProvider; +import jalview.datamodel.Alignment; +import jalview.datamodel.AlignmentI; +import jalview.datamodel.AlignmentOrder; +import jalview.datamodel.ColumnSelection; +import jalview.datamodel.HiddenColumns; +import jalview.datamodel.PDBEntry; +import jalview.datamodel.Sequence; +import jalview.datamodel.SequenceGroup; +import jalview.datamodel.SequenceI; +import jalview.gui.AlignFrame; +import jalview.gui.AlignViewport; +import jalview.gui.Desktop; +import jalview.io.AnnotationFile; +import jalview.io.AppletFormatAdapter; +import jalview.io.DataSourceType; +import jalview.io.FeaturesFile; +import jalview.io.FileFormat; +import jalview.io.FileFormatI; +import jalview.io.FileFormats; +import jalview.io.IdentifyFile; +import jalview.io.JPredFile; +import jalview.io.JnetAnnotationMaker; +import jalview.io.NewickFile; +import jalview.structure.SelectionSource; +import jalview.structure.StructureSelectionManager; +import jalview.util.HttpUtils; +import jalview.util.MessageManager; + +import java.awt.EventQueue; +import java.io.IOException; +import java.net.URL; +import java.util.ArrayList; +import java.util.List; +import java.util.StringTokenizer; +import java.util.Vector; + +/** + * A class to load parameters for either JalviewLite or Jalview + * + * @author hansonr + * + */ +public class JalviewAppLoader +{ + + private JalviewApp app; // Jalview or JalviewJS or JalviewLite + + private boolean debug; + + String separator = "\u00AC"; // JalviewLite note: the default used to + // be '|', but many sequence IDS include + // pipes. + + public String getSeparator() + { + return separator; + } + + public void setSeparator(String separator) + { + this.separator = separator; + } + + public JalviewAppLoader(boolean debug) + { + this.debug = debug; + } + + public void load(JalviewApp app) + { + + this.app = app; + + String sep = app.getParameter("separator"); + if (sep != null) + { + if (sep.length() > 0) + { + separator = sep; + } + else + { + throw new Error(MessageManager + .getString("error.invalid_separator_parameter")); + } + } + + loadTree(); + loadScoreFile(); + loadFeatures(); + loadAnnotations(); + loadJnetFile(); + loadPdbFiles(); + callInitCallback(); + } + + /** + * Load PDBFiles if any specified by parameter(s). Returns true if loaded, + * else false. + * + * @param loaderFrame + * @return + */ + protected boolean loadPdbFiles() + { + boolean result = false; + /* + * Undocumented for 2.6 - + * related to JAL-434 + */ + + boolean doAlign = app.getDefaultParameter("alignpdbfiles", false); + app.setAlignPdbStructures(doAlign); + /* + * + * + * + * + * + */ + + // Accumulate pdbs here if they are heading for the same view (if + // alignPdbStructures is true) + Vector pdbs = new Vector<>(); + // create a lazy matcher if we're asked to + jalview.analysis.SequenceIdMatcher matcher = (app + .getDefaultParameter("relaxedidmatch", false)) + ? new jalview.analysis.SequenceIdMatcher( + app.getViewport().getAlignment() + .getSequencesArray()) + : null; + + int pdbFileCount = 0; + String param; + do + { + if (pdbFileCount > 0) + { + param = app.getParameter("PDBFILE" + pdbFileCount); + } + else + { + param = app.getParameter("PDBFILE"); + } + + if (param != null) + { + PDBEntry pdb = new PDBEntry(); + + String seqstring; + SequenceI[] seqs = null; + String[] chains = null; + + StringTokenizer st = new StringTokenizer(param, " "); + + if (st.countTokens() < 2) + { + String sequence = app.getParameter("PDBSEQ"); + if (sequence != null) + { + seqs = new SequenceI[] { matcher == null + ? (Sequence) app.getViewport().getAlignment() + .findName(sequence) + : matcher.findIdMatch(sequence) }; + } + + } + else + { + param = st.nextToken(); + List tmp = new ArrayList<>(); + List tmp2 = new ArrayList<>(); + + while (st.hasMoreTokens()) + { + seqstring = st.nextToken(); + StringTokenizer st2 = new StringTokenizer(seqstring, "="); + if (st2.countTokens() > 1) + { + // This is the chain + tmp2.add(st2.nextToken()); + seqstring = st2.nextToken(); + } + tmp.add(matcher == null + ? (Sequence) app.getViewport().getAlignment() + .findName(seqstring) + : matcher.findIdMatch(seqstring)); + } + + seqs = tmp.toArray(new SequenceI[tmp.size()]); + if (tmp2.size() == tmp.size()) + { + chains = tmp2.toArray(new String[tmp2.size()]); + } + } + pdb.setId(param); + ret[0] = param; + DataSourceType protocol = resolveFileProtocol(app, ret); + // TODO check JAL-357 for files in a jar (CLASSLOADER) + pdb.setFile(ret[0]); + + if (seqs != null) + { + for (int i = 0; i < seqs.length; i++) + { + if (seqs[i] != null) + { + ((Sequence) seqs[i]).addPDBId(pdb); + StructureSelectionManager + .getStructureSelectionManager( + (StructureSelectionManagerProvider) app) + .registerPDBEntry(pdb); + } + else + { + if (debug) + { + // this may not really be a problem but we give a warning + // anyway + System.err.println( + "Warning: Possible input parsing error: Null sequence for attachment of PDB (sequence " + + i + ")"); + } + } + } + + if (doAlign) + { + pdbs.addElement(new Object[] { pdb, seqs, chains, protocol }); + } + else + { + app.newStructureView(pdb, seqs, chains, protocol); + } + } + } + + pdbFileCount++; + } while (param != null || pdbFileCount < 10); + if (pdbs.size() > 0) + { + SequenceI[][] seqs = new SequenceI[pdbs.size()][]; + PDBEntry[] pdb = new PDBEntry[pdbs.size()]; + String[][] chains = new String[pdbs.size()][]; + String[] protocols = new String[pdbs.size()]; + for (int pdbsi = 0, pdbsiSize = pdbs + .size(); pdbsi < pdbsiSize; pdbsi++) + { + Object[] o = pdbs.elementAt(pdbsi); + pdb[pdbsi] = (PDBEntry) o[0]; + seqs[pdbsi] = (SequenceI[]) o[1]; + chains[pdbsi] = (String[]) o[2]; + protocols[pdbsi] = (String) o[3]; + } + app.alignedStructureView(pdb, seqs, chains, protocols); + result = true; + } + return result; + } + + /** + * Load in a Jnetfile if specified by parameter. Returns true if loaded, else + * false. + * + * @param alignFrame + * @return + */ + protected boolean loadJnetFile() + { + boolean result = false; + String param = app.getParameter("jnetfile"); + if (param == null) + { + // jnet became jpred around 2016 + param = app.getParameter("jpredfile"); + } + if (param != null) + { + try + { + ret[0] = param; + DataSourceType protocol = resolveFileProtocol(app, ret); + JPredFile predictions = new JPredFile(ret[0], protocol); + JnetAnnotationMaker.add_annotation(predictions, + app.getViewport().getAlignment(), 0, false); + // false == do not add sequence profile from concise output + app.getViewport().getAlignment().setupJPredAlignment(); + app.updateForAnnotations(); + result = true; + } catch (Exception ex) + { + ex.printStackTrace(); + } + } + return result; + } + + /** + * Load annotations if specified by parameter. Returns true if loaded, else + * false. + * + * @param alignFrame + * @return + */ + protected boolean loadAnnotations() + { + boolean result = false; + String param = app.getParameter("annotations"); + if (param != null) + { + ret[0] = param; + DataSourceType protocol = resolveFileProtocol(app, ret); + param = ret[0]; + if (new AnnotationFile().annotateAlignmentView(app.getViewport(), + param, protocol)) + { + app.updateForAnnotations(); + result = true; + } + else + { + System.err + .println("Annotations were not added from annotation file '" + + param + "'"); + } + } + return result; + } + + /** + * Load features file and view settings as specified by parameters. Returns + * true if features were loaded, else false. + * + * @param alignFrame + * @return + */ + protected boolean loadFeatures() + { + boolean result = false; + // /////////////////////////// + // modify display of features + // we do this before any features have been loaded, ensuring any hidden + // groups are hidden when features first displayed + // + // hide specific groups + // + String param = app.getParameter("hidefeaturegroups"); + if (param != null) + { + app.setFeatureGroupState(separatorListToArray(param, separator), + false); + // app.setFeatureGroupStateOn(newAlignFrame, param, false); + } + // show specific groups + param = app.getParameter("showfeaturegroups"); + if (param != null) + { + app.setFeatureGroupState(separatorListToArray(param, separator), + true); + // app.setFeatureGroupStateOn(newAlignFrame, param, true); + } + // and now load features + param = app.getParameter("features"); + if (param != null) + { + ret[0] = param; + DataSourceType protocol = resolveFileProtocol(app, ret); + + result = app.parseFeaturesFile(ret[0], protocol); + } + + param = app.getParameter("showFeatureSettings"); + if (param != null && param.equalsIgnoreCase("true")) + { + app.newFeatureSettings(); + } + return result; + } + + /** + * Load a score file if specified by parameter. Returns true if file was + * loaded, else false. + * + * @param loaderFrame + */ + protected boolean loadScoreFile() + { + boolean result = false; + String sScoreFile = app.getParameter("scoreFile"); + if (sScoreFile != null && !"".equals(sScoreFile)) + { + try + { + if (debug) + { + System.err.println( + "Attempting to load T-COFFEE score file from the scoreFile parameter"); + } + result = app.loadScoreFile(sScoreFile); + if (!result) + { + System.err.println( + "Failed to parse T-COFFEE parameter as a valid score file ('" + + sScoreFile + "')"); + } + } catch (Exception e) + { + System.err.printf("Cannot read score file: '%s'. Cause: %s \n", + sScoreFile, e.getMessage()); + } + } + return result; + } + + String[] ret = new String[1]; + + /** + * Load a tree for the alignment if specified by parameter. Returns true if a + * tree was loaded, else false. + * + * @param loaderFrame + * @return + */ + protected boolean loadTree() + { + boolean result = false; + String treeFile = app.getParameter("tree"); + if (treeFile == null) + { + treeFile = app.getParameter("treeFile"); + } + + if (treeFile != null) + { + try + { + ret[0] = treeFile; + NewickFile fin = new NewickFile(treeFile, + resolveFileProtocol(app, ret)); + fin.parse(); + + if (fin.getTree() != null) + { + app.loadTree(fin, ret[0]); + result = true; + if (debug) + { + System.out.println("Successfully imported tree."); + } + } + else + { + if (debug) + { + System.out.println( + "Tree parameter did not resolve to a valid tree."); + } + } + } catch (Exception ex) + { + ex.printStackTrace(); + } + } + return result; + } + + /** + * form a complete URL given a path to a resource and a reference location on + * the same server + * + * @param targetPath + * - an absolute path on the same server as localref or a document + * located relative to localref + * @param localref + * - a URL on the same server as url + * @return a complete URL for the resource located by url + */ + public static String resolveUrlForLocalOrAbsolute(String targetPath, + URL localref) + { + String resolvedPath = ""; + if (targetPath.startsWith("/")) + { + String codebase = localref.toString(); + String localfile = localref.getFile(); + resolvedPath = codebase.substring(0, + codebase.length() - localfile.length()) + targetPath; + return resolvedPath; + } + + /* + * get URL path and strip off any trailing file e.g. + * www.jalview.org/examples/index.html#applets?a=b is trimmed to + * www.jalview.org/examples/ + */ + String urlPath = localref.toString(); + String directoryPath = urlPath; + int lastSeparator = directoryPath.lastIndexOf("/"); + if (lastSeparator > 0) + { + directoryPath = directoryPath.substring(0, lastSeparator + 1); + } + + if (targetPath.startsWith("/")) + { + /* + * construct absolute URL to a file on the server - this is not allowed? + */ + // String localfile = localref.getFile(); + // resolvedPath = urlPath.substring(0, + // urlPath.length() - localfile.length()) + // + targetPath; + resolvedPath = directoryPath + targetPath.substring(1); + } + else + { + resolvedPath = directoryPath + targetPath; + } + // if (debug) + // { + // System.err.println( + // "resolveUrlForLocalOrAbsolute returning " + resolvedPath); + // } + return resolvedPath; + } + + /** + * parse the string into a list + * + * @param list + * @param separator + * @return elements separated by separator + */ + public static String[] separatorListToArray(String list, String separator) + { + // TODO use StringUtils version (slightly different...) + int seplen = separator.length(); + if (list == null || list.equals("") || list.equals(separator)) + { + return null; + } + Vector jv = new Vector<>(); + int cp = 0, pos; + while ((pos = list.indexOf(separator, cp)) > cp) + { + jv.addElement(list.substring(cp, pos)); + cp = pos + seplen; + } + if (cp < list.length()) + { + String c = list.substring(cp); + if (!c.equals(separator)) + { + jv.addElement(c); + } + } + if (jv.size() > 0) + { + String[] v = new String[jv.size()]; + for (int i = 0; i < v.length; i++) + { + v[i] = jv.elementAt(i); + } + jv.removeAllElements(); + // if (debug) + // { + // System.err.println("Array from '" + separator + // + "' separated List:\n" + v.length); + // for (int i = 0; i < v.length; i++) + // { + // System.err.println("item " + i + " '" + v[i] + "'"); + // } + // } + return v; + } + // if (debug) + // { + // System.err.println( + // "Empty Array from '" + separator + "' separated List"); + // } + return null; + } + + public static DataSourceType resolveFileProtocol(JalviewApp app, + String[] retPath) + { + String path = retPath[0]; + /* + * is it paste data? + */ + if (path.startsWith("PASTE")) + { + retPath[0] = path.substring(5); + return DataSourceType.PASTE; + } + + /* + * is it a URL? + */ + if (path.indexOf("://") >= 0) + { + return DataSourceType.URL; + } + + /* + * try relative to document root + */ + URL documentBase = app.getDocumentBase(); + String withDocBase = resolveUrlForLocalOrAbsolute(path, documentBase); + if (HttpUtils.isValidUrl(withDocBase)) + { + // if (debug) + // { + // System.err.println("Prepended document base '" + documentBase + // + "' to make: '" + withDocBase + "'"); + // } + retPath[0] = withDocBase; + return DataSourceType.URL; + } + + /* + * try relative to codebase (if different to document base) + */ + URL codeBase = app.getCodeBase(); + String withCodeBase = resolveUrlForLocalOrAbsolute(path, codeBase); + if (!withCodeBase.equals(withDocBase) + && HttpUtils.isValidUrl(withCodeBase)) + { + // if (debug) + // { + // System.err.println("Prepended codebase '" + codeBase + // + "' to make: '" + withCodeBase + "'"); + // } + retPath[0] = withCodeBase; + return DataSourceType.URL; + } + + /* + * try locating by classloader; try this last so files in the directory + * are resolved using document base + */ + if (inArchive(app.getClass(), path)) + { + return DataSourceType.CLASSLOADER; + } + return null; + } + + /** + * Discovers whether the given file is in the Applet Archive + * + * @param f + * String + * @return boolean + */ + private static boolean inArchive(Class c, String f) + { + // This might throw a security exception in certain browsers + // Netscape Communicator for instance. + try + { + boolean rtn = (c.getResourceAsStream("/" + f) != null); + // if (debug) + // { + // System.err.println("Resource '" + f + "' was " + // + (rtn ? "" : "not ") + "located by classloader."); + // } + return rtn; + } catch (Exception ex) + { + System.out.println("Exception checking resources: " + f + " " + ex); + return false; + } + } + + public void callInitCallback() + { + String initjscallback = app.getParameter("oninit"); + if (initjscallback == null) + { + return; + } + initjscallback = initjscallback.trim(); + if (initjscallback.length() > 0) + { + // TODO + } + } + + /** + * read sequence1...sequenceN as a raw alignment + * + * @param jalviewApp + * @return + */ + public String getPastedSequence(JalviewApp jalviewApp) + { + StringBuffer data = new StringBuffer("PASTE"); + int i = 1; + String file = null; + while ((file = app.getParameter("sequence" + i)) != null) + { + data.append(file.toString() + "\n"); + i++; + } + if (data.length() > 5) + { + file = data.toString(); + } + return file; + } + + /** + * concatenate the list with separator + * + * @param list + * @param separator + * @return concatenated string + */ + public static String arrayToSeparatorList(String[] list, String separator) + { + // TODO use StringUtils version + StringBuffer v = new StringBuffer(); + if (list != null && list.length > 0) + { + for (int i = 0, iSize = list.length; i < iSize; i++) + { + if (list[i] != null) + { + if (i > 0) + { + v.append(separator); + } + v.append(list[i]); + } + } + // if (debug) + // { + // System.err + // .println("Returning '" + separator + "' separated List:\n"); + // System.err.println(v); + // } + return v.toString(); + } + // if (debug) + // { + // System.err.println( + // "Returning empty '" + separator + "' separated List\n"); + // } + return "" + separator; + } + + public String arrayToSeparatorList(String[] array) + { + return arrayToSeparatorList(array, separator); + } + + public String getSelectedSequencesFrom(AlignFrameI alf, String sep) + { + StringBuffer result = new StringBuffer(""); + if (sep == null || sep.length() == 0) + { + sep = separator; // "+0x00AC; + } + AlignViewport v = ((AlignFrame) alf).getViewport(); + if (v.getSelectionGroup() != null) + { + SequenceI[] seqs = v.getSelectionGroup() + .getSequencesInOrder(v.getAlignment()); + + for (int i = 0; i < seqs.length; i++) + { + result.append(seqs[i].getName()); + result.append(sep); + } + } + + return result.toString(); + } + + public void setFeatureGroupStateOn(final AlignFrameI alf, + final String groups, boolean state) + { + java.awt.EventQueue.invokeLater(new Runnable() + { + @Override + public void run() + { + ((AlignFrame) alf).setFeatureGroupState( + separatorListToArray(groups, separator), state); + } + }); + } + + public String getFeatureGroupsOfStateOn(AlignFrameI alf, boolean visible) + { + return arrayToSeparatorList( + ((AlignFrame) alf).getFeatureGroupsOfState(visible)); + } + + public void scrollViewToIn(final AlignFrameI alf, final String topRow, + final String leftHandColumn) + { + java.awt.EventQueue.invokeLater(new Runnable() + { + @Override + public void run() + { + try + { + ((AlignFrame) alf).scrollTo(new Integer(topRow).intValue(), + new Integer(leftHandColumn).intValue()); + + } catch (Exception ex) + { + System.err.println("Couldn't parse integer arguments (topRow='" + + topRow + "' and leftHandColumn='" + leftHandColumn + + "')"); + ex.printStackTrace(); + } + } + }); + } + + public void scrollViewToRowIn(final AlignFrameI alf, final String topRow) + { + + java.awt.EventQueue.invokeLater(new Runnable() + { + @Override + public void run() + { + try + { + ((AlignFrame) alf).scrollToRow(new Integer(topRow).intValue()); + + } catch (Exception ex) + { + System.err.println("Couldn't parse integer arguments (topRow='" + + topRow + "')"); + ex.printStackTrace(); + } + + } + }); + } + + public void scrollViewToColumnIn(final AlignFrameI alf, + final String leftHandColumn) + { + java.awt.EventQueue.invokeLater(new Runnable() + { + + @Override + public void run() + { + try + { + ((AlignFrame) alf) + .scrollToColumn(new Integer(leftHandColumn).intValue()); + + } catch (Exception ex) + { + System.err.println( + "Couldn't parse integer arguments (leftHandColumn='" + + leftHandColumn + "')"); + ex.printStackTrace(); + } + } + }); + + } + + public boolean addPdbFile(AlignFrameI alf, String sequenceId, + String pdbEntryString, String pdbFile) + { + AlignFrame alFrame = (AlignFrame) alf; + SequenceI toaddpdb = alFrame.getViewport().getAlignment() + .findName(sequenceId); + boolean needtoadd = false; + if (toaddpdb != null) + { + Vector pdbe = toaddpdb.getAllPDBEntries(); + PDBEntry pdbentry = null; + if (pdbe != null && pdbe.size() > 0) + { + for (int pe = 0, peSize = pdbe.size(); pe < peSize; pe++) + { + pdbentry = pdbe.elementAt(pe); + if (!pdbentry.getId().equals(pdbEntryString) + && !pdbentry.getFile().equals(pdbFile)) + { + pdbentry = null; + } + else + { + continue; + } + } + } + if (pdbentry == null) + { + pdbentry = new PDBEntry(); + pdbentry.setId(pdbEntryString); + pdbentry.setFile(pdbFile); + needtoadd = true; // add this new entry to sequence. + } + // resolve data source + // TODO: this code should be a refactored to an io package + DataSourceType protocol = AppletFormatAdapter.resolveProtocol(pdbFile, + FileFormat.PDB); + if (protocol == null) + { + return false; + } + if (needtoadd) + { + pdbentry.setProperty("protocol", protocol); + toaddpdb.addPDBId(pdbentry); + alFrame.alignPanel.getStructureSelectionManager() + .registerPDBEntry(pdbentry); + } + } + return true; + } + + public AlignFrameI loadAlignment(String text, int width, int height, + String title) + { + AlignmentI al = null; + + try + { + FileFormatI format = new IdentifyFile().identify(text, + DataSourceType.PASTE); + al = new AppletFormatAdapter().readFile(text, DataSourceType.PASTE, + format); + if (al.getHeight() > 0) + { + return new AlignFrame(al, width, height, title); + } + } catch (IOException ex) + { + ex.printStackTrace(); + } + return null; + } + + public String getFeatureGroupsOn(AlignFrameI alf) + { + return arrayToSeparatorList( + ((AlignFrame) alf).getFeatureGroups()); + } + + public void highlightIn(final AlignFrameI alf, final String sequenceId, + final String position, final String alignedPosition) + { + // TODO: could try to highlight in all alignments if alf==null + jalview.analysis.SequenceIdMatcher matcher = new jalview.analysis.SequenceIdMatcher( + ((AlignFrame) alf).getViewport().getAlignment() + .getSequencesArray()); + final SequenceI sq = matcher.findIdMatch(sequenceId); + if (sq != null) + { + int apos = -1; + try + { + apos = new Integer(position).intValue(); + apos--; + } catch (NumberFormatException ex) + { + return; + } + final int pos = apos; + // use vamsas listener to broadcast to all listeners in scope + if (alignedPosition != null && (alignedPosition.trim().length() == 0 + || alignedPosition.toLowerCase().indexOf("false") > -1)) + { + java.awt.EventQueue.invokeLater(new Runnable() + { + @Override + public void run() + { + StructureSelectionManager + .getStructureSelectionManager(Desktop.getInstance()) + .mouseOverVamsasSequence(sq, sq.findIndex(pos), null); + } + }); + } + else + { + java.awt.EventQueue.invokeLater(new Runnable() + { + @Override + public void run() + { + StructureSelectionManager + .getStructureSelectionManager(Desktop.getInstance()) + .mouseOverVamsasSequence(sq, pos, null); + } + }); + } + } + } + + public void selectIn(final AlignFrameI alf, String sequenceIds, + String columns, String sep) + { + if (sep == null || sep.length() == 0) + { + sep = separator; + } + else + { + if (debug) + { + System.err.println("Selecting region using separator string '" + + separator + "'"); + } + } + // deparse fields + String[] ids = JalviewAppLoader.separatorListToArray(sequenceIds, sep); + String[] cols = JalviewAppLoader.separatorListToArray(columns, sep); + final SequenceGroup sel = new SequenceGroup(); + final ColumnSelection csel = new ColumnSelection(); + AlignmentI al = ((AlignFrame) alf).getViewport().getAlignment(); + jalview.analysis.SequenceIdMatcher matcher = new jalview.analysis.SequenceIdMatcher( + ((AlignFrame) alf).getViewport().getAlignment() + .getSequencesArray()); + int start = 0, end = al.getWidth(), alw = al.getWidth(); + boolean seqsfound = true; + if (ids != null && ids.length > 0) + { + seqsfound = false; + for (int i = 0; i < ids.length; i++) + { + if (ids[i].trim().length() == 0) + { + continue; + } + SequenceI sq = matcher.findIdMatch(ids[i]); + if (sq != null) + { + seqsfound = true; + sel.addSequence(sq, false); + } + } + } + boolean inseqpos = false; + if (cols != null && cols.length > 0) + { + boolean seset = false; + for (int i = 0; i < cols.length; i++) + { + String cl = cols[i].trim(); + if (cl.length() == 0) + { + continue; + } + int p; + if ((p = cl.indexOf("-")) > -1) + { + int from = -1, to = -1; + try + { + from = new Integer(cl.substring(0, p)).intValue(); + from--; + } catch (NumberFormatException ex) + { + System.err.println( + "ERROR: Couldn't parse first integer in range element column selection string '" + + cl + "' - format is 'from-to'"); + return; + } + try + { + to = new Integer(cl.substring(p + 1)).intValue(); + to--; + } catch (NumberFormatException ex) + { + System.err.println( + "ERROR: Couldn't parse second integer in range element column selection string '" + + cl + "' - format is 'from-to'"); + return; + } + if (from >= 0 && to >= 0) + { + // valid range + if (from < to) + { + int t = to; + to = from; + to = t; + } + if (!seset) + { + start = from; + end = to; + seset = true; + } + else + { + // comment to prevent range extension + if (start > from) + { + start = from; + } + if (end < to) + { + end = to; + } + } + for (int r = from; r <= to; r++) + { + if (r >= 0 && r < alw) + { + csel.addElement(r); + } + } + if (debug) + { + System.err.println("Range '" + cl + "' deparsed as [" + from + + "," + to + "]"); + } + } + else + { + System.err.println("ERROR: Invalid Range '" + cl + + "' deparsed as [" + from + "," + to + "]"); + } + } + else + { + int r = -1; + try + { + r = new Integer(cl).intValue(); + r--; + } catch (NumberFormatException ex) + { + if (cl.toLowerCase().equals("sequence")) + { + // we are in the dataset sequence's coordinate frame. + inseqpos = true; + } + else + { + System.err.println( + "ERROR: Couldn't parse integer from point selection element of column selection string '" + + cl + "'"); + return; + } + } + if (r >= 0 && r <= alw) + { + if (!seset) + { + start = r; + end = r; + seset = true; + } + else + { + // comment to prevent range extension + if (start > r) + { + start = r; + } + if (end < r) + { + end = r; + } + } + csel.addElement(r); + if (debug) + { + System.err.println("Point selection '" + cl + + "' deparsed as [" + r + "]"); + } + } + else + { + System.err.println("ERROR: Invalid Point selection '" + cl + + "' deparsed as [" + r + "]"); + } + } + } + } + if (seqsfound) + { + // we only propagate the selection when it was the null selection, or the + // given sequences were found in the alignment. + if (inseqpos && sel.getSize() > 0) + { + // assume first sequence provides reference frame ? + SequenceI rs = sel.getSequenceAt(0); + start = rs.findIndex(start); + end = rs.findIndex(end); + List cs = new ArrayList<>(csel.getSelected()); + csel.clear(); + for (Integer selectedCol : cs) + { + csel.addElement(rs.findIndex(selectedCol)); + } + } + sel.setStartRes(start); + sel.setEndRes(end); + EventQueue.invokeLater(new Runnable() + { + @Override + public void run() + { + ((AlignFrame) alf).select(sel, csel, ((AlignFrame) alf) + .getCurrentView().getAlignment().getHiddenColumns()); + } + }); + } + } + + public String getAlignmentOrderFrom(AlignFrameI alf, String sep) + { + AlignmentI alorder = ((AlignFrame) alf).getViewport().getAlignment(); + String[] order = new String[alorder.getHeight()]; + for (int i = 0; i < order.length; i++) + { + order[i] = alorder.getSequenceAt(i).getName(); + } + return arrayToSeparatorList(order, sep); + } + + public String getSelectedSequencesAsAlignmentFrom(AlignFrameI alf, + String format, String suffix) + { + try + { + AlignViewport vp = ((AlignFrame) alf).getViewport(); + FileFormatI theFormat = FileFormats.getInstance().forName(format); + boolean seqlimits = (suffix == null + || suffix.equalsIgnoreCase("true")); + if (vp.getSelectionGroup() != null) + { + // JBPNote: getSelectionAsNewSequence behaviour has changed - this + // method now returns a full copy of sequence data + // TODO consider using getSequenceSelection instead here + String reply = new AppletFormatAdapter().formatSequences(theFormat, + new Alignment(vp.getSelectionAsNewSequence()), + seqlimits); + return reply; + } + } catch (IllegalArgumentException ex) + { + ex.printStackTrace(); + return "Error retrieving alignment, possibly invalid format specifier: " + + format; + } + return ""; + } + + public String orderAlignmentBy(AlignFrameI alf, String order, + String undoName, String sep) + { + if (sep == null || sep.length() == 0) + { + sep = separator; + } + String[] ids = JalviewAppLoader.separatorListToArray(order, sep); + SequenceI[] sqs = null; + if (ids != null && ids.length > 0) + { + jalview.analysis.SequenceIdMatcher matcher = new jalview.analysis.SequenceIdMatcher( + ((AlignFrame) alf).getViewport().getAlignment() + .getSequencesArray()); + int s = 0; + sqs = new SequenceI[ids.length]; + for (int i = 0; i < ids.length; i++) + { + if (ids[i].trim().length() == 0) + { + continue; + } + SequenceI sq = matcher.findIdMatch(ids[i]); + if (sq != null) + { + sqs[s++] = sq; + } + } + if (s > 0) + { + SequenceI[] sqq = new SequenceI[s]; + System.arraycopy(sqs, 0, sqq, 0, s); + sqs = sqq; + } + else + { + sqs = null; + } + } + if (sqs == null) + { + return ""; + } + ; + final AlignmentOrder aorder = new AlignmentOrder(sqs); + + if (undoName != null && undoName.trim().length() == 0) + { + undoName = null; + } + final String _undoName = undoName; + // TODO: deal with synchronization here: cannot raise any events until after + // this has returned. + return ((AlignFrame) alf).sortBy(aorder, _undoName) ? "true" : ""; + } + + public String getAlignmentFrom(AlignFrameI alf, String format, + String suffix) + { + try + { + boolean seqlimits = (suffix == null + || suffix.equalsIgnoreCase("true")); + + FileFormatI theFormat = FileFormats.getInstance().forName(format); + String reply = new AppletFormatAdapter().formatSequences(theFormat, + ((AlignFrame) alf).getViewport().getAlignment(), seqlimits); + return reply; + } catch (IllegalArgumentException ex) + { + ex.printStackTrace(); + return "Error retrieving alignment, possibly invalid format specifier: " + + format; + } + } + + public void loadAnnotationFrom(AlignFrameI alf, String annotation) + { + if (new AnnotationFile().annotateAlignmentView( + ((AlignFrame) alf).getViewport(), annotation, + DataSourceType.PASTE)) + { + ((AlignFrame) alf).alignPanel.fontChanged(); + ((AlignFrame) alf).alignPanel.setScrollValues(0, 0); + } + else + { + ((AlignFrame) alf).parseFeaturesFile(annotation, + DataSourceType.PASTE); + } + } + + public boolean loadFeaturesFrom(AlignFrameI alf, String features, + boolean autoenabledisplay) + { + boolean ret = ((AlignFrame) alf).parseFeaturesFile(features, + DataSourceType.PASTE); + if (!ret) + { + return false; + } + if (autoenabledisplay) + { + ((AlignFrame) alf).getViewport().setShowSequenceFeatures(true); + // this next was for a checkbox in JalviewLite + // ((AlignFrame) alf).getViewport().sequenceFeatures.setState(true); + } + return true; + } + + public String getFeaturesFrom(AlignFrameI alf, String format) + { + AlignFrame f = ((AlignFrame) alf); + + String features; + FeaturesFile formatter = new FeaturesFile(); + if (format.equalsIgnoreCase("Jalview")) + { + features = formatter.printJalviewFormat( + f.getViewport().getAlignment().getSequencesArray(), + f.alignPanel.getFeatureRenderer(), true); + } + else + { + features = formatter.printGffFormat( + f.getViewport().getAlignment().getSequencesArray(), + f.alignPanel.getFeatureRenderer(), true); + } + + if (features == null) + { + features = ""; + } + return features; + + } + + public String getAnnotationFrom(AlignFrameI alf) + { + AlignFrame f = (AlignFrame) alf; + String annotation = new AnnotationFile() + .printAnnotationsForView(f.getViewport()); + return annotation; + } + + public AlignFrameI newViewFrom(AlignFrameI alf, String name) + { + return (AlignFrameI) ((AlignFrame) alf).newView(name, true); + } + + public String[] separatorListToArray(String list) + { + return separatorListToArray(list, separator); + } + + public Object[] getSelectionForListener(AlignFrameI currentFrame, + SequenceGroup seqsel, ColumnSelection colsel, + HiddenColumns hidden, SelectionSource source, Object alignFrame) + { + // System.err.println("Testing selection event relay to + // jsfunction:"+_listener); + String setid = ""; + AlignFrame src = (AlignFrame) alignFrame; + if (source != null) + { + if (source instanceof AlignViewport + && ((AlignFrame) currentFrame).getViewport() == source) + { + // should be valid if it just generated an event! + src = (AlignFrame) currentFrame; + + } + } + String[] seqs = new String[] {}; + String[] cols = new String[] {}; + int strt = 0, end = (src == null) ? -1 + : src.alignPanel.av.getAlignment().getWidth(); + if (seqsel != null && seqsel.getSize() > 0) + { + seqs = new String[seqsel.getSize()]; + for (int i = 0; i < seqs.length; i++) + { + seqs[i] = seqsel.getSequenceAt(i).getName(); + } + if (strt < seqsel.getStartRes()) + { + strt = seqsel.getStartRes(); + } + if (end == -1 || end > seqsel.getEndRes()) + { + end = seqsel.getEndRes(); + } + } + if (colsel != null && !colsel.isEmpty()) + { + if (end == -1) + { + end = colsel.getMax() + 1; + } + cols = new String[colsel.getSelected().size()]; + for (int i = 0; i < cols.length; i++) + { + cols[i] = "" + (1 + colsel.getSelected().get(i).intValue()); + } + } + else + { + if (seqsel != null && seqsel.getSize() > 0) + { + // send a valid range, otherwise we send the empty selection + cols = new String[2]; + cols[0] = "" + (1 + strt) + "-" + (1 + end); + } + } + return new Object[] { src, setid, arrayToSeparatorList(seqs), + arrayToSeparatorList(cols) }; + } + +} \ No newline at end of file diff --git a/src/jalview/bin/JalviewJS2.java b/src/jalview/bin/JalviewJS2.java index 26110f8..6f69f8a 100644 --- a/src/jalview/bin/JalviewJS2.java +++ b/src/jalview/bin/JalviewJS2.java @@ -20,16 +20,37 @@ public class JalviewJS2 static { /** - * @j2sNative + * @ could do it this way: * - * J2S.thisApplet.__Info.args = - * ["open","examples/uniref50.fa","features", - * "examples/exampleFeatures.txt"]; + * j2sNative + * + * J2S.thisApplet.__Info.args = [ "open","examples/uniref50.fa", + * "features","examples/exampleFeatures.txt", "noannotation" ]; */ } public static void main(String[] args) throws Exception { + if (args.length == 0) + { + args = new String[] { + // "headless", + "open", "examples/uniref50.fa", + "features", + "examples/exampleFeatures.txt" + , "noannotation" + , "showoverview" + // , "png", "test-bh.png" + }; + } + + // String cmds = "nodisplay -open examples/uniref50.fa -sortbytree -props + // test/jalview/io/testProps.jvprops -colour zappo " + // + "-jabaws http://www.compbio.dundee.ac.uk/jabaws -nosortbytree " + // + "-features examples/testdata/plantfdx.features -annotations + // examples/testdata/plantfdx.annotations -tree + // examples/testdata/uniref50_test_tree"; + // args = cmds.split(" "); Jalview.main(args); //showFocusTimer(); } diff --git a/src/jalview/bin/JalviewJSApi.java b/src/jalview/bin/JalviewJSApi.java new file mode 100644 index 0000000..b1fed25 --- /dev/null +++ b/src/jalview/bin/JalviewJSApi.java @@ -0,0 +1,52 @@ +package jalview.bin; + +import jalview.gui.AlignFrame; +import jalview.javascript.JalviewLiteJsApi; + +/** + * JAL-3369 JalviewJS API BH 2019.07.17 + * + * @author hansonr + * + */ +public interface JalviewJSApi extends JalviewLiteJsApi +{ + + void showOverview(); + + /** + * process commandline arguments after the JavaScript application has started + * + * @param args + * @return + */ + Object parseArguments(String[] args); + + + /** + * Open a new Tree panel on the desktop statically. Params are standard (not + * set by Groovy). No dialog is opened. + * + * @param af + * may be null + * @param treeType + * @param modelName + * @return null, or the string "label.you_need_at_least_n_sequences" if number + * of sequences selected is inappropriate + */ + public Object openTreePanel(AlignFrame af, String treeType, + String modelName); + + /** + * public static method for JalviewJS API to open a PCAPanel without + * necessarily using a dialog. + * + * @param af + * may be null + * @param modelName + * @return the PCAPanel, or the string "label.you_need_at_least_n_sequences" + * if number of sequences selected is inappropriate + */ + public Object openPcaPanel(AlignFrame af, String modelName); + +} diff --git a/src/jalview/bin/JalviewLite.java b/src/jalview/bin/JalviewLite.java index e7f2a53..75b0add 100644 --- a/src/jalview/bin/JalviewLite.java +++ b/src/jalview/bin/JalviewLite.java @@ -21,6 +21,9 @@ package jalview.bin; import jalview.analysis.AlignmentUtils; +import jalview.api.AlignFrameI; +import jalview.api.AlignViewportI; +import jalview.api.JalviewApp; import jalview.api.StructureSelectionManagerProvider; import jalview.appletgui.AlignFrame; import jalview.appletgui.AlignViewport; @@ -31,8 +34,8 @@ import jalview.datamodel.Alignment; import jalview.datamodel.AlignmentI; import jalview.datamodel.AlignmentOrder; import jalview.datamodel.ColumnSelection; +import jalview.datamodel.HiddenColumns; import jalview.datamodel.PDBEntry; -import jalview.datamodel.Sequence; import jalview.datamodel.SequenceGroup; import jalview.datamodel.SequenceI; import jalview.io.AnnotationFile; @@ -42,18 +45,19 @@ import jalview.io.FileFormatI; import jalview.io.FileFormats; import jalview.io.FileParse; import jalview.io.IdentifyFile; -import jalview.io.JPredFile; -import jalview.io.JnetAnnotationMaker; import jalview.io.NewickFile; import jalview.javascript.JSFunctionExec; import jalview.javascript.JalviewLiteJsApi; import jalview.javascript.JsCallBack; import jalview.javascript.MouseOverStructureListener; +import jalview.renderer.seqfeatures.FeatureRenderer; import jalview.structure.SelectionListener; +import jalview.structure.SelectionSource; import jalview.structure.StructureSelectionManager; +import jalview.structure.VamsasSource; import jalview.util.ColorUtils; -import jalview.util.HttpUtils; import jalview.util.MessageManager; +import jalview.viewmodel.AlignmentViewport; import java.applet.Applet; import java.awt.Button; @@ -73,7 +77,6 @@ import java.net.URL; import java.util.ArrayList; import java.util.Hashtable; import java.util.List; -import java.util.StringTokenizer; import java.util.Vector; import netscape.javascript.JSObject; @@ -84,10 +87,16 @@ import netscape.javascript.JSObject; * @author $author$ * @version $Revision: 1.92 $ */ +@SuppressWarnings("serial") public class JalviewLite extends Applet - implements StructureSelectionManagerProvider, JalviewLiteJsApi + implements StructureSelectionManagerProvider, JalviewLiteJsApi, + JalviewApp { + public JalviewLite() + { + appLoader = new JalviewAppLoader(debug); + } private static final String TRUE = "true"; private static final String FALSE = "false"; @@ -97,6 +106,12 @@ public class JalviewLite extends Applet return StructureSelectionManager.getStructureSelectionManager(this); } + @Override + public StructureSelectionManagerProvider getStructureSelectionManagerProvider() + { + return this; + } + // ///////////////////////////////////////// // The following public methods may be called // externally, eg via javascript in HTML page @@ -130,7 +145,7 @@ public class JalviewLite extends Applet * .AlignFrame) */ @Override - public String getSelectedSequencesFrom(AlignFrame alf) + public String getSelectedSequencesFrom(AlignFrameI alf) { return getSelectedSequencesFrom(alf, separator); // ""+0x00AC); } @@ -143,17 +158,18 @@ public class JalviewLite extends Applet * .AlignFrame, java.lang.String) */ @Override - public String getSelectedSequencesFrom(AlignFrame alf, String sep) + public String getSelectedSequencesFrom(AlignFrameI alf, String sep) { StringBuffer result = new StringBuffer(""); if (sep == null || sep.length() == 0) { sep = separator; // "+0x00AC; } - if (alf.viewport.getSelectionGroup() != null) + if (((AlignFrame) alf).viewport.getSelectionGroup() != null) { - SequenceI[] seqs = alf.viewport.getSelectionGroup() - .getSequencesInOrder(alf.viewport.getAlignment()); + SequenceI[] seqs = ((AlignFrame) alf).viewport.getSelectionGroup() + .getSequencesInOrder( + ((AlignFrame) alf).viewport.getAlignment()); for (int i = 0; i < seqs.length; i++) { @@ -186,19 +202,19 @@ public class JalviewLite extends Applet * java.lang.String, java.lang.String, java.lang.String) */ @Override - public void highlightIn(final AlignFrame alf, final String sequenceId, + public void highlightIn(final AlignFrameI alf, final String sequenceId, final String position, final String alignedPosition) { // TODO: could try to highlight in all alignments if alf==null jalview.analysis.SequenceIdMatcher matcher = new jalview.analysis.SequenceIdMatcher( - alf.viewport.getAlignment().getSequencesArray()); + ((AlignFrame) alf).viewport.getAlignment().getSequencesArray()); final SequenceI sq = matcher.findIdMatch(sequenceId); if (sq != null) { int apos = -1; try { - apos = Integer.valueOf(position).intValue(); + apos = new Integer(position).intValue(); apos--; } catch (NumberFormatException ex) { @@ -266,7 +282,7 @@ public class JalviewLite extends Applet * java.lang.String, java.lang.String) */ @Override - public void selectIn(AlignFrame alf, String sequenceIds, String columns) + public void selectIn(AlignFrameI alf, String sequenceIds, String columns) { selectIn(alf, sequenceIds, columns, separator); } @@ -278,7 +294,7 @@ public class JalviewLite extends Applet * java.lang.String, java.lang.String, java.lang.String) */ @Override - public void selectIn(final AlignFrame alf, String sequenceIds, + public void selectIn(final AlignFrameI alf, String sequenceIds, String columns, String sep) { if (sep == null || sep.length() == 0) @@ -294,13 +310,13 @@ public class JalviewLite extends Applet } } // deparse fields - String[] ids = separatorListToArray(sequenceIds, sep); - String[] cols = separatorListToArray(columns, sep); + String[] ids = JalviewAppLoader.separatorListToArray(sequenceIds, sep); + String[] cols = JalviewAppLoader.separatorListToArray(columns, sep); final SequenceGroup sel = new SequenceGroup(); final ColumnSelection csel = new ColumnSelection(); - AlignmentI al = alf.viewport.getAlignment(); + AlignmentI al = ((AlignFrame) alf).viewport.getAlignment(); jalview.analysis.SequenceIdMatcher matcher = new jalview.analysis.SequenceIdMatcher( - alf.viewport.getAlignment().getSequencesArray()); + ((AlignFrame) alf).viewport.getAlignment().getSequencesArray()); int start = 0, end = al.getWidth(), alw = al.getWidth(); boolean seqsfound = true; if (ids != null && ids.length > 0) @@ -337,7 +353,7 @@ public class JalviewLite extends Applet int from = -1, to = -1; try { - from = Integer.valueOf(cl.substring(0, p)).intValue(); + from = new Integer(cl.substring(0, p)).intValue(); from--; } catch (NumberFormatException ex) { @@ -348,7 +364,7 @@ public class JalviewLite extends Applet } try { - to = Integer.valueOf(cl.substring(p + 1)).intValue(); + to = new Integer(cl.substring(p + 1)).intValue(); to--; } catch (NumberFormatException ex) { @@ -408,7 +424,7 @@ public class JalviewLite extends Applet int r = -1; try { - r = Integer.valueOf(cl).intValue(); + r = new Integer(cl).intValue(); r--; } catch (NumberFormatException ex) { @@ -484,8 +500,8 @@ public class JalviewLite extends Applet @Override public void run() { - alf.select(sel, csel, - alf.getAlignViewport().getAlignment().getHiddenColumns()); + ((AlignFrame) alf).select(sel, csel, ((AlignFrame) alf) + .getAlignViewport().getAlignment().getHiddenColumns()); } }); } @@ -514,20 +530,21 @@ public class JalviewLite extends Applet * .appletgui.AlignFrame, java.lang.String, java.lang.String) */ @Override - public String getSelectedSequencesAsAlignmentFrom(AlignFrame alf, + public String getSelectedSequencesAsAlignmentFrom(AlignFrameI alf, String format, String suffix) { try { FileFormatI theFormat = FileFormats.getInstance().forName(format); boolean seqlimits = suffix.equalsIgnoreCase(TRUE); - if (alf.viewport.getSelectionGroup() != null) + if (((AlignFrame) alf).viewport.getSelectionGroup() != null) { // JBPNote: getSelectionAsNewSequence behaviour has changed - this // method now returns a full copy of sequence data // TODO consider using getSequenceSelection instead here String reply = new AppletFormatAdapter().formatSequences(theFormat, - new Alignment(alf.viewport.getSelectionAsNewSequence()), + new Alignment(((AlignFrame) alf).viewport + .getSelectionAsNewSequence()), seqlimits); return reply; } @@ -559,7 +576,7 @@ public class JalviewLite extends Applet * ) */ @Override - public String getAlignmentOrderFrom(AlignFrame alf) + public String getAlignmentOrderFrom(AlignFrameI alf) { return getAlignmentOrderFrom(alf, separator); } @@ -572,9 +589,10 @@ public class JalviewLite extends Applet * , java.lang.String) */ @Override - public String getAlignmentOrderFrom(AlignFrame alf, String sep) + public String getAlignmentOrderFrom(AlignFrameI alf, String sep) { - AlignmentI alorder = alf.getAlignViewport().getAlignment(); + AlignmentI alorder = ((AlignFrame) alf).getAlignViewport() + .getAlignment(); String[] order = new String[alorder.getHeight()]; for (int i = 0; i < order.length; i++) { @@ -615,15 +633,16 @@ public class JalviewLite extends Applet * java.lang.String, java.lang.String, java.lang.String) */ @Override - public String orderAlignmentBy(AlignFrame alf, String order, + public String orderAlignmentBy(AlignFrameI alf, String order, String undoName, String sep) { - String[] ids = separatorListToArray(order, sep); + String[] ids = JalviewAppLoader.separatorListToArray(order, sep); SequenceI[] sqs = null; if (ids != null && ids.length > 0) { jalview.analysis.SequenceIdMatcher matcher = new jalview.analysis.SequenceIdMatcher( - alf.viewport.getAlignment().getSequencesArray()); + ((AlignFrame) alf).viewport.getAlignment() + .getSequencesArray()); int s = 0; sqs = new SequenceI[ids.length]; for (int i = 0; i < ids.length; i++) @@ -663,7 +682,7 @@ public class JalviewLite extends Applet final String _undoName = undoName; // TODO: deal with synchronization here: cannot raise any events until after // this has returned. - return alf.sortBy(aorder, _undoName) ? TRUE : ""; + return ((AlignFrame) alf).sortBy(aorder, _undoName) ? TRUE : ""; } /* @@ -685,7 +704,7 @@ public class JalviewLite extends Applet * java.lang.String) */ @Override - public String getAlignmentFrom(AlignFrame alf, String format) + public String getAlignmentFrom(AlignFrameI alf, String format) { return getAlignmentFrom(alf, format, TRUE); } @@ -710,7 +729,7 @@ public class JalviewLite extends Applet * java.lang.String, java.lang.String) */ @Override - public String getAlignmentFrom(AlignFrame alf, String format, + public String getAlignmentFrom(AlignFrameI alf, String format, String suffix) { try @@ -719,7 +738,7 @@ public class JalviewLite extends Applet FileFormatI theFormat = FileFormats.getInstance().forName(format); String reply = new AppletFormatAdapter().formatSequences(theFormat, - alf.viewport.getAlignment(), seqlimits); + ((AlignFrame) alf).viewport.getAlignment(), seqlimits); return reply; } catch (IllegalArgumentException ex) { @@ -748,17 +767,19 @@ public class JalviewLite extends Applet * , java.lang.String) */ @Override - public void loadAnnotationFrom(AlignFrame alf, String annotation) + public void loadAnnotationFrom(AlignFrameI alf, String annotation) { - if (new AnnotationFile().annotateAlignmentView(alf.getAlignViewport(), + if (new AnnotationFile().annotateAlignmentView( + ((AlignFrame) alf).getAlignViewport(), annotation, DataSourceType.PASTE)) { - alf.alignPanel.fontChanged(); - alf.alignPanel.setScrollValues(0, 0); + ((AlignFrame) alf).alignPanel.fontChanged(); + ((AlignFrame) alf).alignPanel.setScrollValues(0, 0); } else { - alf.parseFeaturesFile(annotation, DataSourceType.PASTE); + ((AlignFrame) alf).parseFeaturesFile(annotation, + DataSourceType.PASTE); } } @@ -781,10 +802,11 @@ public class JalviewLite extends Applet * , java.lang.String) */ @Override - public boolean loadFeaturesFrom(AlignFrame alf, String features, + public boolean loadFeaturesFrom(AlignFrameI alf, String features, boolean autoenabledisplay) { - return alf.parseFeaturesFile(features, DataSourceType.PASTE, + return ((AlignFrame) alf).parseFeaturesFile(features, + DataSourceType.PASTE, autoenabledisplay); } @@ -807,9 +829,9 @@ public class JalviewLite extends Applet * java.lang.String) */ @Override - public String getFeaturesFrom(AlignFrame alf, String format) + public String getFeaturesFrom(AlignFrameI alf, String format) { - return alf.outputFeatures(false, format); + return ((AlignFrame) alf).outputFeatures(false, format); } /* @@ -831,9 +853,9 @@ public class JalviewLite extends Applet * ) */ @Override - public String getAnnotationFrom(AlignFrame alf) + public String getAnnotationFrom(AlignFrameI alf) { - return alf.outputAnnotations(false); + return ((AlignFrame) alf).outputAnnotations(false); } /* @@ -864,9 +886,9 @@ public class JalviewLite extends Applet * @see jalview.bin.JalviewLiteJsApi#newViewFrom(jalview.appletgui.AlignFrame) */ @Override - public AlignFrame newViewFrom(AlignFrame alf) + public AlignFrame newViewFrom(AlignFrameI alf) { - return alf.newView(null); + return ((AlignFrame) alf).newView(null); } /* @@ -876,9 +898,9 @@ public class JalviewLite extends Applet * java.lang.String) */ @Override - public AlignFrame newViewFrom(AlignFrame alf, String name) + public AlignFrame newViewFrom(AlignFrameI alf, String name) { - return alf.newView(name); + return ((AlignFrame) alf).newView(name); } /* @@ -930,7 +952,7 @@ public class JalviewLite extends Applet * , java.lang.String) */ @Override - public void setMouseoverListener(AlignFrame af, String listener) + public void setMouseoverListener(AlignFrameI af, String listener) { if (listener != null) { @@ -943,7 +965,7 @@ public class JalviewLite extends Applet } } jalview.javascript.MouseOverListener mol = new jalview.javascript.MouseOverListener( - this, af, listener); + this, (AlignFrame) af, listener, debug); javascriptListeners.addElement(mol); StructureSelectionManager.getStructureSelectionManager(this) .addStructureViewerListener(mol); @@ -952,7 +974,8 @@ public class JalviewLite extends Applet System.err.println("Added a mouseover listener for " + ((af == null) ? "All frames" : "Just views for " - + af.getAlignViewport().getSequenceSetId())); + + ((AlignFrame) af).getAlignViewport() + .getSequenceSetId())); System.err.println("There are now " + javascriptListeners.size() + " listeners in total."); } @@ -977,7 +1000,7 @@ public class JalviewLite extends Applet * , java.lang.String) */ @Override - public void setSelectionListener(AlignFrame af, String listener) + public void setSelectionListener(AlignFrameI af, String listener) { if (listener != null) { @@ -990,7 +1013,7 @@ public class JalviewLite extends Applet } } jalview.javascript.JsSelectionSender mol = new jalview.javascript.JsSelectionSender( - this, af, listener); + this, (AlignFrame) af, listener, debug); javascriptListeners.addElement(mol); StructureSelectionManager.getStructureSelectionManager(this) .addSelectionListener(mol); @@ -999,7 +1022,8 @@ public class JalviewLite extends Applet System.err.println("Added a selection listener for " + ((af == null) ? "All frames" : "Just views for " - + af.getAlignViewport().getSequenceSetId())); + + ((AlignFrame) af).getAlignViewport() + .getSequenceSetId())); System.err.println("There are now " + javascriptListeners.size() + " listeners in total."); } @@ -1030,7 +1054,7 @@ public class JalviewLite extends Applet } } MouseOverStructureListener mol = new MouseOverStructureListener(this, - listener, separatorListToArray(modelSet)); + listener, separatorListToArray(modelSet), debug); javascriptListeners.addElement(mol); StructureSelectionManager.getStructureSelectionManager(this) .addStructureViewerListener(mol); @@ -1051,7 +1075,7 @@ public class JalviewLite extends Applet * .AlignFrame, java.lang.String) */ @Override - public void removeJavascriptListener(AlignFrame af, String listener) + public void removeJavascriptListener(AlignFrameI af, String listener) { if (listener != null) { @@ -1146,11 +1170,10 @@ public class JalviewLite extends Applet } if (jsFunctionExec != null) { - jsFunctionExec.stopQueue(); - jsFunctionExec.jvlite = null; + jsFunctionExec.tidyUp(); + jsFunctionExec = null; } initialAlignFrame = null; - jsFunctionExec = null; javascriptListeners = null; StructureSelectionManager.release(this); } @@ -1176,7 +1199,7 @@ public class JalviewLite extends Applet try { StructureSelectionManager.getStructureSelectionManager(me) - .mouseOverStructure(Integer.valueOf(pdbResNum).intValue(), + .mouseOverStructure(new Integer(pdbResNum).intValue(), chain, pdbfile); if (debug) { @@ -1202,7 +1225,7 @@ public class JalviewLite extends Applet * java.lang.String, java.lang.String) */ @Override - public void scrollViewToIn(final AlignFrame alf, final String topRow, + public void scrollViewToIn(final AlignFrameI alf, final String topRow, final String leftHandColumn) { java.awt.EventQueue.invokeLater(new Runnable() @@ -1212,8 +1235,8 @@ public class JalviewLite extends Applet { try { - alf.scrollTo(Integer.valueOf(topRow).intValue(), - Integer.valueOf(leftHandColumn).intValue()); + ((AlignFrame) alf).scrollTo(new Integer(topRow).intValue(), + new Integer(leftHandColumn).intValue()); } catch (Exception ex) { @@ -1234,7 +1257,7 @@ public class JalviewLite extends Applet * .AlignFrame, java.lang.String) */ @Override - public void scrollViewToRowIn(final AlignFrame alf, final String topRow) + public void scrollViewToRowIn(final AlignFrameI alf, final String topRow) { java.awt.EventQueue.invokeLater(new Runnable() @@ -1244,7 +1267,7 @@ public class JalviewLite extends Applet { try { - alf.scrollToRow(Integer.valueOf(topRow).intValue()); + ((AlignFrame) alf).scrollToRow(new Integer(topRow).intValue()); } catch (Exception ex) { @@ -1265,7 +1288,7 @@ public class JalviewLite extends Applet * .AlignFrame, java.lang.String) */ @Override - public void scrollViewToColumnIn(final AlignFrame alf, + public void scrollViewToColumnIn(final AlignFrameI alf, final String leftHandColumn) { java.awt.EventQueue.invokeLater(new Runnable() @@ -1276,7 +1299,8 @@ public class JalviewLite extends Applet { try { - alf.scrollToColumn(Integer.valueOf(leftHandColumn).intValue()); + ((AlignFrame) alf) + .scrollToColumn(new Integer(leftHandColumn).intValue()); } catch (Exception ex) { @@ -1322,9 +1346,9 @@ public class JalviewLite extends Applet boolean embedded = false; - private boolean checkForJmol = true; + boolean checkForJmol = true; - private boolean checkedForJmol = false; // ensure we don't check for jmol + boolean checkedForJmol = false; // ensure we don't check for jmol // every time the app is re-inited @@ -1338,6 +1362,10 @@ public class JalviewLite extends Applet */ public boolean useXtrnalSviewer = false; + public JalviewAppLoader appLoader; + + public AlignFrame loaderFrame; + public static boolean debug = false; static String builddate = null, version = null, installation = null; @@ -1470,6 +1498,9 @@ public class JalviewLite extends Applet .getString("error.invalid_separator_parameter")); } } + + // Background color + int r = 255; int g = 255; int b = 255; @@ -1489,68 +1520,33 @@ public class JalviewLite extends Applet b = 255; } } + setBackground(new Color(r, g, b)); + param = getParameter("label"); if (param != null) { launcher.setLabel(param); } - setBackground(new Color(r, g, b)); - file = getParameter("file"); if (file == null) { - // Maybe the sequences are added as parameters - StringBuffer data = new StringBuffer("PASTE"); - int i = 1; - while ((file = getParameter("sequence" + i)) != null) - { - data.append(file.toString() + "\n"); - i++; - } - if (data.length() > 5) - { - file = data.toString(); - } + file = appLoader.getPastedSequence(this); } if (getDefaultParameter("enableSplitFrame", true)) { file2 = getParameter("file2"); } - embedded = TRUE.equalsIgnoreCase(getParameter("embedded")); + embedded = (TRUE.equalsIgnoreCase(getParameter("embedded")) + || file != null + && FALSE.equalsIgnoreCase(getParameter("showbutton"))); if (embedded) { - LoadingThread loader = new LoadingThread(file, file2, this); - loader.start(); - } - else if (file != null) - { - /* - * Start the applet immediately or show a button to start it - */ - if (FALSE.equalsIgnoreCase(getParameter("showbutton"))) - { - LoadingThread loader = new LoadingThread(file, file2, this); - loader.start(); - } - else - { - add(launcher); - launcher.addActionListener(new java.awt.event.ActionListener() - { - @Override - public void actionPerformed(ActionEvent e) - { - LoadingThread loader = new LoadingThread(file, file2, - JalviewLite.this); - loader.start(); - } - }); - } + startLoading(); } - else + else if (file == null) { // jalview initialisation with no alignment. loadAlignment() method can // still be called to open new alignments. @@ -1558,6 +1554,24 @@ public class JalviewLite extends Applet fileFound = false; callInitCallback(); } + else + { + add(launcher); + launcher.addActionListener(new java.awt.event.ActionListener() + { + @Override + public void actionPerformed(ActionEvent e) + { + startLoading(); + } + }); + } + } + + protected void startLoading() + { + LoadingThread loader = new LoadingThread(file, file2, this); + loader.start(); } private void initLiveConnect() @@ -1597,7 +1611,7 @@ public class JalviewLite extends Applet } } - private void callInitCallback() + void callInitCallback() { String initjscallback = getParameter("oninit"); if (initjscallback == null) @@ -1623,7 +1637,7 @@ public class JalviewLite extends Applet try { // do onInit with the JS executor thread - new JSFunctionExec(this).executeJavascriptFunction(true, + new JSFunctionExec(this, debug).executeJavascriptFunction(true, initjscallback, null, "Calling oninit callback '" + initjscallback + "'."); } catch (Exception e) @@ -1836,7 +1850,7 @@ public class JalviewLite extends Applet JalviewLite applet; - private void dbgMsg(String msg) + public void dbgMsg(String msg) { if (JalviewLite.debug) { @@ -1853,67 +1867,10 @@ public class JalviewLite extends Applet */ public String resolveFileProtocol(String path) { - /* - * is it paste data? - */ - if (path.startsWith("PASTE")) - { - protocol = DataSourceType.PASTE; - return path.substring(5); - } - /* - * is it a URL? - */ - if (path.indexOf("://") != -1) - { - protocol = DataSourceType.URL; - return path; - } - - /* - * try relative to document root - */ - URL documentBase = getDocumentBase(); - String withDocBase = resolveUrlForLocalOrAbsolute(path, documentBase); - if (HttpUtils.isValidUrl(withDocBase)) - { - if (debug) - { - System.err.println("Prepended document base '" + documentBase - + "' to make: '" + withDocBase + "'"); - } - protocol = DataSourceType.URL; - return withDocBase; - } - - /* - * try relative to codebase (if different to document base) - */ - URL codeBase = getCodeBase(); - String withCodeBase = applet.resolveUrlForLocalOrAbsolute(path, - codeBase); - if (!withCodeBase.equals(withDocBase) - && HttpUtils.isValidUrl(withCodeBase)) - { - protocol = DataSourceType.URL; - if (debug) - { - System.err.println("Prepended codebase '" + codeBase - + "' to make: '" + withCodeBase + "'"); - } - return withCodeBase; - } - - /* - * try locating by classloader; try this last so files in the directory - * are resolved using document base - */ - if (inArchive(path)) - { - protocol = DataSourceType.CLASSLOADER; - } - return path; + String[] ret = new String[] { path }; + protocol = JalviewAppLoader.resolveFileProtocol(applet, ret); + return ret[0]; } public LoadingThread(String file, String file2, JalviewLite _applet) @@ -1958,25 +1915,16 @@ public class JalviewLite extends Applet if (newAlignFrame != null) { addToDisplay(newAlignFrame, newAlignFrame2); - loadTree(newAlignFrame); - - loadScoreFile(newAlignFrame); - - loadFeatures(newAlignFrame); - - loadAnnotations(newAlignFrame); - - loadJnetFile(newAlignFrame); - - loadPdbFiles(newAlignFrame); + applet.loaderFrame = newAlignFrame; + appLoader.load(applet); } else { fileFound = false; applet.remove(launcher); applet.repaint(); + callInitCallback(); } - callInitCallback(); } /** @@ -2089,392 +2037,6 @@ public class JalviewLite extends Applet return null; } - /** - * Load PDBFiles if any specified by parameter(s). Returns true if loaded, - * else false. - * - * @param alignFrame - * @return - */ - protected boolean loadPdbFiles(AlignFrame alignFrame) - { - boolean result = false; - /* - * Undocumented for 2.6 - - * related to JAL-434 - */ - - applet.setAlignPdbStructures( - getDefaultParameter("alignpdbfiles", false)); - /* - * - * - * - * - * - */ - - int pdbFileCount = 0; - // Accumulate pdbs here if they are heading for the same view (if - // alignPdbStructures is true) - Vector pdbs = new Vector(); - // create a lazy matcher if we're asked to - jalview.analysis.SequenceIdMatcher matcher = (applet - .getDefaultParameter("relaxedidmatch", false)) - ? new jalview.analysis.SequenceIdMatcher( - alignFrame.getAlignViewport().getAlignment() - .getSequencesArray()) - : null; - - String param; - do - { - if (pdbFileCount > 0) - { - param = applet.getParameter("PDBFILE" + pdbFileCount); - } - else - { - param = applet.getParameter("PDBFILE"); - } - - if (param != null) - { - PDBEntry pdb = new PDBEntry(); - - String seqstring; - SequenceI[] seqs = null; - String[] chains = null; - - StringTokenizer st = new StringTokenizer(param, " "); - - if (st.countTokens() < 2) - { - String sequence = applet.getParameter("PDBSEQ"); - if (sequence != null) - { - seqs = new SequenceI[] { matcher == null - ? (Sequence) alignFrame.getAlignViewport() - .getAlignment().findName(sequence) - : matcher.findIdMatch(sequence) }; - } - - } - else - { - param = st.nextToken(); - List tmp = new ArrayList<>(); - List tmp2 = new ArrayList<>(); - - while (st.hasMoreTokens()) - { - seqstring = st.nextToken(); - StringTokenizer st2 = new StringTokenizer(seqstring, "="); - if (st2.countTokens() > 1) - { - // This is the chain - tmp2.add(st2.nextToken()); - seqstring = st2.nextToken(); - } - tmp.add(matcher == null - ? (Sequence) alignFrame.getAlignViewport() - .getAlignment().findName(seqstring) - : matcher.findIdMatch(seqstring)); - } - - seqs = tmp.toArray(new SequenceI[tmp.size()]); - if (tmp2.size() == tmp.size()) - { - chains = tmp2.toArray(new String[tmp2.size()]); - } - } - param = resolveFileProtocol(param); - // TODO check JAL-357 for files in a jar (CLASSLOADER) - pdb.setFile(param); - - if (seqs != null) - { - for (int i = 0; i < seqs.length; i++) - { - if (seqs[i] != null) - { - ((Sequence) seqs[i]).addPDBId(pdb); - StructureSelectionManager - .getStructureSelectionManager(applet) - .registerPDBEntry(pdb); - } - else - { - if (JalviewLite.debug) - { - // this may not really be a problem but we give a warning - // anyway - System.err.println( - "Warning: Possible input parsing error: Null sequence for attachment of PDB (sequence " - + i + ")"); - } - } - } - - if (!alignPdbStructures) - { - alignFrame.newStructureView(applet, pdb, seqs, chains, - protocol); - } - else - { - pdbs.addElement(new Object[] { pdb, seqs, chains, protocol }); - } - } - } - - pdbFileCount++; - } while (param != null || pdbFileCount < 10); - if (pdbs.size() > 0) - { - SequenceI[][] seqs = new SequenceI[pdbs.size()][]; - PDBEntry[] pdb = new PDBEntry[pdbs.size()]; - String[][] chains = new String[pdbs.size()][]; - String[] protocols = new String[pdbs.size()]; - for (int pdbsi = 0, pdbsiSize = pdbs - .size(); pdbsi < pdbsiSize; pdbsi++) - { - Object[] o = (Object[]) pdbs.elementAt(pdbsi); - pdb[pdbsi] = (PDBEntry) o[0]; - seqs[pdbsi] = (SequenceI[]) o[1]; - chains[pdbsi] = (String[]) o[2]; - protocols[pdbsi] = (String) o[3]; - } - alignFrame.alignedStructureView(applet, pdb, seqs, chains, - protocols); - result = true; - } - return result; - } - - /** - * Load in a Jnetfile if specified by parameter. Returns true if loaded, - * else false. - * - * @param alignFrame - * @return - */ - protected boolean loadJnetFile(AlignFrame alignFrame) - { - boolean result = false; - String param = applet.getParameter("jnetfile"); - if (param == null) - { - // jnet became jpred around 2016 - param = applet.getParameter("jpredfile"); - } - if (param != null) - { - try - { - param = resolveFileProtocol(param); - JPredFile predictions = new JPredFile(param, protocol); - JnetAnnotationMaker.add_annotation(predictions, - alignFrame.viewport.getAlignment(), 0, false); - // false == do not add sequence profile from concise output - - alignFrame.viewport.getAlignment().setupJPredAlignment(); - - alignFrame.alignPanel.fontChanged(); - alignFrame.alignPanel.setScrollValues(0, 0); - result = true; - } catch (Exception ex) - { - ex.printStackTrace(); - } - } - return result; - } - - /** - * Load annotations if specified by parameter. Returns true if loaded, else - * false. - * - * @param alignFrame - * @return - */ - protected boolean loadAnnotations(AlignFrame alignFrame) - { - boolean result = false; - String param = applet.getParameter("annotations"); - if (param != null) - { - param = resolveFileProtocol(param); - - if (new AnnotationFile().annotateAlignmentView(alignFrame.viewport, - param, protocol)) - { - alignFrame.alignPanel.fontChanged(); - alignFrame.alignPanel.setScrollValues(0, 0); - result = true; - } - else - { - System.err.println( - "Annotations were not added from annotation file '" - + param + "'"); - } - } - return result; - } - - /** - * Load features file and view settings as specified by parameters. Returns - * true if features were loaded, else false. - * - * @param alignFrame - * @return - */ - protected boolean loadFeatures(AlignFrame alignFrame) - { - boolean result = false; - // /////////////////////////// - // modify display of features - // we do this before any features have been loaded, ensuring any hidden - // groups are hidden when features first displayed - // - // hide specific groups - // - String param = applet.getParameter("hidefeaturegroups"); - if (param != null) - { - alignFrame.setFeatureGroupState(separatorListToArray(param), false); - // applet.setFeatureGroupStateOn(newAlignFrame, param, false); - } - // show specific groups - param = applet.getParameter("showfeaturegroups"); - if (param != null) - { - alignFrame.setFeatureGroupState(separatorListToArray(param), true); - // applet.setFeatureGroupStateOn(newAlignFrame, param, true); - } - // and now load features - param = applet.getParameter("features"); - if (param != null) - { - param = resolveFileProtocol(param); - - result = alignFrame.parseFeaturesFile(param, protocol); - } - - param = applet.getParameter("showFeatureSettings"); - if (param != null && param.equalsIgnoreCase(TRUE)) - { - alignFrame.viewport.setShowSequenceFeatures(true); - new FeatureSettings(alignFrame.alignPanel); - } - return result; - } - - /** - * Load a score file if specified by parameter. Returns true if file was - * loaded, else false. - * - * @param alignFrame - */ - protected boolean loadScoreFile(AlignFrame alignFrame) - { - boolean result = false; - String sScoreFile = applet.getParameter("scoreFile"); - if (sScoreFile != null && !"".equals(sScoreFile)) - { - try - { - if (debug) - { - System.err.println( - "Attempting to load T-COFFEE score file from the scoreFile parameter"); - } - result = alignFrame.loadScoreFile(sScoreFile); - if (!result) - { - System.err.println( - "Failed to parse T-COFFEE parameter as a valid score file ('" - + sScoreFile + "')"); - } - } catch (Exception e) - { - System.err.printf("Cannot read score file: '%s'. Cause: %s \n", - sScoreFile, e.getMessage()); - } - } - return result; - } - - /** - * Load a tree for the alignment if specified by parameter. Returns true if - * a tree was loaded, else false. - * - * @param alignFrame - * @return - */ - protected boolean loadTree(AlignFrame alignFrame) - { - boolean result = false; - String treeFile = applet.getParameter("tree"); - if (treeFile == null) - { - treeFile = applet.getParameter("treeFile"); - } - - if (treeFile != null) - { - try - { - treeFile = resolveFileProtocol(treeFile); - NewickFile fin = new NewickFile(treeFile, protocol); - fin.parse(); - - if (fin.getTree() != null) - { - alignFrame.loadTree(fin, treeFile); - result = true; - dbgMsg("Successfully imported tree."); - } - else - { - dbgMsg("Tree parameter did not resolve to a valid tree."); - } - } catch (Exception ex) - { - ex.printStackTrace(); - } - } - return result; - } - - /** - * Discovers whether the given file is in the Applet Archive - * - * @param f - * String - * @return boolean - */ - boolean inArchive(String f) - { - // This might throw a security exception in certain browsers - // Netscape Communicator for instance. - try - { - boolean rtn = (getClass().getResourceAsStream("/" + f) != null); - if (debug) - { - System.err.println("Resource '" + f + "' was " - + (rtn ? "" : "not ") + "located by classloader."); - } - return rtn; - } catch (Exception ex) - { - System.out.println("Exception checking resources: " + f + " " + ex); - return false; - } - } } /** @@ -2507,7 +2069,7 @@ public class JalviewLite extends Applet /** * set to enable the URL based javascript execution mechanism */ - public boolean jsfallbackEnabled = false; + private boolean jsfallbackEnabled = false; /** * parse the string into a list @@ -2515,66 +2077,10 @@ public class JalviewLite extends Applet * @param list * @return elements separated by separator */ + @Override public String[] separatorListToArray(String list) { - return separatorListToArray(list, separator); - } - - /** - * parse the string into a list - * - * @param list - * @param separator - * @return elements separated by separator - */ - public static String[] separatorListToArray(String list, String separator) - { - // TODO use StringUtils version (slightly different...) - int seplen = separator.length(); - if (list == null || list.equals("") || list.equals(separator)) - { - return null; - } - java.util.Vector jv = new Vector(); - int cp = 0, pos; - while ((pos = list.indexOf(separator, cp)) > cp) - { - jv.addElement(list.substring(cp, pos)); - cp = pos + seplen; - } - if (cp < list.length()) - { - String c = list.substring(cp); - if (!c.equals(separator)) - { - jv.addElement(c); - } - } - if (jv.size() > 0) - { - String[] v = new String[jv.size()]; - for (int i = 0; i < v.length; i++) - { - v[i] = (String) jv.elementAt(i); - } - jv.removeAllElements(); - if (debug) - { - System.err.println("Array from '" + separator - + "' separated List:\n" + v.length); - for (int i = 0; i < v.length; i++) - { - System.err.println("item " + i + " '" + v[i] + "'"); - } - } - return v; - } - if (debug) - { - System.err.println( - "Empty Array from '" + separator + "' separated List"); - } - return null; + return JalviewAppLoader.separatorListToArray(list, separator); } /** @@ -2583,49 +2089,10 @@ public class JalviewLite extends Applet * @param list * @return concatenated string */ + @Override public String arrayToSeparatorList(String[] list) { - return arrayToSeparatorList(list, separator); - } - - /** - * concatenate the list with separator - * - * @param list - * @param separator - * @return concatenated string - */ - public static String arrayToSeparatorList(String[] list, String separator) - { - // TODO use StringUtils version - StringBuffer v = new StringBuffer(); - if (list != null && list.length > 0) - { - for (int i = 0, iSize = list.length; i < iSize; i++) - { - if (list[i] != null) - { - if (i > 0) - { - v.append(separator); - } - v.append(list[i]); - } - } - if (debug) - { - System.err - .println("Returning '" + separator + "' separated List:\n"); - System.err.println(v); - } - return v.toString(); - } - if (debug) - { - System.err.println( - "Returning empty '" + separator + "' separated List\n"); - } - return "" + separator; + return JalviewAppLoader.arrayToSeparatorList(list, separator); } /* @@ -2649,9 +2116,10 @@ public class JalviewLite extends Applet * ) */ @Override - public String getFeatureGroupsOn(AlignFrame alf) + public String getFeatureGroupsOn(AlignFrameI alf) { - String lst = arrayToSeparatorList(alf.getFeatureGroups()); + String lst = arrayToSeparatorList( + ((AlignFrame) alf).getFeatureGroups()); return lst; } @@ -2675,9 +2143,10 @@ public class JalviewLite extends Applet * .AlignFrame, boolean) */ @Override - public String getFeatureGroupsOfStateOn(AlignFrame alf, boolean visible) + public String getFeatureGroupsOfStateOn(AlignFrameI alf, boolean visible) { - return arrayToSeparatorList(alf.getFeatureGroupsOfState(visible)); + return arrayToSeparatorList( + ((AlignFrame) alf).getFeatureGroupsOfState(visible)); } /* @@ -2687,7 +2156,7 @@ public class JalviewLite extends Applet * AlignFrame, java.lang.String, boolean) */ @Override - public void setFeatureGroupStateOn(final AlignFrame alf, + public void setFeatureGroupStateOn(final AlignFrameI alf, final String groups, boolean state) { final boolean st = state;// !(state==null || state.equals("") || @@ -2697,7 +2166,8 @@ public class JalviewLite extends Applet @Override public void run() { - alf.setFeatureGroupState(separatorListToArray(groups), st); + ((AlignFrame) alf) + .setFeatureGroupState(separatorListToArray(groups), st); } }); } @@ -2755,6 +2225,7 @@ public class JalviewLite extends Applet * the value to return otherwise * @return true or false */ + @Override public boolean getDefaultParameter(String name, boolean def) { String stn; @@ -2776,13 +2247,15 @@ public class JalviewLite extends Applet * java.lang.String, java.lang.String, java.lang.String) */ @Override - public boolean addPdbFile(AlignFrame alFrame, String sequenceId, + public boolean addPdbFile(AlignFrameI alFrame, String sequenceId, String pdbEntryString, String pdbFile) { - return alFrame.addPdbFile(sequenceId, pdbEntryString, pdbFile); + return ((AlignFrame) alFrame).addPdbFile(sequenceId, pdbEntryString, + pdbFile); } - protected void setAlignPdbStructures(boolean alignPdbStructures) + @Override + public void setAlignPdbStructures(boolean alignPdbStructures) { this.alignPdbStructures = alignPdbStructures; } @@ -2798,86 +2271,36 @@ public class JalviewLite extends Applet // callInitCallback(); } - private Hashtable jshashes = new Hashtable<>(); + private Hashtable jshashes = new Hashtable<>(); private Hashtable> jsmessages = new Hashtable<>(); - public void setJsMessageSet(String messageclass, String viewId, - String[] colcommands) - { - Hashtable msgset = jsmessages.get(messageclass); - if (msgset == null) - { - msgset = new Hashtable<>(); - jsmessages.put(messageclass, msgset); - } - msgset.put(viewId, colcommands); - long[] l = new long[colcommands.length]; - for (int i = 0; i < colcommands.length; i++) - { - l[i] = colcommands[i].hashCode(); - } - jshashes.put(messageclass + "|" + viewId, l); - } - /* - * (non-Javadoc) - * - * @see jalview.bin.JalviewLiteJsApi#getJsMessage(java.lang.String, - * java.lang.String) - */ @Override - public String getJsMessage(String messageclass, String viewId) + public Hashtable getJSHashes() { - Hashtable msgset = jsmessages.get(messageclass); - if (msgset != null) - { - String[] msgs = msgset.get(viewId); - if (msgs != null) - { - for (int i = 0; i < msgs.length; i++) - { - if (msgs[i] != null) - { - String m = msgs[i]; - msgs[i] = null; - return m; - } - } - } - } - return ""; + return jshashes; } - public boolean isJsMessageSetChanged(String string, String string2, - String[] colcommands) + @Override + public Hashtable> getJSMessages() { - long[] l = jshashes.get(string + "|" + string2); - if (l == null && colcommands != null) - { - return true; - } - for (int i = 0; i < colcommands.length; i++) - { - if (l[i] != colcommands[i].hashCode()) - { - return true; - } - } - return false; + return jsmessages; } - private Vector jsExecQueue = new Vector(); + private Vector jsExecQueue = new Vector<>(); - public Vector getJsExecQueue() + @Override + public Vector getJsExecQueue(JSFunctionExec exec) { + jsFunctionExec = exec; return jsExecQueue; } - public void setExecutor(JSFunctionExec jsFunctionExec2) - { - jsFunctionExec = jsFunctionExec2; - } + // public void setExecutor(JSFunctionExec jsFunctionExec2) + // { + // jsFunctionExec = jsFunctionExec2; + // } /** * return the given colour value parameter or the given default if parameter @@ -2914,66 +2337,6 @@ public class JalviewLite extends Applet } /** - * form a complete URL given a path to a resource and a reference location on - * the same server - * - * @param targetPath - * - an absolute path on the same server as localref or a document - * located relative to localref - * @param localref - * - a URL on the same server as url - * @return a complete URL for the resource located by url - */ - private String resolveUrlForLocalOrAbsolute(String targetPath, - URL localref) - { - String resolvedPath = ""; - if (targetPath.startsWith("/")) - { - String codebase = localref.toString(); - String localfile = localref.getFile(); - resolvedPath = codebase.substring(0, - codebase.length() - localfile.length()) + targetPath; - return resolvedPath; - } - - /* - * get URL path and strip off any trailing file e.g. - * www.jalview.org/examples/index.html#applets?a=b is trimmed to - * www.jalview.org/examples/ - */ - String urlPath = localref.toString(); - String directoryPath = urlPath; - int lastSeparator = directoryPath.lastIndexOf("/"); - if (lastSeparator > 0) - { - directoryPath = directoryPath.substring(0, lastSeparator + 1); - } - - if (targetPath.startsWith("/")) - { - /* - * construct absolute URL to a file on the server - this is not allowed? - */ - // String localfile = localref.getFile(); - // resolvedPath = urlPath.substring(0, - // urlPath.length() - localfile.length()) - // + targetPath; - resolvedPath = directoryPath + targetPath.substring(1); - } - else - { - resolvedPath = directoryPath + targetPath; - } - if (debug) - { - System.err.println( - "resolveUrlForLocalOrAbsolute returning " + resolvedPath); - } - return resolvedPath; - } - - /** * open a URL in the browser - resolving it according to relative refs and * coping with javascript: protocol if necessary. * @@ -2990,7 +2353,7 @@ public class JalviewLite extends Applet // form valid URL // Should really use docbase, not codebase. URL prepend; - url = resolveUrlForLocalOrAbsolute(url, + url = JalviewAppLoader.resolveUrlForLocalOrAbsolute(url, prepend = getDefaultParameter("resolvetocodebase", false) ? getCodeBase() : getDocumentBase()); @@ -3023,21 +2386,209 @@ public class JalviewLite extends Applet } } - /** - * bind structures in a viewer to any matching sequences in an alignFrame (use - * sequenceIds to limit scope of search to specific sequences) - * - * @param alFrame - * @param viewer - * @param sequenceIds - * @return TODO: consider making an exception structure for indicating when - * binding fails public SequenceStructureBinding - * addStructureViewInstance( AlignFrame alFrame, Object viewer, String - * sequenceIds) { - * - * if (sequenceIds != null && sequenceIds.length() > 0) { return - * alFrame.addStructureViewInstance(viewer, - * separatorListToArray(sequenceIds)); } else { return - * alFrame.addStructureViewInstance(viewer, null); } // return null; } - */ + @Override + public AlignViewportI getViewport() + { + return loaderFrame.getAlignViewport(); + } + + @Override + public void newStructureView(PDBEntry pdb, SequenceI[] seqs, + String[] chains, DataSourceType protocol) + { + loaderFrame.newStructureView(this, pdb, seqs, chains, + protocol); + } + + @Override + public void alignedStructureView(PDBEntry[] pdb, SequenceI[][] seqs, + String[][] chains, String[] protocols) + { + loaderFrame.alignedStructureView(this, pdb, seqs, chains, protocols); + } + + @Override + public void updateForAnnotations() + { + loaderFrame.alignPanel.fontChanged(); + loaderFrame.alignPanel.setScrollValues(0, 0); + } + + @Override + public void setFeatureGroupState(String[] groups, boolean state) + { + loaderFrame.setFeatureGroupState(groups, state); + } + + @Override + public boolean parseFeaturesFile(String param, DataSourceType protocol) + { + return loaderFrame.parseFeaturesFile(param, protocol); + } + + @Override + public void newFeatureSettings() + { + getViewport().setShowSequenceFeatures(true); + new FeatureSettings(loaderFrame.alignPanel); + } + + @Override + public boolean loadScoreFile(String sScoreFile) throws IOException + { + return loaderFrame.loadScoreFile(sScoreFile); + } + + @Override + public void loadTree(NewickFile tree, String treeFile) throws IOException + { + loaderFrame.loadTree(tree, treeFile); + } + + @Override + public boolean isJsfallbackEnabled() + { + return jsfallbackEnabled; + } + + @Override + public JSObject getJSObject() + { + return JSObject.getWindow(this); + } + + @Override + public void updateColoursFromMouseOver(Object source, + MouseOverStructureListener listener) + { + } + + @Override + public Object[] getSelectionForListener(SequenceGroup seqsel, ColumnSelection colsel, + HiddenColumns hidden, SelectionSource source, Object alignFrame) + { + // System.err.println("Testing selection event relay to + // jsfunction:"+_listener); + String setid = ""; + AlignFrame src = (AlignFrame) alignFrame; + if (source != null) + { + if (source instanceof jalview.appletgui.AlignViewport + && ((jalview.appletgui.AlignViewport) source).applet.currentAlignFrame.viewport == source) + { + // should be valid if it just generated an event! + src = ((jalview.appletgui.AlignViewport) source).applet.currentAlignFrame; + + } + } + String[] seqs = new String[] {}; + String[] cols = new String[] {}; + int strt = 0, end = (src == null) ? -1 + : src.alignPanel.av.getAlignment().getWidth(); + if (seqsel != null && seqsel.getSize() > 0) + { + seqs = new String[seqsel.getSize()]; + for (int i = 0; i < seqs.length; i++) + { + seqs[i] = seqsel.getSequenceAt(i).getName(); + } + if (strt < seqsel.getStartRes()) + { + strt = seqsel.getStartRes(); + } + if (end == -1 || end > seqsel.getEndRes()) + { + end = seqsel.getEndRes(); + } + } + if (colsel != null && !colsel.isEmpty()) + { + if (end == -1) + { + end = colsel.getMax() + 1; + } + cols = new String[colsel.getSelected().size()]; + for (int i = 0; i < cols.length; i++) + { + cols[i] = "" + (1 + colsel.getSelected().get(i).intValue()); + } + } + else + { + if (seqsel != null && seqsel.getSize() > 0) + { + // send a valid range, otherwise we send the empty selection + cols = new String[2]; + cols[0] = "" + (1 + strt) + "-" + (1 + end); + } + } + return new Object[] + { src, setid, arrayToSeparatorList(seqs), arrayToSeparatorList(cols) }; + } + + @Override + public String getJsMessage(String messageclass, String viewId) + { + return JSFunctionExec.getJsMessage(messageclass, viewId, this); + } + + @Override + public Object getFrameForSource(VamsasSource source) + { + if (source != null) + { + if (source instanceof jalview.appletgui.AlignViewport + && ((jalview.appletgui.AlignViewport) source).applet.currentAlignFrame.viewport == source) + { + // should be valid if it just generated an event! + return ((jalview.appletgui.AlignViewport) source).applet.currentAlignFrame; + + } + // TODO: ensure that if '_af' is specified along with a handler + // function, then only events from that alignFrame are sent to that + // function + } + return null; + } + + @Override + public FeatureRenderer getNewFeatureRenderer(AlignViewportI vp) + { + return new jalview.appletgui.FeatureRenderer((AlignmentViewport) vp); + } + + @Override + public String getSelectedSequencesAsAlignment(String format, + boolean suffix) + { + // TODO Auto-generated method stub + return null; + } + + @Override + public String getSelectedSequencesAsAlignmentFrom(AlignFrameI alf, + String format, boolean suffix) + { + // TODO Auto-generated method stub + return null; + } + + // /** + // * bind structures in a viewer to any matching sequences in an alignFrame + // (use + // * sequenceIds to limit scope of search to specific sequences) + // * + // * @param alFrame + // * @param viewer + // * @param sequenceIds + // * @return TODO: consider making an exception structure for indicating when + // * binding fails public SequenceStructureBinding + // * addStructureViewInstance( AlignFrame alFrame, Object viewer, String + // * sequenceIds) { + // * + // * if (sequenceIds != null && sequenceIds.length() > 0) { return + // * alFrame.addStructureViewInstance(viewer, + // * separatorListToArray(sequenceIds)); } else { return + // * alFrame.addStructureViewInstance(viewer, null); } // return null; } + // */ } diff --git a/src/jalview/bin/JalviewTaskbar.java b/src/jalview/bin/JalviewTaskbar.java deleted file mode 100644 index 7dd0382..0000000 --- a/src/jalview/bin/JalviewTaskbar.java +++ /dev/null @@ -1,39 +0,0 @@ -package jalview.bin; - -import java.awt.Image; -import java.awt.Taskbar; - -public class JalviewTaskbar -{ - public JalviewTaskbar() - { - } - - protected static void setTaskbar(Jalview jalview) - { - - if (Taskbar.isTaskbarSupported()) - { - Taskbar tb = Taskbar.getTaskbar(); - if (tb.isSupported(Taskbar.Feature.ICON_IMAGE)) - { - try - { - java.net.URL url = jalview.getClass() - .getResource("/images/JalviewLogo_Huge.png"); - if (url != null) - { - Image image = java.awt.Toolkit.getDefaultToolkit() - .createImage(url); - tb.setIconImage(image); - } - } catch (Exception e) - { - System.out.println("Unable to setIconImage()"); - } - } - } - - } - -} diff --git a/src/jalview/bin/Launcher.java b/src/jalview/bin/Launcher.java deleted file mode 100644 index 412f119..0000000 --- a/src/jalview/bin/Launcher.java +++ /dev/null @@ -1,178 +0,0 @@ -package jalview.bin; - -import java.io.File; -import java.io.IOException; -import java.lang.management.ManagementFactory; -import java.util.ArrayList; - -public class Launcher -{ - - private final static String startClass = "jalview.bin.Jalview"; - - private final static int maxHeapSizePerCent = 90; - - private final static String maxHeapSizePerCentProperty = "jvmmempc"; - - private final static String dockIconPath = "JalviewLogo_Huge.png"; - - public static void main(String[] args) - { - final String javaBin = System.getProperty("java.home") + File.separator - + "bin" + File.separator + "java"; - - ArrayList command = new ArrayList<>(); - command.add(javaBin); - - String memSetting = null; - - boolean isAMac = System.getProperty("os.name").indexOf("Mac") > -1; - - for (String jvmArg : ManagementFactory.getRuntimeMXBean() - .getInputArguments()) - { - command.add(jvmArg); - } - command.add("-cp"); - command.add(ManagementFactory.getRuntimeMXBean().getClassPath()); - ArrayList arguments = new ArrayList<>(); - for (String arg : args) - { - arguments.add(arg); - } - - // add memory setting if not specified - boolean memSet = false; - boolean dockIcon = false; - boolean dockName = false; - ARG: for (int i = 0; i < command.size(); i++) - { - String arg = command.get(i); - if (arg.startsWith("-Xmx")) - { - memSetting = arg; - memSet = true; - } - else if (arg.startsWith("-Xdock:icon")) - { - dockIcon = true; - } - else if (arg.startsWith("-Xdock:name")) - { - dockName = true; - } - } - - if (!memSet) - { - long maxMemLong = -1; - int percent = maxHeapSizePerCent; - String jvmmempc = System.getProperty(maxHeapSizePerCentProperty); - try - { - if (jvmmempc != null) - { - int trypercent = Integer.parseInt(jvmmempc); - if (0 < trypercent && trypercent <= 100) - { - percent = trypercent; - } - else - { - System.out.println("Property '" + maxHeapSizePerCentProperty - + "' should be in range 1..100"); - } - } - } catch (Exception e) - { - System.out.println("Error parsing " + maxHeapSizePerCentProperty - + " '" + jvmmempc + "'"); - } - - try - { - maxMemLong = MemorySetting.memPercent(percent); - } catch (Exception e) - { - e.printStackTrace(); - } catch (Throwable t) - { - t.printStackTrace(); - } - - if (maxMemLong > 0) - { - memSetting = "-Xmx" + Long.toString(maxMemLong); - command.add(memSetting); - } - } - - if (isAMac) - { - if (!dockIcon) - { - command.add("-Xdock:icon=" + dockIconPath); - } - if (!dockName) - { - // -Xdock:name=... doesn't actually work :( - // Leaving it in in case it gets fixed - command.add("-Xdock:name=" + "Jalview"); - } - } - - command.add(startClass); - command.addAll(arguments); - - final ProcessBuilder builder = new ProcessBuilder(command); - - // System.out.println("COMMAND: " + String.join(" ", builder.command())); - System.out.println("Running " + startClass + " with " - + (memSetting == null ? "no memSetting" : memSetting)); - - try - { - builder.inheritIO(); - Process process = builder.start(); - process.waitFor(); - } catch (IOException e) - { - if (e.getMessage().toLowerCase().contains("memory")) - { - System.out.println("Caught a memory exception: " + e.getMessage()); - // Probably the "Cannot allocate memory" error, try without the memory setting - ArrayList commandNoMem = new ArrayList<>(); - for (int i = 0; i < command.size(); i++) - { - if (!command.get(i).startsWith("-Xmx")) - { - commandNoMem.add(command.get(i)); - } - } - final ProcessBuilder builderNoMem = new ProcessBuilder( - commandNoMem); - System.out.println("NO MEM COMMAND: " - + String.join(" ", builderNoMem.command())); - try - { - builderNoMem.inheritIO(); - Process processNoMem = builderNoMem.start(); - processNoMem.waitFor(); - } catch (Exception ex) - { - ex.printStackTrace(); - } - } - else - { - e.printStackTrace(); - } - } catch (Exception e) - { - e.printStackTrace(); - } - // System.exit(0); - - } - -} diff --git a/src/jalview/bin/MemorySetting.java b/src/jalview/bin/MemorySetting.java deleted file mode 100644 index b3bae2d..0000000 --- a/src/jalview/bin/MemorySetting.java +++ /dev/null @@ -1,51 +0,0 @@ -package jalview.bin; - -import java.lang.management.ManagementFactory; -import java.lang.management.OperatingSystemMXBean; - -public class MemorySetting -{ - public static final long leaveFreeMinMemory = 536870912; // 0.5 GB - - public static final long applicationMinMemory = 536870912; // 0.5 GB - - protected static long getPhysicalMemory() - { - final OperatingSystemMXBean o = ManagementFactory - .getOperatingSystemMXBean(); - - try - { - if (o instanceof com.sun.management.OperatingSystemMXBean) - { - final com.sun.management.OperatingSystemMXBean osb = (com.sun.management.OperatingSystemMXBean) o; - return osb.getTotalPhysicalMemorySize(); - } - } catch (NoClassDefFoundError e) - { - // com.sun.management.OperatingSystemMXBean doesn't exist in this JVM - System.out.println("No com.sun.management.OperatingSystemMXBean"); - } - - // We didn't get a com.sun.management.OperatingSystemMXBean. - return -1; - } - - public static long memPercent(int percent) - { - long memPercent = -1; - - long physicalMem = getPhysicalMemory(); - if (physicalMem > applicationMinMemory) - { - // try and set at least applicationMinMemory and thereafter ensure - // leaveFreeMinMemory is left for the OS - memPercent = Math.max(applicationMinMemory, - physicalMem - Math.max(physicalMem * (100 - percent) / 100, - leaveFreeMinMemory)); - } - - return memPercent; - } - -} diff --git a/src/jalview/commands/ChangeCaseCommand.java b/src/jalview/commands/ChangeCaseCommand.java index 7f7142f1..f0ea2f6 100644 --- a/src/jalview/commands/ChangeCaseCommand.java +++ b/src/jalview/commands/ChangeCaseCommand.java @@ -29,17 +29,17 @@ public class ChangeCaseCommand implements CommandI { String description; - public static int TO_LOWER = 0; + public final static int TO_LOWER = 0; - public static int TO_UPPER = 1; + public final static int TO_UPPER = 1; - public static int TOGGLE_CASE = 2; + public final static int TOGGLE_CASE = 2; - int caseChange = -1; + private int caseChange; - SequenceI[] seqs; + private SequenceI[] seqs; - List regions; + private List regions; public ChangeCaseCommand(String description, SequenceI[] seqs, List regions, int caseChange) @@ -51,21 +51,25 @@ public class ChangeCaseCommand implements CommandI doCommand(null); } + @Override public String getDescription() { return description; } + @Override public int getSize() { return 1; } + @Override public void doCommand(AlignmentI[] views) { changeCase(true); } + @Override public void undoCommand(AlignmentI[] views) { changeCase(false); diff --git a/src/jalview/controller/AlignViewController.java b/src/jalview/controller/AlignViewController.java index 9b8a9e3..33699cc 100644 --- a/src/jalview/controller/AlignViewController.java +++ b/src/jalview/controller/AlignViewController.java @@ -166,10 +166,9 @@ public class AlignViewController implements AlignViewControllerI // JBPNote this routine could also mark rows, not just columns. // need a decent query structure to allow all types of feature searches BitSet bs = new BitSet(); - boolean searchSelection = viewport.getSelectionGroup() != null - && !extendCurrent; - SequenceCollectionI sqcol = searchSelection ? viewport - .getSelectionGroup() : viewport.getAlignment(); + SequenceCollectionI sqcol = (viewport.getSelectionGroup() == null + || extendCurrent) ? viewport.getAlignment() + : viewport.getSelectionGroup(); int nseq = findColumnsWithFeature(featureType, sqcol, bs); @@ -205,10 +204,9 @@ public class AlignViewController implements AlignViewControllerI } else { - String key = searchSelection ? "label.no_feature_found_selection" - : "label.no_feature_of_type_found"; - avcg.setStatus(MessageManager.formatMessage(key, - new String[] { featureType })); + avcg.setStatus(MessageManager + .formatMessage("label.no_feature_of_type_found", new String[] + { featureType })); if (!extendCurrent) { cs.clear(); diff --git a/src/jalview/datamodel/Alignment.java b/src/jalview/datamodel/Alignment.java index c4098e2..98510e3 100755 --- a/src/jalview/datamodel/Alignment.java +++ b/src/jalview/datamodel/Alignment.java @@ -47,7 +47,7 @@ import java.util.Vector; * @author JimP * */ -public class Alignment implements AlignmentI, AutoCloseable +public class Alignment implements AlignmentI { private Alignment dataset; @@ -125,8 +125,7 @@ public class Alignment implements AlignmentI, AutoCloseable /** * Make a new alignment from an array of SeqCigars * - * @param seqs - * SeqCigar[] + * @param alseqs */ public Alignment(SeqCigar[] alseqs) { @@ -303,20 +302,15 @@ public class Alignment implements AlignmentI, AutoCloseable } @Override - public void close() + public void finalize() throws Throwable { if (getDataset() != null) { - try - { - getDataset().removeAlignmentRef(); - } catch (Throwable e) - { - e.printStackTrace(); - } + getDataset().removeAlignmentRef(); } nullReferences(); + super.finalize(); } /** @@ -404,6 +398,10 @@ public class Alignment implements AlignmentI, AutoCloseable return null; } + private static final SequenceGroup[] noGroups = new SequenceGroup[0]; + + private ArrayList temp = new ArrayList<>(); + /* * (non-Javadoc) * @@ -413,11 +411,15 @@ public class Alignment implements AlignmentI, AutoCloseable @Override public SequenceGroup[] findAllGroups(SequenceI s) { - ArrayList temp = new ArrayList<>(); synchronized (groups) { int gSize = groups.size(); + if (gSize == 0) + { + return noGroups; + } + temp.clear(); for (int i = 0; i < gSize; i++) { SequenceGroup sg = groups.get(i); @@ -2032,4 +2034,17 @@ public class Alignment implements AlignmentI, AutoCloseable } } + @Override + public void resetColors() + { + for (int i = getHeight(); --i >= 0;) + { + sequences.get(i).resetColors(); + } + // if (dataset != null) + // { + // dataset.resetColors(); + // } + } + } diff --git a/src/jalview/datamodel/AlignmentAnnotation.java b/src/jalview/datamodel/AlignmentAnnotation.java index 2ee4503..ee9389c 100755 --- a/src/jalview/datamodel/AlignmentAnnotation.java +++ b/src/jalview/datamodel/AlignmentAnnotation.java @@ -991,7 +991,7 @@ public class AlignmentAnnotation seqPos = i + startRes; } - sequenceMapping.put(Integer.valueOf(seqPos), annotations[i]); + sequenceMapping.put(new Integer(seqPos), annotations[i]); } } @@ -1030,7 +1030,7 @@ public class AlignmentAnnotation { for (a = sequenceRef.getStart(); a <= sequenceRef.getEnd(); a++) { - index = Integer.valueOf(a); + index = new Integer(a); Annotation annot = sequenceMapping.get(index); if (annot != null) { diff --git a/src/jalview/datamodel/AlignmentI.java b/src/jalview/datamodel/AlignmentI.java index 93a2456..ebf4da3 100755 --- a/src/jalview/datamodel/AlignmentI.java +++ b/src/jalview/datamodel/AlignmentI.java @@ -624,4 +624,10 @@ public interface AlignmentI extends AnnotatedCollectionI public HiddenColumns propagateInsertions(SequenceI profileseq, AlignmentView input); + /** + * Remove all color already assigned to sequences, causing them to be be + * recalculated. + */ + void resetColors(); + } diff --git a/src/jalview/datamodel/AllColsCollection.java b/src/jalview/datamodel/AllColsCollection.java index e216c46..f3077fa 100644 --- a/src/jalview/datamodel/AllColsCollection.java +++ b/src/jalview/datamodel/AllColsCollection.java @@ -22,6 +22,7 @@ package jalview.datamodel; import jalview.api.AlignmentColsCollectionI; +import java.util.BitSet; import java.util.Iterator; public class AllColsCollection implements AlignmentColsCollectionI @@ -56,4 +57,26 @@ public class AllColsCollection implements AlignmentColsCollectionI { return hidden.hasHiddenColumns(); } + + private BitSet bsVisible; + + @Override + public BitSet getHiddenBitSet() + { + return hidden.getBitset(); + } + + /** + * return ALL columns, not just the truly visible ones + */ + @Override + public BitSet getOverviewBitSet() + { + if (bsVisible == null) + { + bsVisible = new BitSet(end + 1); + bsVisible.set(0, end + 1); + } + return bsVisible; + } } diff --git a/src/jalview/datamodel/BinarySequence.java b/src/jalview/datamodel/BinarySequence.java index cea9de7..c33abb3 100755 --- a/src/jalview/datamodel/BinarySequence.java +++ b/src/jalview/datamodel/BinarySequence.java @@ -169,7 +169,7 @@ public class BinarySequence extends Sequence for (int i = 0; i < binary.length; i++) { - out += (Integer.valueOf(binary[i])).toString(); + out += (new Integer(binary[i])).toString(); if (i < (binary.length - 1)) { diff --git a/src/jalview/datamodel/ColumnSelection.java b/src/jalview/datamodel/ColumnSelection.java index 6f14e21..3ccaab8 100644 --- a/src/jalview/datamodel/ColumnSelection.java +++ b/src/jalview/datamodel/ColumnSelection.java @@ -106,7 +106,7 @@ public class ColumnSelection void remove(int col) { - Integer colInt = Integer.valueOf(col); + Integer colInt = new Integer(col); if (selected.get(col)) { @@ -204,7 +204,7 @@ public class ColumnSelection // clear shifted bits and update List of selected columns selected.clear(temp); mask.set(temp - change); - order.set(i, Integer.valueOf(temp - change)); + order.set(i, new Integer(temp - change)); } } // lastly update the bitfield all at once @@ -309,7 +309,7 @@ public class ColumnSelection Integer colInt; for (int i = start; i < end; i++) { - colInt = Integer.valueOf(i); + colInt = new Integer(i); if (selection.contains(colInt)) { selection.remove(colInt); diff --git a/src/jalview/datamodel/DBRefEntry.java b/src/jalview/datamodel/DBRefEntry.java index 54e8379..0004abe 100755 --- a/src/jalview/datamodel/DBRefEntry.java +++ b/src/jalview/datamodel/DBRefEntry.java @@ -21,7 +21,6 @@ package jalview.datamodel; import jalview.api.DBRefEntryI; -import jalview.io.vamsas.Dbref; import jalview.util.DBRefUtils; import jalview.util.MapList; @@ -42,7 +41,7 @@ public class DBRefEntry implements DBRefEntryI private String version = ""; - private String ucversion; + private String ucversion = ""; private String accessionId = ""; diff --git a/src/jalview/datamodel/DBRefSource.java b/src/jalview/datamodel/DBRefSource.java index 2f94884..71d6972 100755 --- a/src/jalview/datamodel/DBRefSource.java +++ b/src/jalview/datamodel/DBRefSource.java @@ -42,7 +42,8 @@ public class DBRefSource public static final String UNIPROT = "UNIPROT"; - public static final String UP_NAME = "UNIPROT_NAME".toUpperCase(); + + public static final String UP_NAME = "UNIPROT_NAME"; /** * Uniprot Knowledgebase/TrEMBL as served from EMBL protein products. */ @@ -56,10 +57,18 @@ public class DBRefSource public static final String EMBLCDSProduct = "EMBLCDSProtein".toUpperCase(); public static final String PDB = "PDB"; - public static final String PFAM = "PFAM"; + + public static final String PFAM = "PFAM"; + public static final String RFAM = "RFAM"; public static final String GENEDB = "GeneDB".toUpperCase(); + public static final String PFAM_FULL = "PFAM (Full)"; + + public static final String PFAM_SEED = "PFAM (Seed)"; + + public static final String RFAM_SEED = "RFAM (Seed)"; + public static final String PDB_CANONICAL_NAME = PDB; @@ -135,7 +144,7 @@ public class DBRefSource // CODINGDBS, DNACODINGDBS, PROTEINDBS }; // public static final int PRIMARY_SOURCES_MASK = CODING_MASK | DNA_CODING_MASK | PROTEIN_MASK; - + public static boolean isPrimarySource(String source) { return ((PRIMARY_SOURCES_MASK & getSourceKey(source)) != 0); diff --git a/src/jalview/datamodel/HiddenColumns.java b/src/jalview/datamodel/HiddenColumns.java index 2d43f02..458bde7 100644 --- a/src/jalview/datamodel/HiddenColumns.java +++ b/src/jalview/datamodel/HiddenColumns.java @@ -86,6 +86,20 @@ public class HiddenColumns */ private List hiddenColumns = new ArrayList<>(); + private BitSet hiddenBitSet; + + public BitSet getBitset() + { + if (hiddenBitSet == null) + { + hiddenBitSet = new BitSet(); + for (int[] range : hiddenColumns) + { + hiddenBitSet.set(range[0], range[1] + 1); + } + } + return hiddenBitSet; + } /** * Constructor */ @@ -213,6 +227,7 @@ public class HiddenColumns prevHiddenCount); } finally { + hiddenBitSet = null; LOCK.writeLock().unlock(); } } @@ -264,6 +279,7 @@ public class HiddenColumns insertRangeAtOverlap(i, start, end, region); added = true; } + hiddenBitSet = null; return added; } @@ -310,6 +326,7 @@ public class HiddenColumns } numColumns += region[1] - oldend; hiddenColumns.subList(i + 1, endi + 1).clear(); + hiddenBitSet = null; } /** @@ -330,6 +347,7 @@ public class HiddenColumns } finally { + hiddenBitSet = null; LOCK.writeLock().unlock(); } } @@ -356,6 +374,7 @@ public class HiddenColumns } finally { + hiddenBitSet = null; LOCK.writeLock().unlock(); } } @@ -399,6 +418,7 @@ public class HiddenColumns } } finally { + hiddenBitSet = null; LOCK.writeLock().unlock(); } } @@ -620,6 +640,7 @@ public class HiddenColumns } finally { + hiddenBitSet = null; LOCK.readLock().unlock(); } } @@ -798,7 +819,7 @@ public class HiddenColumns for (int firstSet = tohide .nextSetBit(start), lastSet = start; firstSet >= start && lastSet <= end; firstSet = tohide - .nextSetBit(lastSet)) + .nextSetBit(lastSet)) { lastSet = tohide.nextClearBit(firstSet); if (lastSet <= end) @@ -813,6 +834,7 @@ public class HiddenColumns cursor = new HiddenColumnsCursor(hiddenColumns); } finally { + hiddenBitSet = null; LOCK.writeLock().unlock(); } } @@ -894,6 +916,7 @@ public class HiddenColumns } } finally { + hiddenBitSet = null; LOCK.writeLock().unlock(); } } @@ -909,16 +932,12 @@ public class HiddenColumns { LOCK.writeLock().lock(); - BitSet hiddenBitSet = new BitSet(); - for (int[] range : hiddenColumns) - { - hiddenBitSet.set(range[0], range[1] + 1); - } - hiddenBitSet.andNot(updates); + getBitset().andNot(updates); hiddenColumns.clear(); hideColumns(hiddenBitSet); } finally { + hiddenBitSet = null; LOCK.writeLock().unlock(); } } diff --git a/src/jalview/datamodel/PDBEntry.java b/src/jalview/datamodel/PDBEntry.java index c1dc77c..80e2de8 100755 --- a/src/jalview/datamodel/PDBEntry.java +++ b/src/jalview/datamodel/PDBEntry.java @@ -131,18 +131,11 @@ public class PDBEntry * CaseInsensitiveString, so we are in effect doing a * case-insensitive comparison of chain codes */ - boolean idMatches = id == o.id - || (id != null && id.equalsIgnoreCase(o.id)); - boolean fileMatches = file == o.file - || (file != null && file.equals(o.file)); - boolean typeMatches = type == o.type - || (type != null && type.equals(o.type)); - if (idMatches && fileMatches && typeMatches) - { - return properties == o.properties - || (properties != null && properties.equals(o.properties)); - } - return false; + return (id == o.id || (id != null && id.equalsIgnoreCase(o.id))) + && (file == o.file || (file != null && file.equals(o.file))) + && (type == o.type || (type != null && type.equals(o.type))) + && (properties == o.properties || (properties != null + && properties.equals(o.properties))); } /** @@ -169,7 +162,7 @@ public class PDBEntry { this.id = pdbId; this.type = entryType == null ? null : entryType.toString(); - this.file = filePath; + this.file = (filePath == null ? null : filePath.replace('\\', '/')); setChainCode(chain); } @@ -220,7 +213,7 @@ public class PDBEntry public void setFile(String f) { - this.file = f; + this.file = f.replace('\\', '/'); } public String getFile() @@ -257,7 +250,7 @@ public class PDBEntry { if (this.properties == null) { - this.properties = new Hashtable(); + this.properties = new Hashtable<>(); } properties.put(key, value); } diff --git a/src/jalview/datamodel/ResidueCount.java b/src/jalview/datamodel/ResidueCount.java index 74eb887..bb604d0 100644 --- a/src/jalview/datamodel/ResidueCount.java +++ b/src/jalview/datamodel/ResidueCount.java @@ -76,9 +76,10 @@ public class ResidueCount * fast lookup tables holding the index into our count * arrays of each symbol; index 0 is reserved for gap counting */ - private static int[] NUC_INDEX = new int[26]; + private final static int[] NUC_INDEX = new int[26]; + + private final static int[] AA_INDEX = new int[26]; - private static int[] AA_INDEX = new int[26]; static { for (int i = 0; i < NUCS.length(); i++) diff --git a/src/jalview/datamodel/SecondaryStructureAnnotation.java b/src/jalview/datamodel/SecondaryStructureAnnotation.java index 476eb19..e395648 100644 --- a/src/jalview/datamodel/SecondaryStructureAnnotation.java +++ b/src/jalview/datamodel/SecondaryStructureAnnotation.java @@ -25,7 +25,9 @@ import fr.orsay.lri.varna.models.rna.RNA; public class SecondaryStructureAnnotation extends AlignmentAnnotation { - private static RNA _rna = null; + // was static, but that cannot work here + + private RNA _rna = null; public SecondaryStructureAnnotation(RNA rna) { @@ -44,7 +46,7 @@ public class SecondaryStructureAnnotation extends AlignmentAnnotation Annotation[] ann = new Annotation[rna.getSize()]; for (int i = 0; i < ann.length; i++) { - ann[i] = new Annotation(_rna.getStructDBN(true), "", ' ', 0f); + ann[i] = new Annotation(rna.getStructDBN(true), "", ' ', 0f); ; } return ann; diff --git a/src/jalview/datamodel/Sequence.java b/src/jalview/datamodel/Sequence.java index ca2b6d4..bad33d1 100755 --- a/src/jalview/datamodel/Sequence.java +++ b/src/jalview/datamodel/Sequence.java @@ -392,6 +392,10 @@ public class Sequence extends ASequence implements SequenceI return sequenceFeatureStore.add(sf); } + /** + * @param sf + * A known feature of this featureStore + */ @Override public void deleteFeature(SequenceFeature sf) { @@ -1967,15 +1971,15 @@ public class Sequence extends ASequence implements SequenceI List result = getFeatures().findFeatures(startPos, endPos, types); - if (datasetSequence != null) - { - result = datasetSequence.getFeatures().findFeatures(startPos, endPos, - types); - } - else - { - result = sequenceFeatureStore.findFeatures(startPos, endPos, types); - } + // if (datasetSequence != null) + // { + // result = datasetSequence.getFeatures().findFeatures(startPos, endPos, + // types); + // } + // else + // { + // result = sequenceFeatureStore.findFeatures(startPos, endPos, types); + // } /* * if end column is gapped, endPos may be to the right, @@ -2026,6 +2030,7 @@ public class Sequence extends ASequence implements SequenceI @Override public void sequenceChanged() { + argb = null; changeCount++; } @@ -2127,4 +2132,54 @@ public class Sequence extends ASequence implements SequenceI // otherwise, sequence was completely hidden return 0; } + + private int[] argb; + + @Override + public int getColor(int i) + { + return argb == null ? 0 : argb[i]; + } + + @Override + public int setColor(int i, int rgb) + { + if (argb == null) + { + argb = new int[this.sequence.length]; + } + return (argb[i] = rgb); + } + + @Override + public void resetColors() + { + argb = null; + } + + /** + * @author Bob Hanson 2019.07.30 + * + * allows passing the result ArrayList as a parameter to avoid + * unnecessary construction + * @return result (JavaScript) or new ArrayList (Java -- see FeatureRender) + * + */ + @Override + public List findFeatures(int column, String type, + List result) + { + return getFeatures().findFeatures(findPosition(column - 1), type, + result); + } + + /** + * allows early intervention for renderer if this returns false + */ + @Override + public boolean hasFeatures(String type) + { + return getFeatures().hasFeatures(type); + } + } diff --git a/src/jalview/datamodel/SequenceFeature.java b/src/jalview/datamodel/SequenceFeature.java index 7052f34..6f51420 100755 --- a/src/jalview/datamodel/SequenceFeature.java +++ b/src/jalview/datamodel/SequenceFeature.java @@ -35,6 +35,8 @@ import java.util.SortedMap; import java.util.TreeMap; import java.util.Vector; +import intervalstore.api.IntervalI; + /** * A class that models a single contiguous feature on a sequence. If flag * 'contactFeature' is true, the start and end positions are interpreted instead @@ -217,10 +219,20 @@ public class SequenceFeature implements FeatureLocationI @Override public boolean equals(Object o) { - return equals(o, false); + return (o != null && (o instanceof SequenceFeature) + && equalsInterval((SequenceFeature) o)); } /** + * Having determined that this is in fact a SequenceFeature, now check it for + * equivalence. Overridden in CrossRef; used by IntervalStore (possibly). + */ + @Override + public boolean equalsInterval(IntervalI sf) + { + return equals((SequenceFeature) sf, false); + } + /** * Overloaded method allows the equality test to optionally ignore the * 'Parent' attribute of a feature. This supports avoiding adding many * superficially duplicate 'exon' or CDS features to genomic or protein @@ -230,14 +242,8 @@ public class SequenceFeature implements FeatureLocationI * @param ignoreParent * @return */ - public boolean equals(Object o, boolean ignoreParent) + public boolean equals(SequenceFeature sf, boolean ignoreParent) { - if (o == null || !(o instanceof SequenceFeature)) - { - return false; - } - - SequenceFeature sf = (SequenceFeature) o; boolean sameScore = Float.isNaN(score) ? Float.isNaN(sf.score) : score == sf.score; if (begin != sf.begin || end != sf.end || !sameScore) @@ -736,6 +742,8 @@ public class SequenceFeature implements FeatureLocationI { source = theSource; } + + } class SFSortByEnd implements Comparator diff --git a/src/jalview/datamodel/SequenceI.java b/src/jalview/datamodel/SequenceI.java index 933f332..0b26564 100755 --- a/src/jalview/datamodel/SequenceI.java +++ b/src/jalview/datamodel/SequenceI.java @@ -584,6 +584,48 @@ public interface SequenceI extends ASequenceI */ public int firstResidueOutsideIterator(Iterator it); + /** + * @author Bob Hanson 2019.07.30 + * + * get a 4-byte color, with caching + * + */ + public int getColor(int i); + + /** + * @author Bob Hanson 2019.07.30 + * + * set a 4-byte color, with caching + * + */ + public int setColor(int i, int argb); + + /** + * @author Bob Hanson 2019.07.30 + * + * allows resetting the color cache + * + */ + public void resetColors(); + + /** + * allows passing the result ArrayList as a parameter to avoid unnecessary + * construction + * + * @author Bob Hanson 2019.07.30 + * + * + */ + List findFeatures(int column, String type, + List result); + + /** + * allows early intervention for renderer if false + * + * @author Bob Hanson 2019.07.30 + * + */ + public boolean hasFeatures(String type); } diff --git a/src/jalview/datamodel/VisibleColsCollection.java b/src/jalview/datamodel/VisibleColsCollection.java index 4ca51b5..cd812a1 100644 --- a/src/jalview/datamodel/VisibleColsCollection.java +++ b/src/jalview/datamodel/VisibleColsCollection.java @@ -22,6 +22,7 @@ package jalview.datamodel; import jalview.api.AlignmentColsCollectionI; +import java.util.BitSet; import java.util.Iterator; public class VisibleColsCollection implements AlignmentColsCollectionI @@ -32,6 +33,8 @@ public class VisibleColsCollection implements AlignmentColsCollectionI HiddenColumns hidden; + private BitSet bsVisible; + public VisibleColsCollection(int s, int e, HiddenColumns h) { start = s; @@ -57,4 +60,27 @@ public class VisibleColsCollection implements AlignmentColsCollectionI return false; } + /** + * Only the visible columns. + */ + @Override + public BitSet getOverviewBitSet() + { + if (bsVisible == null) + { + bsVisible = new BitSet(end + 1); + } + bsVisible.clear(); + bsVisible.set(start, end + 1); + bsVisible.andNot(hidden.getBitset()); + + return bsVisible; + } + + @Override + public BitSet getHiddenBitSet() + { + return new BitSet(); + } + } diff --git a/src/jalview/datamodel/features/FeatureAttributes.java b/src/jalview/datamodel/features/FeatureAttributes.java index 7acebee..f51fe48 100644 --- a/src/jalview/datamodel/features/FeatureAttributes.java +++ b/src/jalview/datamodel/features/FeatureAttributes.java @@ -1,5 +1,8 @@ package jalview.datamodel.features; +import jalview.bin.ApplicationSingletonProvider; +import jalview.bin.ApplicationSingletonProvider.ApplicationSingletonI; + import java.util.ArrayList; import java.util.Collections; import java.util.Comparator; @@ -12,14 +15,23 @@ import java.util.TreeMap; /** * A singleton class to hold the set of attributes known for each feature type */ -public class FeatureAttributes +public class FeatureAttributes implements ApplicationSingletonI { public enum Datatype { Character, Number, Mixed } - private static FeatureAttributes instance = new FeatureAttributes(); + public static FeatureAttributes getInstance() + { + return (FeatureAttributes) ApplicationSingletonProvider + .getInstance(FeatureAttributes.class); + } + + private FeatureAttributes() + { + attributes = new HashMap<>(); + } /* * map, by feature type, of a map, by attribute name, of @@ -173,21 +185,6 @@ public class FeatureAttributes } /** - * Answers the singleton instance of this class - * - * @return - */ - public static FeatureAttributes getInstance() - { - return instance; - } - - private FeatureAttributes() - { - attributes = new HashMap<>(); - } - - /** * Answers the attribute names known for the given feature type, in * alphabetical order (not case sensitive), or an empty set if no attributes * are known. An attribute name is typically 'simple' e.g. "AC", but may be diff --git a/src/jalview/datamodel/features/FeatureSources.java b/src/jalview/datamodel/features/FeatureSources.java index 1be1b82..ec04bad 100644 --- a/src/jalview/datamodel/features/FeatureSources.java +++ b/src/jalview/datamodel/features/FeatureSources.java @@ -1,31 +1,22 @@ package jalview.datamodel.features; +import jalview.bin.ApplicationSingletonProvider; +import jalview.bin.ApplicationSingletonProvider.ApplicationSingletonI; + import java.util.HashMap; import java.util.Map; -/** - * A singleton to hold metadata about feature attributes, keyed by a unique - * feature source identifier - * - * @author gmcarstairs - * - */ -public class FeatureSources +public class FeatureSources implements ApplicationSingletonI { - private static FeatureSources instance = new FeatureSources(); - - private Map sources; - /** - * Answers the singleton instance of this class - * - * @return - */ public static FeatureSources getInstance() { - return instance; + return (FeatureSources) ApplicationSingletonProvider + .getInstance(FeatureSources.class); } + private Map sources; + private FeatureSources() { sources = new HashMap<>(); diff --git a/src/jalview/datamodel/features/FeatureStore.java b/src/jalview/datamodel/features/FeatureStore.java index 54c0d59..1451892 100644 --- a/src/jalview/datamodel/features/FeatureStore.java +++ b/src/jalview/datamodel/features/FeatureStore.java @@ -23,25 +23,134 @@ package jalview.datamodel.features; import jalview.datamodel.SequenceFeature; import java.util.ArrayList; +import java.util.Collection; import java.util.Collections; import java.util.HashSet; import java.util.List; import java.util.Set; -import intervalstore.api.IntervalStoreI; -import intervalstore.impl.BinarySearcher; -import intervalstore.impl.IntervalStore; - -/** - * A data store for a set of sequence features that supports efficient lookup of - * features overlapping a given range. Intended for (but not limited to) storage - * of features for one sequence and feature type. - * - * @author gmcarstairs - * - */ -public class FeatureStore +public abstract class FeatureStore implements FeatureStoreI { + + /** + * track last start for quick insertion of ordered features + */ + protected int lastStart = -1, lastContactStart = -1; + + /** + * Answers the 'length' of the feature, counting 0 for non-positional features + * and 1 for contact features + * + * @param feature + * @return + */ + protected static int getFeatureLength(SequenceFeature feature) + { + if (feature.isNonPositional()) + { + return 0; + } + if (feature.isContactFeature()) + { + return 1; + } + return 1 + feature.getEnd() - feature.getBegin(); + } + + /** + * Answers true if the list contains the feature, else false. This method is + * optimised for the condition that the list is sorted on feature start + * position ascending, and will give unreliable results if this does not hold. + * + * @param list + * @param feature + * @return + */ + @Override + public boolean listContains(List list, + SequenceFeature feature) + { + if (list == null || feature == null) + { + return false; + } + + return (getEquivalentFeatureIndex(list, feature) >= 0); + } + + /** + * Binary search for the index (>= 0) of a feature in a list. + * + * @param list + * @param feature + * @return index if found; -1 if not + */ + protected int getEquivalentFeatureIndex(List list, + SequenceFeature feature) + { + + /* + * locate the first entry in the list which does not precede the feature + */ + int begin = feature.begin; + int pos = findFirstBegin(list, begin); + int len = list.size(); + while (pos < len) + { + SequenceFeature sf = list.get(pos); + if (sf.begin > begin) + { + return -1; // no match found + } + if (sf.equals(feature)) + { + return pos; + } + pos++; + } + return -1; + } + + /** + * A helper method to return the maximum of two floats, where a non-NaN value + * is treated as 'greater than' a NaN value (unlike Math.max which does the + * opposite) + * + * @param f1 + * @param f2 + */ + protected static float max(float f1, float f2) + { + if (Float.isNaN(f1)) + { + return Float.isNaN(f2) ? f1 : f2; + } + else + { + return Float.isNaN(f2) ? f1 : Math.max(f1, f2); + } + } + + /** + * A helper method to return the minimum of two floats, where a non-NaN value + * is treated as 'less than' a NaN value (unlike Math.min which does the + * opposite) + * + * @param f1 + * @param f2 + */ + protected static float min(float f1, float f2) + { + if (Float.isNaN(f1)) + { + return Float.isNaN(f2) ? f1 : f2; + } + else + { + return Float.isNaN(f2) ? f1 : Math.min(f1, f2); + } + } + /* * Non-positional features have no (zero) start/end position. * Kept as a separate list in case this criterion changes in future. @@ -62,7 +171,7 @@ public class FeatureStore * IntervalStore holds remaining features and provides efficient * query for features overlapping any given interval */ - IntervalStoreI features; + Collection features; /* * Feature groups represented in stored positional features @@ -95,7 +204,6 @@ public class FeatureStore */ public FeatureStore() { - features = new IntervalStore<>(); positionalFeatureGroups = new HashSet<>(); nonPositionalFeatureGroups = new HashSet<>(); positionalMinScore = Float.NaN; @@ -107,39 +215,99 @@ public class FeatureStore } /** - * Adds one sequence feature to the store, and returns true, unless the - * feature is already contained in the store, in which case this method - * returns false. Containment is determined by SequenceFeature.equals() - * comparison. + * Add a contact feature to the lists that hold them ordered by start (first + * contact) and by end (second contact) position, ensuring the lists remain + * ordered, and returns true. This method allows duplicate features to be + * added, so test before calling to avoid this. * * @param feature + * @return */ - public boolean addFeature(SequenceFeature feature) + protected synchronized boolean addContactFeature(SequenceFeature feature) { - if (contains(feature)) + if (contactFeatureStarts == null) { - return false; + contactFeatureStarts = new ArrayList<>(); + contactFeatureEnds = new ArrayList<>(); } /* - * keep a record of feature groups + * insert into list sorted by start (first contact position): + * binary search the sorted list to find the insertion point */ - if (!feature.isNonPositional()) - { - positionalFeatureGroups.add(feature.getFeatureGroup()); - } + contactFeatureStarts.add( + findFirstBegin(contactFeatureStarts, feature.begin), feature); + /* + * insert into list sorted by end (second contact position): + * binary search the sorted list to find the insertion point + */ + contactFeatureEnds.add(findFirstEnd(contactFeatureEnds, feature.end), + feature); + + return true; + } + + /** + * Adds one sequence feature to the store, and returns true, unless the + * feature is already contained in the store, in which case this method + * returns false. Containment is determined by SequenceFeature.equals() + * comparison. + * + * @param feature + */ + + @Override + public boolean addFeature(SequenceFeature feature) + { + // if (contains(feature)) + // { + // return false; + // } + + // /* + // * keep a record of feature groups + // */ + // if (!feature.isNonPositional()) + // { + // positionalFeatureGroups.add(feature.getFeatureGroup()); + // } if (feature.isContactFeature()) { + if (containsContactFeature(feature)) + { + return false; + } + positionalFeatureGroups.add(feature.getFeatureGroup()); + if (feature.begin > lastContactStart) + { + lastContactStart = feature.begin; + } addContactFeature(feature); } else if (feature.isNonPositional()) { + if (containsNonPositional(feature)) + { + return false; + } + addNonPositionalFeature(feature); } else { - addNestedFeature(feature); + // allow for check with + if (checkContainsPositionalFeatureForAdd(feature) + || !addPositionalFeature(feature)) + { + return false; + } + positionalFeatureGroups.add(feature.getFeatureGroup()); + // addPositionalFeature(feature); + if (feature.begin > lastStart) + { + lastStart = feature.begin; + } } /* @@ -171,50 +339,31 @@ public class FeatureStore return true; } - /** - * Answers true if this store contains the given feature (testing by - * SequenceFeature.equals), else false - * - * @param feature - * @return - */ - public boolean contains(SequenceFeature feature) + private void addFeaturesForGroup(String group, + Collection sfs, List result) { - if (feature.isNonPositional()) + if (sfs == null) { - return nonPositionalFeatures == null ? false : nonPositionalFeatures - .contains(feature); + return; } - - if (feature.isContactFeature()) + for (SequenceFeature sf : sfs) { - return contactFeatureStarts == null ? false : listContains( - contactFeatureStarts, feature); + String featureGroup = sf.getFeatureGroup(); + if (group == null && featureGroup == null + || group != null && group.equals(featureGroup)) + { + result.add(sf); + } } - - return features == null ? false : features - .contains(feature); } /** - * Answers the 'length' of the feature, counting 0 for non-positional features - * and 1 for contact features + * Adds one feature to the IntervalStore that can manage nested features + * (creating the IntervalStore if necessary) * - * @param feature - * @return + * @return true if added -- allowing for late checking during addition */ - protected static int getFeatureLength(SequenceFeature feature) - { - if (feature.isNonPositional()) - { - return 0; - } - if (feature.isContactFeature()) - { - return 1; - } - return 1 + feature.getEnd() - feature.getBegin(); - } + abstract protected boolean addPositionalFeature(SequenceFeature feature); /** * Adds the feature to the list of non-positional features (with lazy @@ -240,302 +389,64 @@ public class FeatureStore } /** - * Adds one feature to the IntervalStore that can manage nested features - * (creating the IntervalStore if necessary) - */ - protected synchronized void addNestedFeature(SequenceFeature feature) - { - if (features == null) - { - features = new IntervalStore<>(); - } - features.add(feature); - } - - /** - * Add a contact feature to the lists that hold them ordered by start (first - * contact) and by end (second contact) position, ensuring the lists remain - * ordered, and returns true. This method allows duplicate features to be - * added, so test before calling to avoid this. - * - * @param feature - * @return - */ - protected synchronized boolean addContactFeature(SequenceFeature feature) - { - if (contactFeatureStarts == null) - { - contactFeatureStarts = new ArrayList<>(); - } - if (contactFeatureEnds == null) - { - contactFeatureEnds = new ArrayList<>(); - } - - /* - * insert into list sorted by start (first contact position): - * binary search the sorted list to find the insertion point - */ - int insertPosition = BinarySearcher.findFirst(contactFeatureStarts, - f -> f.getBegin() >= feature.getBegin()); - contactFeatureStarts.add(insertPosition, feature); - - - /* - * insert into list sorted by end (second contact position): - * binary search the sorted list to find the insertion point - */ - insertPosition = BinarySearcher.findFirst(contactFeatureEnds, - f -> f.getEnd() >= feature.getEnd()); - contactFeatureEnds.add(insertPosition, feature); - - return true; - } - - /** - * Answers true if the list contains the feature, else false. This method is - * optimised for the condition that the list is sorted on feature start - * position ascending, and will give unreliable results if this does not hold. + * Answers true if this store contains the given feature (testing by + * SequenceFeature.equals), else false * - * @param features * @param feature * @return */ - protected static boolean listContains(List features, - SequenceFeature feature) - { - if (features == null || feature == null) - { - return false; - } - - /* - * locate the first entry in the list which does not precede the feature - */ - // int pos = binarySearch(features, - // SearchCriterion.byFeature(feature, RangeComparator.BY_START_POSITION)); - int pos = BinarySearcher.findFirst(features, - val -> val.getBegin() >= feature.getBegin()); - int len = features.size(); - while (pos < len) - { - SequenceFeature sf = features.get(pos); - if (sf.getBegin() > feature.getBegin()) - { - return false; // no match found - } - if (sf.equals(feature)) - { - return true; - } - pos++; - } - return false; - } - - /** - * Returns a (possibly empty) list of features whose extent overlaps the given - * range. The returned list is not ordered. Contact features are included if - * either of the contact points lies within the range. - * - * @param start - * start position of overlap range (inclusive) - * @param end - * end position of overlap range (inclusive) - * @return - */ - public List findOverlappingFeatures(long start, long end) + @Override + public boolean contains(SequenceFeature feature) { - List result = new ArrayList<>(); - - findContactFeatures(start, end, result); - - if (features != null) + if (feature.isNonPositional()) { - result.addAll(features.findOverlaps(start, end)); - } - - return result; - } + return containsNonPositional(feature); - /** - * Adds contact features to the result list where either the second or the - * first contact position lies within the target range - * - * @param from - * @param to - * @param result - */ - protected void findContactFeatures(long from, long to, - List result) - { - if (contactFeatureStarts != null) - { - findContactStartOverlaps(from, to, result); } - if (contactFeatureEnds != null) - { - findContactEndOverlaps(from, to, result); - } - } - /** - * Adds to the result list any contact features whose end (second contact - * point), but not start (first contact point), lies in the query from-to - * range - * - * @param from - * @param to - * @param result - */ - protected void findContactEndOverlaps(long from, long to, - List result) - { - /* - * find the first contact feature (if any) - * whose end point is not before the target range - */ - int index = BinarySearcher.findFirst(contactFeatureEnds, - f -> f.getEnd() >= from); - - while (index < contactFeatureEnds.size()) + if (feature.isContactFeature()) { - SequenceFeature sf = contactFeatureEnds.get(index); - if (!sf.isContactFeature()) - { - System.err.println("Error! non-contact feature type " - + sf.getType() + " in contact features list"); - index++; - continue; - } + return containsContactFeature(feature); - int begin = sf.getBegin(); - if (begin >= from && begin <= to) - { - /* - * this feature's first contact position lies in the search range - * so we don't include it in results a second time - */ - index++; - continue; - } - - if (sf.getEnd() > to) - { - /* - * this feature (and all following) has end point after the target range - */ - break; - } - - /* - * feature has end >= from and end <= to - * i.e. contact end point lies within overlap search range - */ - result.add(sf); - index++; } - } - /** - * Adds contact features whose start position lies in the from-to range to the - * result list - * - * @param from - * @param to - * @param result - */ - protected void findContactStartOverlaps(long from, long to, - List result) - { - int index = BinarySearcher.findFirst(contactFeatureStarts, - f -> f.getBegin() >= from); - - while (index < contactFeatureStarts.size()) - { - SequenceFeature sf = contactFeatureStarts.get(index); - if (!sf.isContactFeature()) - { - System.err.println("Error! non-contact feature " + sf.toString() - + " in contact features list"); - index++; - continue; - } - if (sf.getBegin() > to) - { - /* - * this feature's start (and all following) follows the target range - */ - break; - } + return containsPositionalFeature(feature); - /* - * feature has begin >= from and begin <= to - * i.e. contact start point lies within overlap search range - */ - result.add(sf); - index++; - } } /** - * Answers a list of all positional features stored, in no guaranteed order + * A check that can be overridden if the check is being done during the add + * operation itself. * + * @param feature * @return */ - public List getPositionalFeatures() + protected boolean checkContainsPositionalFeatureForAdd( + SequenceFeature feature) { - List result = new ArrayList<>(); - - /* - * add any contact features - from the list by start position - */ - if (contactFeatureStarts != null) - { - result.addAll(contactFeatureStarts); - } - - /* - * add any nested features - */ - if (features != null) - { - result.addAll(features); - } - - return result; + return containsPositionalFeature(feature); } - /** - * Answers a list of all contact features. If there are none, returns an - * immutable empty list. - * - * @return - */ - public List getContactFeatures() + private boolean containsPositionalFeature(SequenceFeature feature) { - if (contactFeatureStarts == null) - { - return Collections.emptyList(); - } - return new ArrayList<>(contactFeatureStarts); - } - - /** - * Answers a list of all non-positional features. If there are none, returns - * an immutable empty list. - * - * @return - */ - public List getNonPositionalFeatures() + return features == null || feature.begin > lastStart ? false + : containsFeature(feature); + } + + private boolean containsContactFeature(SequenceFeature feature) { - if (nonPositionalFeatures == null) - { - return Collections.emptyList(); - } - return new ArrayList<>(nonPositionalFeatures); + return contactFeatureStarts != null && feature.begin <= lastContactStart + && listContains(contactFeatureStarts, feature); + } + + private boolean containsNonPositional(SequenceFeature feature) + { + return nonPositionalFeatures == null ? false + : nonPositionalFeatures.contains(feature); } + abstract protected boolean containsFeature(SequenceFeature feature); + /** * Deletes the given feature from the store, returning true if it was found * (and deleted), else false. This method makes no assumption that the feature @@ -544,6 +455,8 @@ public class FeatureStore * * @param sf */ + + @Override public synchronized boolean delete(SequenceFeature sf) { boolean removed = false; @@ -561,15 +474,12 @@ public class FeatureStore } } - boolean removedNonPositional = false; - /* * if not found, try non-positional features */ if (!removed && nonPositionalFeatures != null) { - removedNonPositional = nonPositionalFeatures.remove(sf); - removed = removedNonPositional; + removed = nonPositionalFeatures.remove(sf); } /* @@ -577,7 +487,7 @@ public class FeatureStore */ if (!removed && features != null) { - removed = features.remove(sf); + removed = findAndRemoveNonContactFeature(sf); } if (removed) @@ -588,100 +498,66 @@ public class FeatureStore return removed; } - /** - * Rescan all features to recompute any cached values after an entry has been - * deleted. This is expected to be an infrequent event, so performance here is - * not critical. - */ - protected synchronized void rescanAfterDelete() - { - positionalFeatureGroups.clear(); - nonPositionalFeatureGroups.clear(); - totalExtent = 0; - positionalMinScore = Float.NaN; - positionalMaxScore = Float.NaN; - nonPositionalMinScore = Float.NaN; - nonPositionalMaxScore = Float.NaN; + abstract protected boolean findAndRemoveNonContactFeature(SequenceFeature sf); - /* - * scan non-positional features for groups and scores - */ - for (SequenceFeature sf : getNonPositionalFeatures()) - { - nonPositionalFeatureGroups.add(sf.getFeatureGroup()); - float score = sf.getScore(); - nonPositionalMinScore = min(nonPositionalMinScore, score); - nonPositionalMaxScore = max(nonPositionalMaxScore, score); - } + abstract protected void findContactFeatures(long from, long to, + List result); - /* - * scan positional features for groups, scores and extents - */ - for (SequenceFeature sf : getPositionalFeatures()) - { - positionalFeatureGroups.add(sf.getFeatureGroup()); - float score = sf.getScore(); - positionalMinScore = min(positionalMinScore, score); - positionalMaxScore = max(positionalMaxScore, score); - totalExtent += getFeatureLength(sf); - } + abstract protected int findFirstBegin(List list, + long pos); + + abstract protected int findFirstEnd(List list, long pos); + + @Override + public List findOverlappingFeatures(long start, long end) + { + return findOverlappingFeatures(start, end, null); } - /** - * A helper method to return the minimum of two floats, where a non-NaN value - * is treated as 'less than' a NaN value (unlike Math.min which does the - * opposite) - * - * @param f1 - * @param f2 - */ - protected static float min(float f1, float f2) + @Override + public List getContactFeatures() { - if (Float.isNaN(f1)) - { - return Float.isNaN(f2) ? f1 : f2; - } - else - { - return Float.isNaN(f2) ? f1 : Math.min(f1, f2); - } + return getContactFeatures(new ArrayList<>()); } /** - * A helper method to return the maximum of two floats, where a non-NaN value - * is treated as 'greater than' a NaN value (unlike Math.max which does the - * opposite) + * Answers a list of all contact features. If there are none, returns an + * immutable empty list. * - * @param f1 - * @param f2 + * @return */ - protected static float max(float f1, float f2) + + @Override + public List getContactFeatures( + List result) { - if (Float.isNaN(f1)) - { - return Float.isNaN(f2) ? f1 : f2; - } - else + if (contactFeatureStarts != null) { - return Float.isNaN(f2) ? f1 : Math.max(f1, f2); + result.addAll(contactFeatureStarts); } + return result; } /** - * Answers true if this store has no features, else false + * Answers the number of positional (or non-positional) features stored. + * Contact features count as 1. * + * @param positional * @return */ - public boolean isEmpty() + + @Override + public int getFeatureCount(boolean positional) { - boolean hasFeatures = (contactFeatureStarts != null - && !contactFeatureStarts - .isEmpty()) - || (nonPositionalFeatures != null && !nonPositionalFeatures - .isEmpty()) - || (features != null && features.size() > 0); + if (!positional) + { + return nonPositionalFeatures == null ? 0 + : nonPositionalFeatures.size(); + } + + return (contactFeatureStarts == null ? 0 : contactFeatureStarts.size()) + + features.size(); - return !hasFeatures; } /** @@ -692,6 +568,8 @@ public class FeatureStore * @param positionalFeatures * @return */ + + @Override public Set getFeatureGroups(boolean positionalFeatures) { if (positionalFeatures) @@ -700,52 +578,68 @@ public class FeatureStore } else { - return nonPositionalFeatureGroups == null ? Collections - . emptySet() : Collections - .unmodifiableSet(nonPositionalFeatureGroups); + return nonPositionalFeatureGroups == null + ? Collections. emptySet() + : Collections.unmodifiableSet(nonPositionalFeatureGroups); } } + @Override + public Collection getFeatures() + { + return features; + } + /** - * Answers the number of positional (or non-positional) features stored. - * Contact features count as 1. + * Answers a list of all either positional or non-positional features whose + * feature group matches the given group (which may be null) * * @param positional + * @param group * @return */ - public int getFeatureCount(boolean positional) + + @Override + public List getFeaturesForGroup(boolean positional, + String group) { - if (!positional) + List result = new ArrayList<>(); + + /* + * if we know features don't include the target group, no need + * to inspect them for matches + */ + if (positional && !positionalFeatureGroups.contains(group) + || !positional && !nonPositionalFeatureGroups.contains(group)) { - return nonPositionalFeatures == null ? 0 : nonPositionalFeatures - .size(); + return result; } - int size = 0; - - if (contactFeatureStarts != null) + if (positional) { - // note a contact feature (start/end) counts as one - size += contactFeatureStarts.size(); + addFeaturesForGroup(group, contactFeatureStarts, result); + addFeaturesForGroup(group, features, result); } - - if (features != null) + else { - size += features.size(); + addFeaturesForGroup(group, nonPositionalFeatures, result); } - - return size; + return result; } /** - * Answers the total length of positional features (or zero if there are - * none). Contact features contribute a value of 1 to the total. + * Answers the maximum score held for positional or non-positional features. + * This may be Float.NaN if there are no features, are none has a non-NaN + * score. * + * @param positional * @return */ - public int getTotalFeatureLength() + + @Override + public float getMaximumScore(boolean positional) { - return totalExtent; + return positional ? positionalMaxScore : nonPositionalMaxScore; } /** @@ -756,59 +650,156 @@ public class FeatureStore * @param positional * @return */ + + @Override public float getMinimumScore(boolean positional) { return positional ? positionalMinScore : nonPositionalMinScore; } + @Override + public List getNonPositionalFeatures() + { + return getNonPositionalFeatures(new ArrayList<>()); + } + /** - * Answers the maximum score held for positional or non-positional features. - * This may be Float.NaN if there are no features, are none has a non-NaN - * score. + * Answers a list of all non-positional features. If there are none, returns + * an immutable empty list. * - * @param positional * @return */ - public float getMaximumScore(boolean positional) + + @Override + public List getNonPositionalFeatures( + List result) { - return positional ? positionalMaxScore : nonPositionalMaxScore; + if (nonPositionalFeatures != null) + { + result.addAll(nonPositionalFeatures); + } + return result; + } + + @Override + public List getPositionalFeatures() + { + return getPositionalFeatures(new ArrayList<>()); } /** - * Answers a list of all either positional or non-positional features whose - * feature group matches the given group (which may be null) + * Answers a list of all positional features stored, in no guaranteed order * - * @param positional - * @param group * @return */ - public List getFeaturesForGroup(boolean positional, - String group) + + @Override + public List getPositionalFeatures( + List result) { - List result = new ArrayList<>(); /* - * if we know features don't include the target group, no need - * to inspect them for matches + * add any contact features - from the list by start position */ - if (positional && !positionalFeatureGroups.contains(group) - || !positional && !nonPositionalFeatureGroups.contains(group)) + if (contactFeatureStarts != null) { - return result; + result.addAll(contactFeatureStarts); } - List sfs = positional ? getPositionalFeatures() - : getNonPositionalFeatures(); - for (SequenceFeature sf : sfs) + /* + * add any nested features + */ + if (features != null) { - String featureGroup = sf.getFeatureGroup(); - if (group == null && featureGroup == null || group != null - && group.equals(featureGroup)) + result.addAll(features); + } + + return result; + } + + /** + * Answers the total length of positional features (or zero if there are + * none). Contact features contribute a value of 1 to the total. + * + * @return + */ + + @Override + public int getTotalFeatureLength() + { + return totalExtent; + } + + /** + * Answers true if this store has no features, else false + * + * @return + */ + + @Override + public boolean isEmpty() + { + boolean hasFeatures = (contactFeatureStarts != null + && !contactFeatureStarts.isEmpty()) + || (nonPositionalFeatures != null + && !nonPositionalFeatures.isEmpty()) + || features.size() > 0; + + return !hasFeatures; + } + + /** + * Rescan all features to recompute any cached values after an entry has been + * deleted. This is expected to be an infrequent event, so performance here is + * not critical. + */ + protected synchronized void rescanAfterDelete() + { + positionalFeatureGroups.clear(); + nonPositionalFeatureGroups.clear(); + totalExtent = 0; + positionalMinScore = Float.NaN; + positionalMaxScore = Float.NaN; + nonPositionalMinScore = Float.NaN; + nonPositionalMaxScore = Float.NaN; + /* + * scan non-positional features for groups and scores + */ + if (nonPositionalFeatures != null) + { + List list = nonPositionalFeatures; + for (int i = 0, n = list.size(); i < n; i++) { - result.add(sf); + SequenceFeature sf = list.get(i); + nonPositionalFeatureGroups.add(sf.getFeatureGroup()); + float score = sf.getScore(); + nonPositionalMinScore = min(nonPositionalMinScore, score); + nonPositionalMaxScore = max(nonPositionalMaxScore, score); } } - return result; + + /* + * scan positional features for groups, scores and extents + */ + + rescanPositional(contactFeatureStarts); + rescanPositional(features); + } + + private void rescanPositional(Collection sfs) + { + if (sfs == null) + { + return; + } + for (SequenceFeature sf : sfs) + { + positionalFeatureGroups.add(sf.getFeatureGroup()); + float score = sf.getScore(); + positionalMinScore = min(positionalMinScore, score); + positionalMaxScore = max(positionalMaxScore, score); + totalExtent += getFeatureLength(sf); + } } /** @@ -820,6 +811,8 @@ public class FeatureStore * @param shiftBy * @return */ + + @Override public synchronized boolean shiftFeatures(int fromPosition, int shiftBy) { /* @@ -828,8 +821,10 @@ public class FeatureStore * (Although a simple shift of all values would preserve data integrity!) */ boolean modified = false; - for (SequenceFeature sf : getPositionalFeatures()) + List list = getPositionalFeatures(); + for (int i = 0, n = list.size(); i < n; i++) { + SequenceFeature sf = list.get(i); if (sf.getBegin() >= fromPosition) { modified = true; @@ -851,4 +846,5 @@ public class FeatureStore } return modified; } + } diff --git a/src/jalview/datamodel/features/FeatureStoreI.java b/src/jalview/datamodel/features/FeatureStoreI.java new file mode 100644 index 0000000..fb32577 --- /dev/null +++ b/src/jalview/datamodel/features/FeatureStoreI.java @@ -0,0 +1,58 @@ +package jalview.datamodel.features; + +import jalview.datamodel.SequenceFeature; + +import java.util.Collection; +import java.util.List; +import java.util.Set; + +public interface FeatureStoreI +{ + + boolean addFeature(SequenceFeature feature); + + boolean contains(SequenceFeature feature); + + boolean delete(SequenceFeature sf); + + List findOverlappingFeatures(long start, long end); + + List findOverlappingFeatures(long start, long end, + List result); + + List getContactFeatures(); + + List getContactFeatures(List result); + + int getFeatureCount(boolean positional); + + Set getFeatureGroups(boolean positionalFeatures); + + Collection getFeatures(); + + List getFeaturesForGroup(boolean positional, + String group); + + float getMaximumScore(boolean positional); + + float getMinimumScore(boolean positional); + + List getNonPositionalFeatures(); + + List getNonPositionalFeatures( + List result); + + List getPositionalFeatures(); + + List getPositionalFeatures(List result); + + int getTotalFeatureLength(); + + boolean isEmpty(); + + boolean shiftFeatures(int fromPosition, int shiftBy); + + boolean listContains(List features, + SequenceFeature feature); + +} diff --git a/src/jalview/datamodel/features/FeatureStoreImpl.java b/src/jalview/datamodel/features/FeatureStoreImpl.java new file mode 100644 index 0000000..a90755d --- /dev/null +++ b/src/jalview/datamodel/features/FeatureStoreImpl.java @@ -0,0 +1,304 @@ +/* + * Jalview - A Sequence Alignment Editor and Viewer ($$Version-Rel$$) + * Copyright (C) $$Year-Rel$$ The Jalview Authors + * + * This file is part of Jalview. + * + * Jalview is free software: you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, either version 3 + * of the License, or (at your option) any later version. + * + * Jalview is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty + * of MERCHANTABILITY or FITNESS FOR A PARTICULAR + * PURPOSE. See the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Jalview. If not, see . + * The Jalview Authors are detailed in the 'AUTHORS' file. + */ +package jalview.datamodel.features; + +import jalview.datamodel.SequenceFeature; + +import java.util.ArrayList; +import java.util.List; + +import intervalstore.api.IntervalStoreI; +import intervalstore.impl.BinarySearcher; + +/** + * A data store for a set of sequence features that supports efficient lookup of + * features overlapping a given range. Intended for (but not limited to) storage + * of features for one sequence and feature type. + * + * @author gmcarstairs + * + */ +public class FeatureStoreImpl extends FeatureStore +{ + + /** + * Default constructor uses NCList + */ + public FeatureStoreImpl() + { + this(true); + } + + public FeatureStoreImpl(boolean useNCList) + { + features = (useNCList ? new intervalstore.impl.IntervalStore<>() + : new intervalstore.nonc.IntervalStore<>(false)); + } + + /** + * Add a contact feature to the lists that hold them ordered by start (first + * contact) and by end (second contact) position, ensuring the lists remain + * ordered, and returns true. This method allows duplicate features to be + * added, so test before calling to avoid this. + * + * @param feature + * @return + */ + @Override + protected synchronized boolean addContactFeature(SequenceFeature feature) + { + if (contactFeatureStarts == null) + { + contactFeatureStarts = new ArrayList<>(); + contactFeatureEnds = new ArrayList<>(); + } + + /* + * insert into list sorted by start (first contact position): + * binary search the sorted list to find the insertion point + */ + int insertPosition = findFirstBeginStatic(contactFeatureStarts, + feature.getBegin()); + contactFeatureStarts.add(insertPosition, feature); + + /* + * insert into list sorted by end (second contact position): + * binary search the sorted list to find the insertion point + */ + insertPosition = findFirstEndStatic(contactFeatureEnds, + feature.getEnd()); + contactFeatureEnds.add(insertPosition, feature); + + return true; + } + + /** + * Adds one feature to the IntervalStore that can manage nested features + * (creating the IntervalStore if necessary) + */ + @Override + protected synchronized boolean addPositionalFeature( + SequenceFeature feature) + { + return features.add(feature); + } + + /** + * Adds contact features to the result list where either the second or the + * first contact position lies within the target range + * + * @param from + * @param to + * @param result + */ + @Override + protected void findContactFeatures(long from, long to, + List result) + { + if (contactFeatureStarts != null) + { + findContactStartOverlaps(from, to, result); + findContactEndOverlaps(from, to, result); + } + } + + @Override + protected boolean containsFeature(SequenceFeature feature) + { + return features.contains(feature); + } + + /** + * Adds to the result list any contact features whose end (second contact + * point), but not start (first contact point), lies in the query from-to + * range + * + * @param from + * @param to + * @param result + */ + + private void findContactEndOverlaps(long from, long to, + List result) + { + /* + * find the first contact feature (if any) + * whose end point is not before the target range + */ + int index = findFirstEndStatic(contactFeatureEnds, from); + + int n = contactFeatureEnds.size(); + while (index < n) + { + SequenceFeature sf = contactFeatureEnds.get(index); + if (!sf.isContactFeature()) + { + System.err.println("Error! non-contact feature type " + sf.getType() + + " in contact features list"); + index++; + continue; + } + + int begin = sf.getBegin(); + if (begin >= from && begin <= to) + { + /* + * this feature's first contact position lies in the search range + * so we don't include it in results a second time + */ + index++; + continue; + } + + if (sf.getEnd() > to) + { + /* + * this feature (and all following) has end point after the target range + */ + break; + } + + /* + * feature has end >= from and end <= to + * i.e. contact end point lies within overlap search range + */ + result.add(sf); + index++; + } + } + + /** + * Adds contact features whose start position lies in the from-to range to the + * result list + * + * @param from + * @param to + * @param result + */ + + private void findContactStartOverlaps(long from, long to, + List result) + { + int index = findFirstBegin(contactFeatureStarts, from); + + while (index < contactFeatureStarts.size()) + { + SequenceFeature sf = contactFeatureStarts.get(index); + if (!sf.isContactFeature()) + { + System.err.println("Error! non-contact feature " + sf.toString() + + " in contact features list"); + index++; + continue; + } + if (sf.getBegin() > to) + { + /* + * this feature's start (and all following) follows the target range + */ + break; + } + + /* + * feature has begin >= from and begin <= to + * i.e. contact start point lies within overlap search range + */ + result.add(sf); + index++; + } + } + + /** + * Returns a (possibly empty) list of features whose extent overlaps the given + * range. The returned list is not ordered. Contact features are included if + * either of the contact points lies within the range. + * + * @param start + * start position of overlap range (inclusive) + * @param end + * end position of overlap range (inclusive) + * @param result + * ignored + * @return + */ + + @Override + public List findOverlappingFeatures(long start, long end, + List result) + { + result = new ArrayList<>(); + findContactFeatures(start, end, result); + findOverlaps(start, end, result); + return result; + } + + private void findOverlaps(long start, long end, + List result) + { + result.addAll(((IntervalStoreI) features) + .findOverlaps(start, end)); + } + + @Override + protected int findFirstBegin(List list, long pos) + { + return findFirstBeginStatic(list, pos); + } + + /** + * Possibly a bit faster using a static method. + * + * @param list + * @param pos + * @return + */ + private static int findFirstBeginStatic(List list, + long pos) + { + return BinarySearcher.findFirst(list, f -> f.getBegin() >= pos); + } + + @Override + protected int findFirstEnd(List list, long pos) + { + return findFirstEndStatic(list, pos); + } + + /** + * Possibly a bit faster using a static method. + * + * @param list + * @param pos + * @return + */ + private static int findFirstEndStatic(List list, + long pos) + { + return BinarySearcher.findFirst(list, f -> f.getEnd() >= pos); + } + + @Override + protected boolean findAndRemoveNonContactFeature(SequenceFeature sf) + { + return features.remove(sf); + } + +} diff --git a/src/jalview/datamodel/features/FeatureStoreJS.java b/src/jalview/datamodel/features/FeatureStoreJS.java new file mode 100644 index 0000000..4f49360 --- /dev/null +++ b/src/jalview/datamodel/features/FeatureStoreJS.java @@ -0,0 +1,414 @@ +/* + * Jalview - A Sequence Alignment Editor and Viewer ($$Version-Rel$$) + * Copyright (C) $$Year-Rel$$ The Jalview Authors + * + * This file is part of Jalview. + * + * Jalview is free software: you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, either version 3 + * of the License, or (at your option) any later version. + * + * Jalview is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty + * of MERCHANTABILITY or FITNESS FOR A PARTICULAR + * PURPOSE. See the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Jalview. If not, see . + * The Jalview Authors are detailed in the 'AUTHORS' file. + */ +package jalview.datamodel.features; + +import jalview.datamodel.SequenceFeature; + +import java.util.ArrayList; +import java.util.List; + +import intervalstore.nonc.IntervalStore; + +/** + * An adaption of FeatureStore that is efficient and lightweight, accelerating + * processing speed in JavaScript. + * + * It could be used in Java as well, with significant acceleration, but all this + * is so fast anyway that it probably will not be noticed in Java to speed it up + * by a factor of two or three. So for now, at least, this implementation is + * just in JavaScript. The flag for this is in SequenceFeatures. + * + * This implementation uses the IntervalStore developed by Bob Hanson, found at + * https://github.com/BobHanson/IntervalStoreJ, forked from the one developed by + * Mungo Carstairs at https://github.com/bartongroup/IntervalStoreJ. + * + * See the discussion folder at https://github.com/BobHanson/IntervalStoreJ for + * details. + * + * @author gmcarstairs + * @author Bob Hanson 2019.08.03-2019.08.16 + * + */ +public class FeatureStoreJS extends FeatureStore +{ + private IntervalStore featureStore; + + public FeatureStoreJS() + { + // the only reference to features field in this class -- for the superclass + + // linked-list no-NCList IntervalStore with presort + + features = featureStore = new IntervalStore<>(true); + } + + /** + * Add a contact feature to the lists that hold them ordered by start (first + * contact) and by end (second contact) position, ensuring the lists remain + * ordered. This method allows duplicate features to be added, so test before + * calling to avoid this. + * + * @param feature + * @return true + */ + @Override + protected synchronized boolean addContactFeature(SequenceFeature feature) + { + if (contactFeatureStarts == null) + { + contactFeatureStarts = new ArrayList<>(); + contactFeatureEnds = new ArrayList<>(); + } + contactFeatureStarts.add( + findFirstBegin(contactFeatureStarts, feature.begin), feature); + contactFeatureEnds.add(findFirstEnd(contactFeatureEnds, feature.end), + feature); + return true; + } + + + /** + * Add a feature to the IntervalStore, not allowing for duplicates. + * + * + * @return false if could not add it (late check for duplicate) + */ + @Override + protected synchronized boolean addPositionalFeature( + SequenceFeature feature) + { + return featureStore.add(feature, false); + } + + /** + * Initial check in FeatureStore.add(feature) that in other implementations + * does a containment check, but in this implementation just returns false to + * indicate that we should continue. This implementation will do this check as + * part of the add() method for greater efficiency (one binary search instead + * of two). + * + * @return false -- meaning "maybe not contained; continue adding" + */ + @Override + protected boolean checkContainsPositionalFeatureForAdd( + SequenceFeature feature) + { + return false; + } + + /** + * Check to see if a feature (or its equivalent based on + * IntervalI.equalsInterval) is already in this store. This method should be + * avoided except when necessary, as it involves a binary search with identity + * check. + * + * @return true if this feature or its equivalent (based on equalsInterval) is + * present already in the collection. + */ + @Override + protected boolean containsFeature(SequenceFeature feature) + { + return featureStore.contains(feature); + } + + @Override + protected boolean findAndRemoveNonContactFeature(SequenceFeature sf) + { + return featureStore.remove(sf); + } + + /** + * Add contact features to the result list where either the second or the + * first contact position lies within the target range, inclusively. + * + * @param from + * @param to + * @param result + */ + @Override + protected void findContactFeatures(long from, long to, + List result) + { + getContactStartOverlaps(from, to, result); + getContactEndOverlaps(from, to, result); + } + + /** + * Locate the first feature start in a standard ArrayList that is at or after + * this position. + * + */ + + @Override + protected int findFirstBegin(List list, long pos) + { + int matched = list.size(); + int end = matched - 1; + int start = (end < 0 || list.get(end).begin < pos ? matched : 0); + while (start <= end) + { + int mid = (start + end) / 2; + if (list.get(mid).begin >= pos) + { + matched = mid; + end = mid - 1; + } + else + { + start = mid + 1; + } + } + return matched; + } + + /** + * Locate the feature end in a standard ArrayList that is after or at this + * position. + * + */ + + @Override + protected int findFirstEnd(List list, long pos) + { + int matched = list.size(); + int end = matched - 1; + int start = 0; + while (start <= end) + { + int mid = (start + end) / 2; + if (list.get(mid).end >= pos) + { + matched = mid; + end = mid - 1; + } + else + { + start = mid + 1; + } + } + return matched; + } + + /** + * Returns a (possibly empty) list of features whose extent overlaps the given + * range. The returned list is ordered as follows: + * + * (1) ContactFeature starts + * + * (2) ContactFeature ends (that are not also starts) + * + * (3) noncontact SequenceFeatures, in reverse start order + * + * (This last reverse order is for efficiency in processing only.) + * + * + * + * @param start + * start position of overlap range (inclusive) + * @param end + * end position of overlap range (inclusive) + * + * @param result + * optional result list; for highest efficiency, provide this + * parameter + * @return result same as result parameter, or a new ArrayList if that is null + */ + + @Override + public List findOverlappingFeatures(long start, long end, + List result) + { + if (result == null) + { + result = new ArrayList<>(); + } + if (contactFeatureStarts != null) + { + if (start == end) + { + getContactPointStarts(contactFeatureStarts, start, result); + getContactPointEnds(contactFeatureEnds, end, result); + } + else + { + findContactFeatures(start, end, result); + } + } + if (featureStore.size() > 0) + { + featureStore.findOverlaps(start, end, result); + } + return result; + } + + /** + * Adds to the result list any contact features having end (second contact + * point), but not start (first contact point), in the query from-to range + * + * @param from + * @param to + * @param result + */ + + private void getContactEndOverlaps(long from, long to, + List result) + { + // find the first contact feature (if any) + // with end point not before the target range + + for (int i = findFirstEnd(contactFeatureEnds, + from), n = contactFeatureEnds.size(); i < n; i++) + { + SequenceFeature sf = contactFeatureEnds.get(i); + if (sf.begin >= from && sf.begin <= to) + { + // this feature's first contact position lies in the search range + // so we don't include it in results a second time + continue; + } + + if (sf.end > to) + { + // this feature (and all following) has end point after the target range + break; + } + + // feature has end >= from and end <= to + // i.e. contact end point lies within overlap search range + result.add(sf); + } + } + + /** + * Binary search for contact start or end matching a specific position. This + * efficient search was designed specifically for rapid return for the + * OverviewPanel. It's implementation sped processing of that panel by 2300%. + * + * @param l + * @param pos + * @param result + * @param isStart + * + * @author Bob Hanson 2019.07.30 + */ + private void getContactPointStarts(List l, long pos, + List result) + { + int low = 0; + int high = l.size() - 1; + while (low <= high) + { + int mid = (low + high) >>> 1; + SequenceFeature f = l.get(mid); + switch (Long.signum(f.begin - pos)) + { + case -1: + low = mid + 1; + continue; + case 1: + high = mid - 1; + continue; + case 0: + int m = mid; + result.add(f); + // could be "5" in 12345556788 ? + while (++mid <= high && (f = l.get(mid)) != null && f.begin == pos) + { + result.add(f); + } + while (--m >= low && (f = l.get(m)) != null && f.begin == pos) + { + result.add(f); + } + return; + } + } + } + + private void getContactPointEnds(List l, long pos, + List result) + { + int low = 0; + int high = l.size() - 1; + while (low <= high) + { + int mid = (low + high) >>> 1; + SequenceFeature f = l.get(mid); + switch (Long.signum(f.end - pos)) + { + case -1: + low = mid + 1; + continue; + case 1: + high = mid - 1; + continue; + case 0: + int m = mid; + if (f.begin != f.end) + { + result.add(f); + } + // could be "5" in 12345556788 ? + while (++mid <= high && (f = l.get(mid)) != null + && f.end == pos) + { + if (f.begin != f.end) + { + result.add(f); + } + } + while (--m >= low && (f = l.get(m)) != null + && f.end == pos) + { + if (f.begin != f.end) + { + result.add(f); + } + } + return; + } + } + } + + /** + * Adds contact features whose start position lies in the from-to range to the + * result list + * + * @param from + * @param to + * @param result + */ + + private void getContactStartOverlaps(long from, long to, + List result) + { + for (int i = findFirstBegin(contactFeatureStarts, + from), n = contactFeatureStarts.size(); i < n; i++) + { + SequenceFeature sf = contactFeatureStarts.get(i); + if (sf.begin > to) + { + break; + } + result.add(sf); + } + } +} diff --git a/src/jalview/datamodel/features/SequenceFeatures.java b/src/jalview/datamodel/features/SequenceFeatures.java index ba8396a..cb2b8cc 100644 --- a/src/jalview/datamodel/features/SequenceFeatures.java +++ b/src/jalview/datamodel/features/SequenceFeatures.java @@ -23,6 +23,7 @@ package jalview.datamodel.features; import jalview.datamodel.SequenceFeature; import jalview.io.gff.SequenceOntologyFactory; import jalview.io.gff.SequenceOntologyI; +import jalview.util.Platform; import java.util.ArrayList; import java.util.Arrays; @@ -50,7 +51,33 @@ public class SequenceFeatures implements SequenceFeaturesI * map from feature type to structured store of features for that type * null types are permitted (but not a good idea!) */ - private Map featureStore; + private Map featureStore; + + /** + * original NCList-based IntervalStore + */ + private final static int INTERVAL_STORE_NCLIST = 0; + + /** + * linked-list deferred-sort IntervalStore - experimental only; unused + */ + private final static int INTERVAL_STORE_LINKED_LIST_NO_PRESORT = 1; + + /** + * linked-list IntervalStore option for JavaScript + */ + private final static int INTERVAL_STORE_LINKED_LIST = -1; + + /** + * mode for Java or JavaScript; can be set differently for testing, but + * default is LINKED_LIST for JalviewJS and NCLIST for Java + */ + private final int INTERVAL_STORE_MODE = ( + // true || // + Platform.isJS() ? // + INTERVAL_STORE_LINKED_LIST // + : INTERVAL_STORE_NCLIST// + ); /** * Constructor @@ -62,7 +89,7 @@ public class SequenceFeatures implements SequenceFeaturesI * ? wrap as a synchronized map for add and delete operations */ // featureStore = Collections - // .synchronizedSortedMap(new TreeMap()); + // .synchronizedSortedMap(new TreeMap()); featureStore = new TreeMap<>(); } @@ -96,11 +123,25 @@ public class SequenceFeatures implements SequenceFeaturesI if (featureStore.get(type) == null) { - featureStore.put(type, new FeatureStore()); + featureStore.put(type, newFeatureStore()); } return featureStore.get(type).addFeature(sf); } + private FeatureStoreI newFeatureStore() + { + switch (INTERVAL_STORE_MODE) + { + default: + case INTERVAL_STORE_NCLIST: + return new FeatureStoreImpl(true); + case INTERVAL_STORE_LINKED_LIST_NO_PRESORT: + return new FeatureStoreImpl(false); + case INTERVAL_STORE_LINKED_LIST: + return new FeatureStoreJS(); + } + } + /** * {@inheritDoc} */ @@ -109,12 +150,14 @@ public class SequenceFeatures implements SequenceFeaturesI String... type) { List result = new ArrayList<>(); - - for (FeatureStore featureSet : varargToTypes(type)) + for (FeatureStoreI featureSet : varargToTypes(type)) { - result.addAll(featureSet.findOverlappingFeatures(from, to)); + // System.err.println("SF findFeature " + System.currentTimeMillis() + // + " " + from + " " + to + " " + // + featureSet.getPositionalFeatures().get(0).type); + // + result.addAll(featureSet.findOverlappingFeatures(from, to, null)); } - return result; } @@ -153,8 +196,8 @@ public class SequenceFeatures implements SequenceFeaturesI return new ArrayList<>(); } - return getAllFeatures(featureTypes.toArray(new String[featureTypes - .size()])); + return getAllFeatures( + featureTypes.toArray(new String[featureTypes.size()])); } /** @@ -165,7 +208,7 @@ public class SequenceFeatures implements SequenceFeaturesI { int result = 0; - for (FeatureStore featureSet : varargToTypes(type)) + for (FeatureStoreI featureSet : varargToTypes(type)) { result += featureSet.getFeatureCount(positional); } @@ -180,7 +223,7 @@ public class SequenceFeatures implements SequenceFeaturesI { int result = 0; - for (FeatureStore featureSet : varargToTypes(type)) + for (FeatureStoreI featureSet : varargToTypes(type)) { result += featureSet.getTotalFeatureLength(); } @@ -195,9 +238,9 @@ public class SequenceFeatures implements SequenceFeaturesI { List result = new ArrayList<>(); - for (FeatureStore featureSet : varargToTypes(type)) + for (FeatureStoreI featureSet : varargToTypes(type)) { - result.addAll(featureSet.getPositionalFeatures()); + featureSet.getPositionalFeatures(result); } return result; } @@ -209,7 +252,7 @@ public class SequenceFeatures implements SequenceFeaturesI * @param type * @return */ - protected Iterable varargToTypes(String... type) + protected Iterable varargToTypes(String... type) { if (type == null || type.length == 0) { @@ -219,9 +262,9 @@ public class SequenceFeatures implements SequenceFeaturesI return featureStore.values(); } - List types = new ArrayList<>(); + List types = new ArrayList<>(); List args = Arrays.asList(type); - for (Entry featureType : featureStore.entrySet()) + for (Entry featureType : featureStore.entrySet()) { if (args.contains(featureType.getKey())) { @@ -239,9 +282,9 @@ public class SequenceFeatures implements SequenceFeaturesI { List result = new ArrayList<>(); - for (FeatureStore featureSet : varargToTypes(type)) + for (FeatureStoreI featureSet : varargToTypes(type)) { - result.addAll(featureSet.getContactFeatures()); + featureSet.getContactFeatures(result); } return result; } @@ -254,9 +297,9 @@ public class SequenceFeatures implements SequenceFeaturesI { List result = new ArrayList<>(); - for (FeatureStore featureSet : varargToTypes(type)) + for (FeatureStoreI featureSet : varargToTypes(type)) { - result.addAll(featureSet.getNonPositionalFeatures()); + featureSet.getNonPositionalFeatures(result); } return result; } @@ -267,7 +310,7 @@ public class SequenceFeatures implements SequenceFeaturesI @Override public boolean delete(SequenceFeature sf) { - for (FeatureStore featureSet : featureStore.values()) + for (FeatureStoreI featureSet : featureStore.values()) { if (featureSet.delete(sf)) { @@ -283,7 +326,7 @@ public class SequenceFeatures implements SequenceFeaturesI @Override public boolean hasFeatures() { - for (FeatureStore featureSet : featureStore.values()) + for (FeatureStoreI featureSet : featureStore.values()) { if (!featureSet.isEmpty()) { @@ -302,7 +345,7 @@ public class SequenceFeatures implements SequenceFeaturesI { Set groups = new HashSet<>(); - for (FeatureStore featureSet : varargToTypes(type)) + for (FeatureStoreI featureSet : varargToTypes(type)) { groups.addAll(featureSet.getFeatureGroups(positionalFeatures)); } @@ -319,10 +362,10 @@ public class SequenceFeatures implements SequenceFeaturesI { Set result = new HashSet<>(); - for (Entry featureType : featureStore.entrySet()) + for (Entry featureType : featureStore.entrySet()) { - Set featureGroups = featureType.getValue().getFeatureGroups( - positionalFeatures); + Set featureGroups = featureType.getValue() + .getFeatureGroups(positionalFeatures); for (String group : groups) { if (featureGroups.contains(group)) @@ -346,7 +389,7 @@ public class SequenceFeatures implements SequenceFeaturesI public Set getFeatureTypes(String... soTerm) { Set types = new HashSet<>(); - for (Entry entry : featureStore.entrySet()) + for (Entry entry : featureStore.entrySet()) { String type = entry.getKey(); if (!entry.getValue().isEmpty() && isOntologyTerm(type, soTerm)) @@ -373,7 +416,7 @@ public class SequenceFeatures implements SequenceFeaturesI { return true; } - SequenceOntologyI so = SequenceOntologyFactory.getInstance(); + SequenceOntologyI so = SequenceOntologyFactory.getSequenceOntology(); for (String term : soTerm) { if (type.equals(term) || so.isA(type, term)) @@ -390,8 +433,9 @@ public class SequenceFeatures implements SequenceFeaturesI @Override public float getMinimumScore(String type, boolean positional) { - return featureStore.containsKey(type) ? featureStore.get(type) - .getMinimumScore(positional) : Float.NaN; + return featureStore.containsKey(type) + ? featureStore.get(type).getMinimumScore(positional) + : Float.NaN; } /** @@ -400,8 +444,9 @@ public class SequenceFeatures implements SequenceFeaturesI @Override public float getMaximumScore(String type, boolean positional) { - return featureStore.containsKey(type) ? featureStore.get(type) - .getMaximumScore(positional) : Float.NaN; + return featureStore.containsKey(type) + ? featureStore.get(type).getMaximumScore(positional) + : Float.NaN; } /** @@ -433,7 +478,7 @@ public class SequenceFeatures implements SequenceFeaturesI String group, String... type) { List result = new ArrayList<>(); - for (FeatureStore featureSet : varargToTypes(type)) + for (FeatureStoreI featureSet : varargToTypes(type)) { if (featureSet.getFeatureGroups(positional).contains(group)) { @@ -450,7 +495,7 @@ public class SequenceFeatures implements SequenceFeaturesI public boolean shiftFeatures(int fromPosition, int shiftBy) { boolean modified = false; - for (FeatureStore fs : featureStore.values()) + for (FeatureStoreI fs : featureStore.values()) { modified |= fs.shiftFeatures(fromPosition, shiftBy); } @@ -465,4 +510,63 @@ public class SequenceFeatures implements SequenceFeaturesI { featureStore.clear(); } + + /** + * Simplified find for features associated with a given position. + * + * JavaScript set to not use IntervalI, but easily testable by setting false + * to true in javadoc + * + * FeatureRenderer has checked already that featureStore does contain type. + * + * @author Bob Hanson 2019.07.30 + */ + @Override + public List findFeatures(int pos, String type, + List list) + { + FeatureStoreI fs = featureStore.get(type); + return fs.findOverlappingFeatures(pos, pos, list); + } + + // Chrome; developer console closed + + // BH 2019.08.01 useIntervalStore true, redraw false: + // Platform: timer mark 13.848 0.367 overviewrender 16000 pixels row:14 + // Platform: timer mark 15.391 0.39 overviewrender 16000 pixels row:14 + // Platform: timer mark 16.498 0.39 overviewrender 16000 pixels row:14 + // Platform: timer mark 17.596 0.401 overviewrender 16000 pixels row:14 + // Platform: timer mark 18.738 0.363 overviewrender 16000 pixels row:14 + // Platform: timer mark 19.659 0.358 overviewrender 16000 pixels row:14 + // Platform: timer mark 20.737 0.359 overviewrender 16000 pixels row:14 + // Platform: timer mark 21.797 0.391 overviewrender 16000 pixels row:14 + // Platform: timer mark 22.851 0.361 overviewrender 16000 pixels row:14 + // Platform: timer mark 24.019 0.395 overviewrender 16000 pixels row:14 + + // BH 2019.08.01 useIntervalStore false, redraw false: + // Platform: timer mark 19.011 0.181 overviewrender 16000 pixels row:14 + // Platform: timer mark 20.311 0.183 overviewrender 16000 pixels row:14 + // Platform: timer mark 21.368 0.175 overviewrender 16000 pixels row:14 + // Platform: timer mark 22.347 0.178 overviewrender 16000 pixels row:14 + // Platform: timer mark 23.605 0.216 overviewrender 16000 pixels row:14 + // Platform: timer mark 24.836 0.191 overviewrender 16000 pixels row:14 + // Platform: timer mark 26.016 0.181 overviewrender 16000 pixels row:14 + // Platform: timer mark 27.278 0.178 overviewrender 16000 pixels row:14 + // Platform: timer mark 28.158 0.181 overviewrender 16000 pixels row:14 + // Platform: timer mark 29.227 0.196 overviewrender 16000 pixels row:14 + // Platform: timer mark 30.1 0.171 overviewrender 16000 pixels row:14 + // Platform: timer mark 31.684 0.196 overviewrender 16000 pixels row:14 + // Platform: timer mark 32.779 0.18 overviewrender 16000 pixels row:14 + // Platform: timer mark 52.355 0.185 overviewrender 16000 pixels row:14 + // Platform: timer mark 53.829 0.186 overviewrender 16000 pixels row:14 + + /** + * @author Bob Hanson 2019.08.01 + */ + @Override + public boolean hasFeatures(String type) + { + return featureStore.containsKey(type); + } + } diff --git a/src/jalview/datamodel/features/SequenceFeaturesI.java b/src/jalview/datamodel/features/SequenceFeaturesI.java index ca0283e..deed751 100644 --- a/src/jalview/datamodel/features/SequenceFeaturesI.java +++ b/src/jalview/datamodel/features/SequenceFeaturesI.java @@ -228,4 +228,23 @@ public interface SequenceFeaturesI * Deletes all positional and non-positional features */ void deleteAll(); + + /** + * Point-specific parameter return for JavaScript + * + * @param pos + * @param type + * @param result + * @return result (JavaScript) or new ArrayList (Java -- see FeatureRender) + * @author Bob Hanson 2019.07.30 + */ + List findFeatures(int pos, String type, List result); + + /** + * @author Bob Hanson 2019.08.01 + * + * @param type + * @return true if this type is in featureStore + */ + boolean hasFeatures(String type); } diff --git a/src/jalview/ext/ensembl/EnsemblCdna.java b/src/jalview/ext/ensembl/EnsemblCdna.java index e01ad17..bdfd208 100644 --- a/src/jalview/ext/ensembl/EnsemblCdna.java +++ b/src/jalview/ext/ensembl/EnsemblCdna.java @@ -23,6 +23,7 @@ package jalview.ext.ensembl; import jalview.datamodel.SequenceFeature; import jalview.datamodel.SequenceI; import jalview.io.gff.SequenceOntologyI; +import jalview.util.Platform; import java.util.ArrayList; import java.util.List; @@ -44,9 +45,7 @@ public class EnsemblCdna extends EnsemblSeqProxy * or ENSMUST or similar for other species * or CCDSnnnnn.nn with at least 3 digits */ - private static final Regex ACCESSION_REGEX = new Regex( - "(ENS([A-Z]{3}|)[TG][0-9]{11}$)" + "|" + "(CCDS[0-9.]{3,}$)"); - + private static Regex ACCESSION_REGEX; /* * fetch exon features on genomic sequence (to identify the cdna regions) * and cds and variation features (to retain) @@ -88,6 +87,16 @@ public class EnsemblCdna extends EnsemblSeqProxy @Override public Regex getAccessionValidator() { + if (ACCESSION_REGEX == null) + { + /* + * accepts ENSG/T/E/P with 11 digits + * or ENSMUSP or similar for other species + * or CCDSnnnnn.nn with at least 3 digits + */ + ACCESSION_REGEX = Platform.newRegex( + "(ENS([A-Z]{3}|)[TG][0-9]{11}$)" + "|" + "(CCDS[0-9.]{3,}$)", null); + } return ACCESSION_REGEX; } diff --git a/src/jalview/ext/ensembl/EnsemblCds.java b/src/jalview/ext/ensembl/EnsemblCds.java index 8f13d99..bf37265 100644 --- a/src/jalview/ext/ensembl/EnsemblCds.java +++ b/src/jalview/ext/ensembl/EnsemblCds.java @@ -93,7 +93,7 @@ public class EnsemblCds extends EnsemblSeqProxy @Override protected boolean retainFeature(SequenceFeature sf, String accessionId) { - if (SequenceOntologyFactory.getInstance().isA(sf.getType(), + if (SequenceOntologyFactory.getSequenceOntology().isA(sf.getType(), SequenceOntologyI.CDS)) { return false; diff --git a/src/jalview/ext/ensembl/EnsemblGene.java b/src/jalview/ext/ensembl/EnsemblGene.java index 0d73a47..63a6a6c 100644 --- a/src/jalview/ext/ensembl/EnsemblGene.java +++ b/src/jalview/ext/ensembl/EnsemblGene.java @@ -56,7 +56,7 @@ public class EnsemblGene extends EnsemblSeqProxy * accepts anything as we will attempt lookup of gene or * transcript id or gene name */ - private static final Regex ACCESSION_REGEX = new Regex(".*"); + private static Regex ACCESSION_REGEX; private static final EnsemblFeatureType[] FEATURES_TO_FETCH = { EnsemblFeatureType.gene, EnsemblFeatureType.transcript, @@ -577,7 +577,7 @@ public class EnsemblGene extends EnsemblSeqProxy @Override protected boolean retainFeature(SequenceFeature sf, String accessionId) { - SequenceOntologyI so = SequenceOntologyFactory.getInstance(); + SequenceOntologyI so = SequenceOntologyFactory.getSequenceOntology(); String type = sf.getType(); if (so.isA(type, SequenceOntologyI.GENE)) { @@ -606,6 +606,10 @@ public class EnsemblGene extends EnsemblSeqProxy @Override public Regex getAccessionValidator() { + if (ACCESSION_REGEX == null) + { + ACCESSION_REGEX = Platform.newRegex(".*", null); + } return ACCESSION_REGEX; } @@ -624,7 +628,7 @@ public class EnsemblGene extends EnsemblSeqProxy { return new FeatureSettingsAdapter() { - SequenceOntologyI so = SequenceOntologyFactory.getInstance(); + SequenceOntologyI so = SequenceOntologyFactory.getSequenceOntology(); @Override public boolean isFeatureDisplayed(String type) diff --git a/src/jalview/ext/ensembl/EnsemblInfo.java b/src/jalview/ext/ensembl/EnsemblInfo.java index 97a8e74..a59a64d 100644 --- a/src/jalview/ext/ensembl/EnsemblInfo.java +++ b/src/jalview/ext/ensembl/EnsemblInfo.java @@ -1,10 +1,10 @@ package jalview.ext.ensembl; +import jalview.bin.ApplicationSingletonProvider; +import jalview.bin.ApplicationSingletonProvider.ApplicationSingletonI; import jalview.datamodel.AlignmentI; import jalview.datamodel.DBRefSource; -import jalview.util.JSONUtils; -import java.io.BufferedReader; import java.io.IOException; import java.net.MalformedURLException; import java.net.URL; @@ -16,9 +16,48 @@ import java.util.Set; import org.json.simple.parser.ParseException; -public class EnsemblInfo extends EnsemblRestClient +public class EnsemblInfo extends EnsemblRestClient implements ApplicationSingletonI { + /** + * On first request only, populate the lookup map by fetching the list of + * divisions known to EnsemblGenomes + * + */ + private static EnsemblInfo getInstance() + { + return (EnsemblInfo) ApplicationSingletonProvider.getInstance(EnsemblInfo.class); + } + + private EnsemblInfo() + { + // use getInstance() + + /* + * for convenience, pre-fill ensembl.org as the domain for "ENSEMBL" + */ + divisions.put(DBRefSource.ENSEMBL.toUpperCase(), ensemblDomain); + try + { + @SuppressWarnings("unchecked") + Iterator rvals = (Iterator) getJSON( + getDivisionsUrl(ensemblGenomesDomain), null, -1, + MODE_ITERATOR, null); + if (rvals == null) + { + return; + } + while (rvals.hasNext()) + { + String division = rvals.next().toString(); + divisions.put(division.toUpperCase(), ensemblGenomesDomain); + } + } catch (IOException | ParseException | NumberFormatException e) + { + // ignore + } + } + /* * cached results of REST /info/divisions service, currently *
    @@ -34,7 +73,7 @@ public class EnsemblInfo extends EnsemblRestClient
        * The values for EnsemblGenomes are retrieved by a REST call, that for
        * Ensembl is added programmatically for convenience of lookup
        */
    -  private static Map divisions;
    +  private Map divisions = new HashMap<>();
     
       @Override
       public String getDbName()
    @@ -68,42 +107,9 @@ public class EnsemblInfo extends EnsemblRestClient
        * @param division
        * @return
        */
    -  public String getDomain(String division)
    +  public static String getDomain(String division)
       {
    -    if (divisions == null)
    -    {
    -      fetchDivisions();
    -    }
    -    return divisions.get(division.toUpperCase());
    -  }
    -
    -  /**
    -   * On first request only, populate the lookup map by fetching the list of
    -   * divisions known to EnsemblGenomes.
    -   */
    -  void fetchDivisions()
    -  {
    -    divisions = new HashMap<>();
    -
    -    /*
    -     * for convenience, pre-fill ensembl.org as the domain for "ENSEMBL"
    -     */
    -    divisions.put(DBRefSource.ENSEMBL.toUpperCase(), ensemblDomain);
    -    try
    -    {
    -      @SuppressWarnings("unchecked")
    -   	  Iterator rvals = (Iterator) getJSON(getDivisionsUrl(ensemblGenomesDomain), null, -1, MODE_ITERATOR, null);
    -      if (rvals == null)
    -    	  return;
    -      while (rvals.hasNext())
    -      {
    -        String division = rvals.next().toString();
    -        divisions.put(division.toUpperCase(), ensemblGenomesDomain);
    -      }
    -    } catch (IOException | ParseException | NumberFormatException e)
    -    {
    -      // ignore
    -    }
    +    return getInstance().divisions.get(division.toUpperCase());
       }
     
       /**
    @@ -124,12 +130,8 @@ public class EnsemblInfo extends EnsemblRestClient
        * 
        * @return
        */
    -  public Set getDivisions() {
    -    if (divisions == null)
    -    {
    -      fetchDivisions();
    -    }
    -
    -    return divisions.keySet();
    +  public static Set getDivisions()
    +  {
    +    return getInstance().divisions.keySet();
       }
     }
    diff --git a/src/jalview/ext/ensembl/EnsemblMap.java b/src/jalview/ext/ensembl/EnsemblMap.java
    index e9f1af1..9789819 100644
    --- a/src/jalview/ext/ensembl/EnsemblMap.java
    +++ b/src/jalview/ext/ensembl/EnsemblMap.java
    @@ -3,10 +3,8 @@ package jalview.ext.ensembl;
     import jalview.datamodel.AlignmentI;
     import jalview.datamodel.DBRefSource;
     import jalview.datamodel.GeneLociI;
    -import jalview.util.JSONUtils;
     import jalview.util.MapList;
     
    -import java.io.BufferedReader;
     import java.io.IOException;
     import java.net.MalformedURLException;
     import java.net.URL;
    @@ -18,18 +16,6 @@ import java.util.Map;
     
     import org.json.simple.parser.ParseException;
     
    -/**
    - * A client for the Ensembl REST service /map endpoint, to convert from
    - * coordinates of one genome assembly to another.
    - * 

    - * Note that species and assembly identifiers passed to this class must be valid - * in Ensembl. They are not case sensitive. - * - * @author gmcarstairs - * @see https://rest.ensembl.org/documentation/info/assembly_map - * @see https://rest.ensembl.org/info/assembly/human?content-type=text/xml - * @see https://rest.ensembl.org/info/species?content-type=text/xml - */ public class EnsemblMap extends EnsemblRestClient { private static final String MAPPED = "mapped"; @@ -166,7 +152,9 @@ public class EnsemblMap extends EnsemblRestClient { Iterator rvals = (Iterator) getJSON(url, null, -1, MODE_ITERATOR, MAPPINGS); if (rvals == null) - return null; + { + return null; + } while (rvals.hasNext()) { // todo check for "mapped" @@ -233,7 +221,7 @@ public class EnsemblMap extends EnsemblRestClient URL url = null; try { - String domain = new EnsemblInfo().getDomain(division); + String domain = EnsemblInfo.getDomain(division); if (domain != null) { url = getIdMapUrl(domain, accession, start, end, cdsOrCdna); @@ -298,7 +286,9 @@ GeneLociI parseIdMappingResponse(URL url, String accession, { Iterator rvals = (Iterator) getJSON(url, null, -1, MODE_ITERATOR, MAPPINGS); if (rvals == null) - return null; + { + return null; + } String assembly = null; String chromosome = null; int fromEnd = 0; diff --git a/src/jalview/ext/ensembl/EnsemblProtein.java b/src/jalview/ext/ensembl/EnsemblProtein.java index 0280f16..f586ed6 100644 --- a/src/jalview/ext/ensembl/EnsemblProtein.java +++ b/src/jalview/ext/ensembl/EnsemblProtein.java @@ -23,6 +23,7 @@ package jalview.ext.ensembl; import jalview.datamodel.AlignmentI; import jalview.datamodel.SequenceFeature; import jalview.datamodel.SequenceI; +import jalview.util.Platform; import java.util.ArrayList; import java.util.List; @@ -42,8 +43,7 @@ public class EnsemblProtein extends EnsemblSeqProxy * or ENSMUSP or similar for other species * or CCDSnnnnn.nn with at least 3 digits */ - private static final Regex ACCESSION_REGEX = new Regex( - "(ENS([A-Z]{3}|)P[0-9]{11}$)" + "|" + "(CCDS[0-9.]{3,}$)"); + private static Regex ACCESSION_REGEX; /** * Default constructor (to use rest.ensembl.org) @@ -119,6 +119,11 @@ public class EnsemblProtein extends EnsemblSeqProxy @Override public Regex getAccessionValidator() { + if (ACCESSION_REGEX == null) + { + ACCESSION_REGEX = Platform.newRegex( + "(ENS([A-Z]{3}|)P[0-9]{11}$)" + "|" + "(CCDS[0-9.]{3,}$)", null); + } return ACCESSION_REGEX; } diff --git a/src/jalview/ext/ensembl/EnsemblRestClient.java b/src/jalview/ext/ensembl/EnsemblRestClient.java index bf151bf..6d4bc79 100644 --- a/src/jalview/ext/ensembl/EnsemblRestClient.java +++ b/src/jalview/ext/ensembl/EnsemblRestClient.java @@ -75,7 +75,7 @@ abstract class EnsemblRestClient extends EnsemblSequenceFetcher private static final String REST_CHANGE_LOG = "https://github.com/Ensembl/ensembl-rest/wiki/Change-log"; - private static Map domainData; + private static final Map domainData; private final static long AVAILABILITY_RETEST_INTERVAL = 10000L; // 10 seconds diff --git a/src/jalview/ext/ensembl/EnsemblSeqProxy.java b/src/jalview/ext/ensembl/EnsemblSeqProxy.java index 2e20665..bdaef0b 100644 --- a/src/jalview/ext/ensembl/EnsemblSeqProxy.java +++ b/src/jalview/ext/ensembl/EnsemblSeqProxy.java @@ -423,7 +423,9 @@ public abstract class EnsemblSeqProxy extends EnsemblRestClient List seqs = parseSequenceJson(ids); if (seqs == null) - return alignment; + { + return alignment; + } if (seqs.isEmpty()) { @@ -490,7 +492,9 @@ public abstract class EnsemblSeqProxy extends EnsemblRestClient Platform.timeCheck("ENS seqproxy", Platform.TIME_MARK); Map val = (Map) getJSON(null, ids, -1, MODE_MAP, null); if (val == null) - return null; + { + return null; + } Object s = val.get("desc"); String desc = s == null ? null : s.toString(); s = val.get("id"); @@ -736,7 +740,7 @@ public abstract class EnsemblSeqProxy extends EnsemblRestClient * for sequence_variant on reverse strand, have to convert the allele * values to their complements */ - if (!forwardStrand && SequenceOntologyFactory.getInstance() + if (!forwardStrand && SequenceOntologyFactory.getSequenceOntology() .isA(sf.getType(), SequenceOntologyI.SEQUENCE_VARIANT)) { reverseComplementAlleles(copy); @@ -984,7 +988,7 @@ public abstract class EnsemblSeqProxy extends EnsemblRestClient public static boolean isTranscript(String featureType) { return SequenceOntologyI.NMD_TRANSCRIPT_VARIANT.equals(featureType) - || SequenceOntologyFactory.getInstance().isA(featureType, + || SequenceOntologyFactory.getSequenceOntology().isA(featureType, SequenceOntologyI.TRANSCRIPT); } } diff --git a/src/jalview/ext/ensembl/EnsemblSequenceFetcher.java b/src/jalview/ext/ensembl/EnsemblSequenceFetcher.java index 7454eb6..21f9f7e 100644 --- a/src/jalview/ext/ensembl/EnsemblSequenceFetcher.java +++ b/src/jalview/ext/ensembl/EnsemblSequenceFetcher.java @@ -23,6 +23,7 @@ package jalview.ext.ensembl; import jalview.analysis.AlignmentUtils; import jalview.bin.Cache; import jalview.datamodel.DBRefSource; +import jalview.util.Platform; import jalview.ws.seqfetcher.DbSourceProxyImpl; import com.stevesoft.pat.Regex; @@ -45,14 +46,7 @@ abstract class EnsemblSequenceFetcher extends DbSourceProxyImpl // ensemblgenomes REST service merged to ensembl 9th April 2019 protected static final String DEFAULT_ENSEMBL_GENOMES_BASEURL = DEFAULT_ENSEMBL_BASEURL; - /* - * accepts ENSG/T/E/P with 11 digits - * or ENSMUSP or similar for other species - * or CCDSnnnnn.nn with at least 3 digits - */ - private static final Regex ACCESSION_REGEX = new Regex( - "(ENS([A-Z]{3}|)[GTEP]{1}[0-9]{11}$)" + "|" - + "(CCDS[0-9.]{3,}$)"); + private static Regex ACCESSION_REGEX; protected final String ensemblGenomesDomain; @@ -121,6 +115,17 @@ abstract class EnsemblSequenceFetcher extends DbSourceProxyImpl @Override public Regex getAccessionValidator() { + if (ACCESSION_REGEX == null) + { + /* + * accepts ENSG/T/E/P with 11 digits + * or ENSMUSP or similar for other species + * or CCDSnnnnn.nn with at least 3 digits + */ + ACCESSION_REGEX = Platform + .newRegex("(ENS([A-Z]{3}|)[GTEP]{1}[0-9]{11}$)" + "|" + + "(CCDS[0-9.]{3,}$)", null); + } return ACCESSION_REGEX; } diff --git a/src/jalview/ext/htsjdk/VCFReader.java b/src/jalview/ext/htsjdk/VCFReader.java index 04525f0..14c057f 100644 --- a/src/jalview/ext/htsjdk/VCFReader.java +++ b/src/jalview/ext/htsjdk/VCFReader.java @@ -1,14 +1,14 @@ package jalview.ext.htsjdk; -import java.io.Closeable; -import java.io.File; -import java.io.IOException; - import htsjdk.samtools.util.CloseableIterator; import htsjdk.variant.variantcontext.VariantContext; import htsjdk.variant.vcf.VCFFileReader; import htsjdk.variant.vcf.VCFHeader; +import java.io.Closeable; +import java.io.File; +import java.io.IOException; + /** * A thin wrapper for htsjdk classes to read either plain, or compressed, or * compressed and indexed VCF files @@ -116,7 +116,7 @@ public class VCFReader implements Closeable, Iterable { final CloseableIterator it = reader.iterator(); - return new CloseableIterator() + return new CloseableIterator() { boolean atEnd = false; @@ -145,7 +145,7 @@ public class VCFReader implements Closeable, Iterable int vend = variant.getEnd(); // todo what is the undeprecated way to get // the chromosome for the variant? - if (chrom.equals(variant.getContig()) && (vstart <= end) + if (chrom.equals(variant.getChr()) && (vstart <= end) && (vend >= start)) { return variant; diff --git a/src/jalview/ext/jmol/JalviewJmolBinding.java b/src/jalview/ext/jmol/JalviewJmolBinding.java index 4698e4d..fa31fd9 100644 --- a/src/jalview/ext/jmol/JalviewJmolBinding.java +++ b/src/jalview/ext/jmol/JalviewJmolBinding.java @@ -44,6 +44,7 @@ import java.awt.event.ComponentEvent; import java.awt.event.ComponentListener; import java.io.File; import java.net.URL; +import java.security.AccessControlException; import java.util.ArrayList; import java.util.BitSet; import java.util.Hashtable; @@ -618,6 +619,74 @@ public abstract class JalviewJmolBinding extends AAStructureBindingModel */ private int _modelFileNameMap[]; + // //////////////////////////////// + // /StructureListener + // @Override + public synchronized String[] getPdbFilex() + { + if (viewer == null) + { + return new String[0]; + } + if (modelFileNames == null) + { + List mset = new ArrayList<>(); + _modelFileNameMap = new int[viewer.ms.mc]; + String m = viewer.ms.getModelFileName(0); + if (m != null) + { + String filePath = m; + try + { + filePath = new File(m).getAbsolutePath(); + } catch (AccessControlException x) + { + // usually not allowed to do this in applet + System.err.println( + "jmolBinding: Using local file string from Jmol: " + m); + } + if (filePath.indexOf("/file:") != -1) + { + // applet path with docroot - discard as format won't match pdbfile + filePath = m; + } + mset.add(filePath); + _modelFileNameMap[0] = 0; // filename index for first model is always 0. + } + int j = 1; + for (int i = 1; i < viewer.ms.mc; i++) + { + m = viewer.ms.getModelFileName(i); + String filePath = m; + if (m != null) + { + try + { + filePath = new File(m).getAbsolutePath(); + } catch (AccessControlException x) + { + // usually not allowed to do this in applet, so keep raw handle + // System.err.println("jmolBinding: Using local file string from + // Jmol: "+m); + } + } + + /* + * add this model unless it is read from a structure file we have + * already seen (example: 2MJW is an NMR structure with 10 models) + */ + if (!mset.contains(filePath)) + { + mset.add(filePath); + _modelFileNameMap[j] = i; // record the model index for the filename + j++; + } + } + modelFileNames = mset.toArray(new String[mset.size()]); + } + return modelFileNames; + } + @Override public synchronized String[] getStructureFiles() { @@ -812,7 +881,7 @@ public abstract class JalviewJmolBinding extends AAStructureBindingModel try { // recover PDB filename for the model hovered over. - int mnumber = Integer.valueOf(mdlId).intValue() - 1; + int mnumber = new Integer(mdlId).intValue() - 1; if (_modelFileNameMap != null) { int _mp = _modelFileNameMap.length - 1; diff --git a/src/jalview/ext/paradise/Annotate3D.java b/src/jalview/ext/paradise/Annotate3D.java index 3c443de..3b7044b 100644 --- a/src/jalview/ext/paradise/Annotate3D.java +++ b/src/jalview/ext/paradise/Annotate3D.java @@ -137,13 +137,13 @@ public class Annotate3D public static Iterator getRNAMLForPDBFileAsString(String pdbfile) throws Exception { - List vals = new ArrayList<>(); + List vals = new ArrayList(); vals.add(new BasicNameValuePair("tool", "rnaview")); vals.add(new BasicNameValuePair("data", pdbfile)); vals.add(new BasicNameValuePair("output", "rnaml")); // return processJsonResponseFor(HttpClientUtils.doHttpUrlPost(twoDtoolsURL, // vals)); - ArrayList readers = new ArrayList<>(); + ArrayList readers = new ArrayList(); final BufferedReader postResponse = HttpClientUtils .doHttpUrlPost(twoDtoolsURL, vals, 0, 0); readers.add(postResponse); @@ -159,23 +159,90 @@ public class Annotate3D public static Iterator processJsonResponseFor(Reader respons) throws Exception { + // BH 2019 never called? try { @SuppressWarnings("unchecked") - List responses = (List) JSONUtils.parse(respons); - return new RvalsIterator(responses); + final Iterator rvals = ((List) JSONUtils.parse(respons)).iterator(); + return new Iterator() + { + @Override + public boolean hasNext() + { + return rvals.hasNext(); + } + + @SuppressWarnings("unchecked") + @Override + public Reader next() + { + Map val = (Map) rvals.next(); + + Object sval = null; + try + { + sval = val.get("2D"); + } catch (Exception x) + { + x.printStackTrace(); + } + ; + if (sval == null) + { + System.err.println( + "DEVELOPER WARNING: Annotate3d didn't return a '2D' tag in its response. Consider checking output of server. Response was :" + + val.toString()); + + sval = ""; + } + return new StringReader(sval.toString()); + + } + + @Override + public void remove() + { + throw new Error( + MessageManager.getString("error.not_implemented_remove")); + + } + + @Override + protected Object clone() throws CloneNotSupportedException + { + throw new CloneNotSupportedException( + MessageManager.getString("error.not_implemented_clone")); + } + + @Override + public boolean equals(Object obj) + { + return super.equals(obj); + } + + @Override + protected void finalize() throws Throwable + { + while (rvals.hasNext()) + { + rvals.next(); + } + super.finalize(); + } + }; } catch (Exception foo) { throw new Exception(MessageManager.getString( "exception.couldnt_parse_responde_from_annotated3d_server"), foo); } + } public static Iterator getRNAMLForPDBId(String pdbid) throws Exception { - List vals = new ArrayList<>(); + List vals = new ArrayList(); vals.add(new BasicNameValuePair("tool", "rnaview")); vals.add(new BasicNameValuePair("pdbid", pdbid)); vals.add(new BasicNameValuePair("output", "rnaml")); @@ -183,70 +250,9 @@ public class Annotate3D + pdbid + "&output=rnaml"); // return processJsonResponseFor(new // InputStreamReader(geturl.openStream())); - ArrayList readers = new ArrayList<>(); + ArrayList readers = new ArrayList(); readers.add(new InputStreamReader(geturl.openStream())); return readers.iterator(); } } - -class RvalsIterator implements Iterator, AutoCloseable -{ - private Iterator rvals; - - protected RvalsIterator(List responses) - { - this.rvals = responses.iterator(); - } - - @Override - public boolean hasNext() - { - return rvals.hasNext(); - } - - @Override - public Reader next() - { - Map val = (Map) rvals.next(); - - Object sval = null; - try - { - sval = val.get("2D"); - } catch (Exception x) - { - x.printStackTrace(); - } - if (sval == null) - { - System.err.println( - "DEVELOPER WARNING: Annotate3d didn't return a '2D' tag in its response. Consider checking output of server. Response was :" - + val.toString()); - - sval = ""; - } - return new StringReader(sval.toString()); - } - - @Override - public void remove() - { - throw new UnsupportedOperationException(); - } - - @Override - protected Object clone() throws CloneNotSupportedException - { - throw new UnsupportedOperationException(); - } - - @Override - public void close() - { - while (rvals.hasNext()) - { - rvals.next(); - } - } -} diff --git a/src/jalview/ext/so/SequenceOntology.java b/src/jalview/ext/so/SequenceOntology.java index 0d631e6..5a86fa1 100644 --- a/src/jalview/ext/so/SequenceOntology.java +++ b/src/jalview/ext/so/SequenceOntology.java @@ -82,10 +82,10 @@ public class SequenceOntology implements SequenceOntologyI */ public SequenceOntology() { - termsFound = new ArrayList(); - termsNotFound = new ArrayList(); - termsByDescription = new HashMap(); - termIsA = new HashMap>(); + termsFound = new ArrayList<>(); + termsNotFound = new ArrayList<>(); + termsByDescription = new HashMap<>(); + termIsA = new HashMap<>(); loadOntologyZipFile("so-xp-simple.obo"); } @@ -404,7 +404,7 @@ public class SequenceOntology implements SequenceOntologyI */ protected synchronized void findParents(Term childTerm) { - List result = new ArrayList(); + List result = new ArrayList<>(); for (Triple triple : ontology.getTriples(childTerm, null, isA)) { Term parent = triple.getObject(); diff --git a/src/jalview/fts/core/FTSRestRequest.java b/src/jalview/fts/core/FTSRestRequest.java index 2d9eeb6..52c48a1 100644 --- a/src/jalview/fts/core/FTSRestRequest.java +++ b/src/jalview/fts/core/FTSRestRequest.java @@ -24,6 +24,7 @@ package jalview.fts.core; import jalview.bin.Cache; import jalview.datamodel.SequenceI; import jalview.fts.api.FTSDataColumnI; +import jalview.gui.Preferences; import java.util.Collection; @@ -46,7 +47,7 @@ public class FTSRestRequest private boolean allowEmptySequence; private boolean allowUnpublishedEntries = Cache - .getDefault("ALLOW_UNPUBLISHED_PDB_QUERYING", false); + .getDefault(Preferences.ALLOW_UNPUBLISHED_PDB_QUERYING, false); private boolean facet; diff --git a/src/jalview/fts/service/pdb/PDBFTSRestClient.java b/src/jalview/fts/service/pdb/PDBFTSRestClient.java index cd3e5c9..87d640b 100644 --- a/src/jalview/fts/service/pdb/PDBFTSRestClient.java +++ b/src/jalview/fts/service/pdb/PDBFTSRestClient.java @@ -20,6 +20,8 @@ */ package jalview.fts.service.pdb; +import jalview.bin.ApplicationSingletonProvider; +import jalview.bin.ApplicationSingletonProvider.ApplicationSingletonI; import jalview.datamodel.SequenceI; import jalview.fts.api.FTSData; import jalview.fts.api.FTSDataColumnI; @@ -53,15 +55,19 @@ import com.sun.jersey.api.client.config.DefaultClientConfig; * * @author tcnofoegbu */ -public class PDBFTSRestClient extends FTSRestClient +public class PDBFTSRestClient extends FTSRestClient implements ApplicationSingletonI { - - private static FTSRestClientI instance = null; - public static final String PDB_SEARCH_ENDPOINT = "https://www.ebi.ac.uk/pdbe/search/pdb/select?"; - protected PDBFTSRestClient() + public static FTSRestClientI getInstance() + { + return (FTSRestClientI) ApplicationSingletonProvider + .getInstance(PDBFTSRestClient.class); + } + + private PDBFTSRestClient() { + // singleton -- use getInstance() } /** @@ -459,15 +465,6 @@ public static String parseJsonExceptionString(String jsonErrorResponse) return "/fts/pdb_data_columns.txt"; } - public static FTSRestClientI getInstance() - { - if (instance == null) - { - instance = new PDBFTSRestClient(); - } - return instance; - } - private Collection allDefaultDisplayedStructureDataColumns; public Collection getAllDefaultDisplayedStructureDataColumns() diff --git a/src/jalview/fts/service/uniprot/UniProtFTSRestClient.java b/src/jalview/fts/service/uniprot/UniProtFTSRestClient.java index 3f0b8a4..094052b 100644 --- a/src/jalview/fts/service/uniprot/UniProtFTSRestClient.java +++ b/src/jalview/fts/service/uniprot/UniProtFTSRestClient.java @@ -21,6 +21,8 @@ package jalview.fts.service.uniprot; +import jalview.bin.ApplicationSingletonProvider; +import jalview.bin.ApplicationSingletonProvider.ApplicationSingletonI; import jalview.bin.Cache; import jalview.fts.api.FTSData; import jalview.fts.api.FTSDataColumnI; @@ -28,6 +30,7 @@ import jalview.fts.api.FTSRestClientI; import jalview.fts.core.FTSRestClient; import jalview.fts.core.FTSRestRequest; import jalview.fts.core.FTSRestResponse; +import jalview.gui.Preferences; import jalview.util.MessageManager; import jalview.util.Platform; @@ -44,25 +47,31 @@ import com.sun.jersey.api.client.WebResource; import com.sun.jersey.api.client.config.DefaultClientConfig; public class UniProtFTSRestClient extends FTSRestClient + implements ApplicationSingletonI { - private static final String DEFAULT_UNIPROT_DOMAIN = "https://www.uniprot.org"; - static + public static FTSRestClientI getInstance() { - Platform.addJ2SDirectDatabaseCall(DEFAULT_UNIPROT_DOMAIN); + return (FTSRestClientI) ApplicationSingletonProvider + .getInstance(UniProtFTSRestClient.class); + } + + private UniProtFTSRestClient() + { + // singleton -- use getInstance() + + uniprotSearchEndpoint = Cache.getDefault(Preferences.UNIPROT_DOMAIN, + DEFAULT_UNIPROT_DOMAIN) + "/uniprot/"; } - private static FTSRestClientI instance = null; + private static final String DEFAULT_UNIPROT_DOMAIN = "https://www.uniprot.org"; public final String uniprotSearchEndpoint; - public UniProtFTSRestClient() + static { - super(); - uniprotSearchEndpoint = Cache.getDefault("UNIPROT_DOMAIN", - DEFAULT_UNIPROT_DOMAIN) + "/uniprot/"; + Platform.addJ2SDirectDatabaseCall(DEFAULT_UNIPROT_DOMAIN); } - @SuppressWarnings("unchecked") @Override public FTSRestResponse executeRequest(FTSRestRequest uniprotRestRequest) @@ -347,15 +356,6 @@ public class UniProtFTSRestClient extends FTSRestClient }; } - public static FTSRestClientI getInstance() - { - if (instance == null) - { - instance = new UniProtFTSRestClient(); - } - return instance; - } - @Override public String getColumnDataConfigFileName() { diff --git a/src/jalview/gui/APQHandlers.java b/src/jalview/gui/APQHandlers.java deleted file mode 100644 index 5ebd47f..0000000 --- a/src/jalview/gui/APQHandlers.java +++ /dev/null @@ -1,151 +0,0 @@ -package jalview.gui; - -import jalview.util.MessageManager; -import jalview.util.Platform; - -import java.awt.Desktop; -import java.awt.desktop.AboutEvent; -import java.awt.desktop.AboutHandler; -import java.awt.desktop.PreferencesEvent; -import java.awt.desktop.PreferencesHandler; -import java.awt.desktop.QuitEvent; -import java.awt.desktop.QuitHandler; -import java.awt.desktop.QuitResponse; -import java.awt.desktop.QuitStrategy; - -import javax.swing.JOptionPane; - -public class APQHandlers -{ - private static boolean setAPQHandlers = false; - - public APQHandlers() { - } - - protected static boolean setAPQHandlers(jalview.gui.Desktop jalviewDesktop) - { - // flagging this test to avoid unnecessary reflection - if (!setAPQHandlers) - { - // see if the Quit, About and Preferences handlers are available - Class desktopClass = Desktop.class; - Desktop hdesktop = Desktop.getDesktop(); - - try - { - Float specversion = Float.parseFloat( - System.getProperty("java.specification.version")); - - if (specversion >= 9) - { - if (Platform.isMac()) - { - if (desktopClass.getDeclaredMethod("setAboutHandler", - new Class[] - { AboutHandler.class }) != null) - { - - hdesktop.setAboutHandler(new AboutHandler() - { - @Override - public void handleAbout(AboutEvent e) - { - jalviewDesktop.aboutMenuItem_actionPerformed(null); - } - }); - - } - - if (desktopClass.getDeclaredMethod("setPreferencesHandler", - new Class[] - { PreferencesHandler.class }) != null) - { - - hdesktop.setPreferencesHandler( - new PreferencesHandler() - { - @Override - public void handlePreferences( - PreferencesEvent e) - { - jalviewDesktop.preferences_actionPerformed(null); - } - }); - - } - - if (desktopClass.getDeclaredMethod("setQuitHandler", - new Class[] - { QuitHandler.class }) != null) - { - - hdesktop.setQuitHandler(new QuitHandler() - { - @Override - public void handleQuitRequestWith( - QuitEvent e, QuitResponse r) - { - boolean confirmQuit = jalview.bin.Cache - .getDefault( - jalview.gui.Desktop.CONFIRM_KEYBOARD_QUIT, - true); - int n; - if (confirmQuit) - { - n = JOptionPane.showConfirmDialog(null, - MessageManager.getString("label.quit_jalview"), - MessageManager.getString("action.quit"), - JOptionPane.OK_CANCEL_OPTION, - JOptionPane.PLAIN_MESSAGE, null); - } - else - { - n = JOptionPane.OK_OPTION; - } - if (n == JOptionPane.OK_OPTION) - { - System.out.println("Shortcut Quit confirmed by user"); - jalviewDesktop.quit(); - r.performQuit(); // probably won't reach this line, but just - // in - // case - } - else - { - r.cancelQuit(); - System.out.println("Shortcut Quit cancelled by user"); - } - } - }); - hdesktop.setQuitStrategy( - QuitStrategy.CLOSE_ALL_WINDOWS); - - } - } - setAPQHandlers = true; - } - else - { - System.out.println( - "Not going to try setting APQ Handlers as java.spec.version is " - + specversion); - } - - } catch (Exception e) - { - System.out.println( - "Exception when looking for About, Preferences, Quit Handlers"); - // e.printStackTrace(); - } catch (Throwable t) - { - System.out.println( - "Throwable when looking for About, Preferences, Quit Handlers"); - // t.printStackTrace(); - } - - } - - return setAPQHandlers; - } - -} diff --git a/src/jalview/gui/AlignExportOptions.java b/src/jalview/gui/AlignExportOptions.java index 70601c9..3a8fb7c 100644 --- a/src/jalview/gui/AlignExportOptions.java +++ b/src/jalview/gui/AlignExportOptions.java @@ -96,7 +96,7 @@ public class AlignExportOptions extends JPanel this.settings = defaults; this.isComplexAlignFile = format.isComplexAlignFile(); init(viewport.hasHiddenRows(), viewport.hasHiddenColumns()); - dialog = JvOptionPane.newOptionDialog(Desktop.desktop); + dialog = JvOptionPane.newOptionDialog(Desktop.getDesktopPane()); } /** diff --git a/src/jalview/gui/AlignFrame.java b/src/jalview/gui/AlignFrame.java index 1b09868..bac06e9 100644 --- a/src/jalview/gui/AlignFrame.java +++ b/src/jalview/gui/AlignFrame.java @@ -28,10 +28,12 @@ import jalview.analysis.GeneticCodeI; import jalview.analysis.ParseProperties; import jalview.analysis.SequenceIdMatcher; import jalview.api.AlignExportSettingsI; +import jalview.api.AlignFrameI; import jalview.api.AlignViewControllerGuiI; import jalview.api.AlignViewControllerI; import jalview.api.AlignViewportI; import jalview.api.AlignmentViewPanel; +//from JalviewLite imports import jalview.api.FeatureRenderer; import jalview.api.FeatureSettingsControllerI; import jalview.api.SplitContainerI; import jalview.api.ViewStyleI; @@ -105,6 +107,7 @@ import jalview.ws.seqfetcher.DbSourceProxy; import java.awt.BorderLayout; import java.awt.Color; import java.awt.Component; +import java.awt.Dimension; import java.awt.Rectangle; import java.awt.Toolkit; import java.awt.datatransfer.Clipboard; @@ -162,7 +165,8 @@ import ext.vamsas.ServiceHandle; * @version $Revision$ */ @SuppressWarnings("serial") -public class AlignFrame extends GAlignFrame implements DropTargetListener, +public class AlignFrame extends GAlignFrame + implements AlignFrameI, DropTargetListener, IProgressIndicator, AlignViewControllerGuiI, ColourChangeListener { @@ -296,9 +300,6 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener, viewport = new AlignViewport(al, hiddenColumns, sequenceSetId, viewId); - alignPanel = new AlignmentPanel(this, viewport); - - addAlignmentPanel(alignPanel, true); init(); } @@ -318,8 +319,6 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener, { viewport.hideSequence(hiddenSeqs); } - alignPanel = new AlignmentPanel(this, viewport); - addAlignmentPanel(alignPanel, true); init(); } @@ -335,7 +334,6 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener, { viewport = ap.av; alignPanel = ap; - addAlignmentPanel(ap, false); init(); } @@ -345,11 +343,34 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener, */ void init() { -// setBackground(Color.white); // BH 2019 + boolean newPanel = (alignPanel == null); + viewport.setShowAutocalculatedAbove(isShowAutoCalculatedAbove()); + if (newPanel) + { + if (Platform.isJS()) + { + // need to set this up front if NOANNOTATION is + // used in conjunction with SHOWOVERVIEW. + + // I have not determined if this is appropriate for + // Jalview/Java, as it means we are setting this flag + // for all subsequent AlignFrames. For now, at least, + // I am setting it to be JalviewJS-only. + + boolean showAnnotation = Jalview.getInstance().getShowAnnotation(); + viewport.setShowAnnotation(showAnnotation); + } + alignPanel = new AlignmentPanel(this, viewport); + } + addAlignmentPanel(alignPanel, newPanel); + + // setBackground(Color.white); // BH 2019 if (!Jalview.isHeadlessMode()) { progressBar = new ProgressBar(this.statusPanel, this.statusBar); + statusPanel.setVisible(Jalview.getInstance().getShowStatus()); + alignFrameMenuBar.setVisible(Jalview.getInstance().getAllowMenuBar()); } avc = new jalview.controller.AlignViewController(this, viewport, @@ -364,7 +385,7 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener, // modifyPID.setEnabled(false); } - String sortby = jalview.bin.Cache.getDefault("SORT_ALIGNMENT", + String sortby = jalview.bin.Cache.getDefault(Preferences.SORT_ALIGNMENT, "No sort"); if (sortby.equals("Id")) @@ -376,9 +397,6 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener, sortPairwiseMenuItem_actionPerformed(null); } - this.alignPanel.av - .setShowAutocalculatedAbove(isShowAutoCalculatedAbove()); - setMenusFromViewport(viewport); buildSortByAnnotationScoresMenu(); calculateTree.addActionListener(new ActionListener() @@ -392,7 +410,7 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener, }); buildColourMenu(); - if (Desktop.desktop != null) + if (Desktop.getDesktopPane() != null) { this.setDropTarget(new java.awt.dnd.DropTarget(this, this)); if (!Platform.isJS()) @@ -407,7 +425,7 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener, wrapMenuItem_actionPerformed(null); } - if (jalview.bin.Cache.getDefault("SHOW_OVERVIEW", false)) + if (jalview.bin.Cache.getDefault(Preferences.SHOW_OVERVIEW, false)) { this.overviewMenuItem_actionPerformed(null); } @@ -551,7 +569,7 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener, switch (evt.getKeyCode()) { - case 27: // escape key + case KeyEvent.VK_ESCAPE: // escape key deselectAllSequenceMenuItem_actionPerformed(null); break; @@ -790,9 +808,12 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener, { ap.av.getAlignment().padGaps(); } - ap.av.updateConservation(ap); - ap.av.updateConsensus(ap); - ap.av.updateStrucConsensus(ap); + if (Jalview.getInstance().getStartCalculations()) + { + ap.av.updateConservation(ap); + ap.av.updateConsensus(ap); + ap.av.updateStrucConsensus(ap); + } } } @@ -815,14 +836,12 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener, private void addServiceListeners() { final java.beans.PropertyChangeListener thisListener; - Desktop.instance.addJalviewPropertyChangeListener("services", + Desktop.getInstance().addJalviewPropertyChangeListener("services", thisListener = new java.beans.PropertyChangeListener() { @Override public void propertyChange(PropertyChangeEvent evt) { - // // System.out.println("Discoverer property change."); - // if (evt.getPropertyName().equals("services")) { SwingUtilities.invokeLater(new Runnable() { @@ -846,7 +865,7 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener, javax.swing.event.InternalFrameEvent evt) { // System.out.println("deregistering discoverer listener"); - Desktop.instance.removeJalviewPropertyChangeListener("services", + Desktop.getInstance().removeJalviewPropertyChangeListener("services", thisListener); closeMenuItem_actionPerformed(true); } @@ -923,10 +942,8 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener, /* * Show/hide annotations only enabled if annotation panel is shown */ - showAllSeqAnnotations.setEnabled(annotationPanelMenuItem.getState()); - hideAllSeqAnnotations.setEnabled(annotationPanelMenuItem.getState()); - showAllAlAnnotations.setEnabled(annotationPanelMenuItem.getState()); - hideAllAlAnnotations.setEnabled(annotationPanelMenuItem.getState()); + syncAnnotationMenuItems(); + viewBoxesMenuItem.setSelected(av.getShowBoxes()); viewTextMenuItem.setSelected(av.getShowText()); showNonconservedMenuItem.setSelected(av.getShowUnconserved()); @@ -944,7 +961,7 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener, applyToAllGroups.setState(av.getColourAppliesToAllGroups()); showNpFeatsMenuitem.setSelected(av.isShowNPFeats()); showDbRefsMenuitem.setSelected(av.isShowDBRefs()); - autoCalculate.setSelected(av.autoCalculateConsensus); + autoCalculate.setSelected(av.getAutoCalculateConsensusAndConservation()); sortByTree.setSelected(av.sortByTree); listenToViewSelections.setSelected(av.followSelection); @@ -1027,7 +1044,7 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener, @Override public void addFromFile_actionPerformed(ActionEvent e) { - Desktop.instance.inputLocalFileMenuItem_actionPerformed(viewport); + Desktop.getInstance().inputLocalFileMenuItem_actionPerformed(viewport); } @Override @@ -1041,7 +1058,7 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener, // file is reloaded. if (FileFormat.Jalview.equals(currentFileFormat)) { - JInternalFrame[] frames = Desktop.desktop.getAllFrames(); + JInternalFrame[] frames = Desktop.getDesktopPane().getAllFrames(); for (int i = 0; i < frames.length; i++) { if (frames[i] instanceof AlignFrame && frames[i] != this @@ -1051,20 +1068,20 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener, try { frames[i].setSelected(true); - Desktop.instance.closeAssociatedWindows(); + Desktop.getInstance().closeAssociatedWindows(); } catch (java.beans.PropertyVetoException ex) { } } } - Desktop.instance.closeAssociatedWindows(); + Desktop.getInstance().closeAssociatedWindows(); FileLoader loader = new FileLoader(); DataSourceType protocol = fileName.startsWith("http:") ? DataSourceType.URL : DataSourceType.FILE; - loader.LoadFile(viewport, fileName, protocol, currentFileFormat); + loader.loadFile(viewport, fileName, protocol, currentFileFormat); } else { @@ -1080,12 +1097,12 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener, DataSourceType protocol = (fileName.startsWith("http:") ? DataSourceType.URL : DataSourceType.FILE); - newframe = loader.LoadFileWaitTillLoaded(fileName, protocol, + newframe = loader.loadFileWaitTillLoaded(fileName, protocol, currentFileFormat); } else { - newframe = loader.LoadFileWaitTillLoaded(fileObject, + newframe = loader.loadFileWaitTillLoaded(fileObject, DataSourceType.FILE, currentFileFormat); } @@ -1116,14 +1133,14 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener, @Override public void addFromText_actionPerformed(ActionEvent e) { - Desktop.instance + Desktop.getInstance() .inputTextboxMenuItem_actionPerformed(viewport.getAlignPanel()); } @Override public void addFromURL_actionPerformed(ActionEvent e) { - Desktop.instance.inputURLMenuItem_actionPerformed(viewport); + Desktop.getInstance().inputURLMenuItem_actionPerformed(viewport); } @Override @@ -1167,7 +1184,7 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener, // todo is this (2005) test now obsolete - value is never null? while (currentFileFormat == null) { - JvOptionPane.showInternalMessageDialog(Desktop.desktop, + JvOptionPane.showInternalMessageDialog(Desktop.getDesktopPane(), MessageManager .getString("label.select_file_format_before_saving"), MessageManager.getString("label.file_format_not_specified"), @@ -1289,6 +1306,7 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener, String tempFilePath = doBackup ? backupfiles.getTempFilePath() : file; PrintWriter out = new PrintWriter( new FileWriter(tempFilePath)); + out.print(output); out.close(); AlignFrame.this.setTitle(file); @@ -1929,16 +1947,17 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener, StringSelection ss = new StringSelection(output); + Desktop d = Desktop.getInstance(); try { - jalview.gui.Desktop.internalCopy = true; + d.internalCopy = true; // Its really worth setting the clipboard contents // to empty before setting the large StringSelection!! Toolkit.getDefaultToolkit().getSystemClipboard() .setContents(new StringSelection(""), null); Toolkit.getDefaultToolkit().getSystemClipboard().setContents(ss, - Desktop.instance); + Desktop.getInstance()); } catch (OutOfMemoryError er) { new OOMWarning("copying region", er); @@ -1958,7 +1977,7 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener, hiddenCutoff, hiddenOffset); } - Desktop.jalviewClipboard = new Object[] { seqs, + d.jalviewClipboard = new Object[] { seqs, viewport.getAlignment().getDataset(), hiddenColumns }; setStatus(MessageManager.formatMessage( "label.copied_sequences_to_clipboard", new Object[] @@ -2030,12 +2049,14 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener, boolean annotationAdded = false; AlignmentI alignment = null; - if (Desktop.jalviewClipboard != null) + Desktop d = Desktop.getInstance(); + + if (d.jalviewClipboard != null) { // The clipboard was filled from within Jalview, we must use the // sequences // And dataset from the copied alignment - SequenceI[] newseq = (SequenceI[]) Desktop.jalviewClipboard[0]; + SequenceI[] newseq = (SequenceI[]) d.jalviewClipboard[0]; // be doubly sure that we create *new* sequence objects. sequences = new SequenceI[newseq.length]; for (int i = 0; i < newseq.length; i++) @@ -2060,10 +2081,10 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener, if (newAlignment) { - if (Desktop.jalviewClipboard != null) + if (d.jalviewClipboard != null) { // dataset is inherited - alignment.setDataset((Alignment) Desktop.jalviewClipboard[1]); + alignment.setDataset((Alignment) d.jalviewClipboard[1]); } else { @@ -2079,8 +2100,8 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener, alignment = viewport.getAlignment(); alwidth = alignment.getWidth() + 1; // decide if we need to import sequences from an existing dataset - boolean importDs = Desktop.jalviewClipboard != null - && Desktop.jalviewClipboard[1] != alignment.getDataset(); + boolean importDs = d.jalviewClipboard != null + && d.jalviewClipboard[1] != alignment.getDataset(); // importDs==true instructs us to copy over new dataset sequences from // an existing alignment Vector newDs = (importDs) ? new Vector<>() : null; // used to @@ -2157,7 +2178,7 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener, newGraphGroups.add(q, null); } newGraphGroups.set(newann.graphGroup, - Integer.valueOf(++fgroup)); + new Integer(++fgroup)); } newann.graphGroup = newGraphGroups.get(newann.graphGroup) .intValue(); @@ -2204,7 +2225,7 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener, newGraphGroups.add(q, null); } newGraphGroups.set(newann.graphGroup, - Integer.valueOf(++fgroup)); + new Integer(++fgroup)); } newann.graphGroup = newGraphGroups.get(newann.graphGroup) .intValue(); @@ -2282,10 +2303,9 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener, DEFAULT_HEIGHT); String newtitle = new String("Copied sequences"); - if (Desktop.jalviewClipboard != null - && Desktop.jalviewClipboard[2] != null) + if (d.jalviewClipboard != null && d.jalviewClipboard[2] != null) { - HiddenColumns hc = (HiddenColumns) Desktop.jalviewClipboard[2]; + HiddenColumns hc = (HiddenColumns) d.jalviewClipboard[2]; af.viewport.setHiddenColumns(hc); } @@ -2338,10 +2358,11 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener, DEFAULT_HEIGHT); String newtitle = new String("Flanking alignment"); - if (Desktop.jalviewClipboard != null - && Desktop.jalviewClipboard[2] != null) + Desktop d = Desktop.getInstance(); + + if (d.jalviewClipboard != null && d.jalviewClipboard[2] != null) { - HiddenColumns hc = (HiddenColumns) Desktop.jalviewClipboard[2]; + HiddenColumns hc = (HiddenColumns) d.jalviewClipboard[2]; af.viewport.setHiddenColumns(hc); } @@ -2438,7 +2459,7 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener, + 1) == viewport.getAlignment().getWidth()) ? true : false; if (wholeHeight && wholeWidth) { - JvOptionPane dialog = JvOptionPane.newOptionDialog(Desktop.desktop); + JvOptionPane dialog = JvOptionPane.newOptionDialog(Desktop.getDesktopPane()); dialog.setResponseHandler(0, okAction); // 0 = OK_OPTION Object[] options = new Object[] { MessageManager.getString("action.ok"), MessageManager.getString("action.cancel") }; @@ -2912,7 +2933,7 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener, @Override public void gatherViews_actionPerformed(ActionEvent e) { - Desktop.instance.gatherViews(this); + Desktop.getInstance().gatherViews(this); } /** @@ -3290,13 +3311,20 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener, { final boolean setVisible = annotationPanelMenuItem.isSelected(); viewport.setShowAnnotation(setVisible); - this.showAllSeqAnnotations.setEnabled(setVisible); - this.hideAllSeqAnnotations.setEnabled(setVisible); - this.showAllAlAnnotations.setEnabled(setVisible); - this.hideAllAlAnnotations.setEnabled(setVisible); + syncAnnotationMenuItems(); alignPanel.updateLayout(); } + private void syncAnnotationMenuItems() + { + final boolean setVisible = annotationPanelMenuItem.isSelected(); + showAllSeqAnnotations.setEnabled(setVisible); + hideAllSeqAnnotations.setEnabled(setVisible); + showAllAlAnnotations.setEnabled(setVisible); + hideAllAlAnnotations.setEnabled(setVisible); + } + + @Override public void alignmentProperties() { @@ -3357,12 +3385,38 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener, } JInternalFrame frame = new JInternalFrame(); - final OverviewPanel overview = new OverviewPanel(alignPanel); + + // BH 2019.07.26 we allow for an embedded + // undecorated overview with defined size + frame.setName(Jalview.getAppID("overview")); + // + Dimension dim = (Dimension) Platform.getEmbeddedAttribute(frame, + Platform.EMBEDDED_DIM); + if (dim != null && dim.width == 0) + { + dim = null; // hidden, not embedded + } + + OverviewPanel overview = new OverviewPanel(alignPanel, dim); + frame.setContentPane(overview); + if (dim == null) + { + dim = new Dimension(); + // was frame.getSize(), but that is 0,0 at this point; + } + else + { + // we are imbedding, and so we have an undecorated frame + // and we can set the the frame dimensions accordingly. + } + // allowing for unresizable option using, style="resize:none" + boolean resizable = (Platform.getEmbeddedAttribute(frame, + "resize") != "none"); Desktop.addInternalFrame(frame, MessageManager .formatMessage("label.overview_params", new Object[] - { this.getTitle() }), true, frame.getWidth(), frame.getHeight(), - true, true); + { this.getTitle() }), true, dim.width, dim.height, resizable, + true); frame.pack(); frame.setLayer(JLayeredPane.PALETTE_LAYER); frame.addInternalFrameListener( @@ -3642,8 +3696,8 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener, @Override public void autoCalculate_actionPerformed(ActionEvent e) { - viewport.autoCalculateConsensus = autoCalculate.isSelected(); - if (viewport.autoCalculateConsensus) + viewport.setAutoCalculateConsensusAndConservation(autoCalculate.isSelected()); + if (viewport.getAutoCalculateConsensusAndConservation()) { viewport.firePropertyChange("alignment", null, viewport.getAlignment().getSequences()); @@ -3689,7 +3743,7 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener, { if (_s.getLength() < sg.getEndRes()) { - JvOptionPane.showMessageDialog(Desktop.desktop, + JvOptionPane.showMessageDialog(Desktop.getDesktopPane(), MessageManager.getString( "label.selected_region_to_tree_may_only_contain_residues_or_gaps"), MessageManager.getString( @@ -4011,7 +4065,7 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener, viewport.setCurrentTree(showNewickTree(fin, filePath).getTree()); } catch (Exception ex) { - JvOptionPane.showMessageDialog(Desktop.desktop, ex.getMessage(), + JvOptionPane.showMessageDialog(Desktop.getDesktopPane(), ex.getMessage(), MessageManager .getString("label.problem_reading_tree_file"), JvOptionPane.WARNING_MESSAGE); @@ -4019,7 +4073,7 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener, } if (fin != null && fin.hasWarningMessage()) { - JvOptionPane.showMessageDialog(Desktop.desktop, + JvOptionPane.showMessageDialog(Desktop.getDesktopPane(), fin.getWarningMessage(), MessageManager.getString( "label.possible_problem_with_tree_file"), @@ -4147,9 +4201,11 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener, final JMenu dismenu = new JMenu("Protein Disorder"); // JAL-940 - only show secondary structure prediction services from // the legacy server + Hashtable> services = Discoverer + .getInstance().getServices(); if (// Cache.getDefault("SHOW_JWS1_SERVICES", true) - // && - Discoverer.services != null && (Discoverer.services.size() > 0)) + // && + services != null && (services.size() > 0)) { // TODO: refactor to allow list of AbstractName/Handler bindings to // be @@ -4157,8 +4213,7 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener, // No MSAWS used any more: // Vector msaws = null; // (Vector) // Discoverer.services.get("MsaWS"); - Vector secstrpr = Discoverer.services - .get("SecStrPred"); + Vector secstrpr = services.get("SecStrPred"); if (secstrpr != null) { // Add any secondary structure prediction services @@ -4209,10 +4264,10 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener, webService.add(me.webServiceNoServices); } // TODO: move into separate menu builder class. - boolean new_sspred = false; + // boolean new_sspred = false; if (Cache.getDefault("SHOW_JWS2_SERVICES", true)) { - Jws2Discoverer jws2servs = Jws2Discoverer.getDiscoverer(); + Jws2Discoverer jws2servs = Jws2Discoverer.getInstance(); if (jws2servs != null) { if (jws2servs.hasServices()) @@ -4399,7 +4454,7 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener, final String errorTitle = MessageManager .getString("label.implementation_error") + MessageManager.getString("label.translation_failed"); - JvOptionPane.showMessageDialog(Desktop.desktop, msg, errorTitle, + JvOptionPane.showMessageDialog(Desktop.getDesktopPane(), msg, errorTitle, JvOptionPane.ERROR_MESSAGE); return; } @@ -4409,7 +4464,7 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener, "label.select_at_least_three_bases_in_at_least_one_sequence_to_cDNA_translation"); final String errorTitle = MessageManager .getString("label.translation_failed"); - JvOptionPane.showMessageDialog(Desktop.desktop, msg, errorTitle, + JvOptionPane.showMessageDialog(Desktop.getDesktopPane(), msg, errorTitle, JvOptionPane.WARNING_MESSAGE); } else @@ -4423,7 +4478,7 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener, if (Cache.getDefault(Preferences.ENABLE_SPLIT_FRAME, true)) { final SequenceI[] seqs = viewport.getSelectionAsNewSequence(); - viewport.openSplitFrame(af, new Alignment(seqs)); + AlignViewport.openSplitFrame(this, af, new Alignment(seqs)); } else { @@ -4456,7 +4511,7 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener, { // BH 2018 return avc.parseFeaturesFile(file, sourceType, - Cache.getDefault("RELAXEDSEQIDMATCHING", false)); + Cache.getDefault(Preferences.RELAXEDSEQIDMATCHING, false)); } @@ -4470,6 +4525,7 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener, { viewport.setShowSequenceFeatures(true); showSeqFeatures.setSelected(true); + alignPanel.getAlignment().resetColors(); } } @@ -4599,7 +4655,7 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener, if (filesmatched.size() > 0) { boolean autoAssociate = Cache - .getDefault("AUTOASSOCIATE_PDBANDSEQS", false); + .getDefault(Preferences.AUTOASSOCIATE_PDBANDSEQS, false); if (!autoAssociate) { String msg = MessageManager.formatMessage( @@ -4622,10 +4678,9 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener, // associating PDB files which have no IDs. for (SequenceI toassoc : (SequenceI[]) fm[2]) { - PDBEntry pe = new AssociatePdbFileWithSeq() + PDBEntry pe = AssociatePdbFileWithSeq .associatePdbWithSeq(fm[0].toString(), - (DataSourceType) fm[1], toassoc, false, - Desktop.instance); + (DataSourceType) fm[1], toassoc, false); if (pe != null) { System.err.println("Associated file : " @@ -4736,7 +4791,7 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener, { // some problem - if no warning its probable that the ID matching // process didn't work - JvOptionPane.showMessageDialog(Desktop.desktop, + JvOptionPane.showMessageDialog(Desktop.getDesktopPane(), tcf.getWarningMessage() == null ? MessageManager.getString( "label.check_file_matches_sequence_ids_alignment") @@ -4795,17 +4850,13 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener, } else { - new FileLoader().LoadFile(viewport, file, sourceType, format); + new FileLoader().loadFile(viewport, file, sourceType, format); } } } if (isAnnotation) { - - alignPanel.adjustAnnotationHeight(); - viewport.updateSequenceIdColours(); - buildSortByAnnotationScoresMenu(); - alignPanel.paintAlignment(true, true); + updateForAnnotations(); } } catch (Exception ex) { @@ -4829,11 +4880,23 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener, + (format != null ? "(parsing as '" + format + "' file)" : ""), - oom, Desktop.desktop); + oom, Desktop.getDesktopPane()); } } /** + * Do all updates necessary after an annotation file such as jnet. Also called + * from Jalview.loadAppletParams for "annotations", "jnetFile" + */ + public void updateForAnnotations() + { + alignPanel.adjustAnnotationHeight(); + viewport.updateSequenceIdColours(); + buildSortByAnnotationScoresMenu(); + alignPanel.paintAlignment(true, true); + } + + /** * Method invoked by the ChangeListener on the tabbed pane, in other words * when a different tabbed pane is selected by the user or programmatically. */ @@ -4916,6 +4979,32 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener, } /** + * Change the display state for the given feature groups -- Added by BH from + * JalviewLite + * + * @param groups + * list of group strings + * @param state + * visible or invisible + */ + public void setFeatureGroupState(String[] groups, boolean state) + { + jalview.api.FeatureRenderer fr = null; + viewport.setShowSequenceFeatures(true); + if (alignPanel != null + && (fr = alignPanel.getFeatureRenderer()) != null) + { + + fr.setGroupVisibility(Arrays.asList(groups), state); + alignPanel.getSeqPanel().seqCanvas.repaint(); + if (alignPanel.overviewPanel != null) + { + alignPanel.overviewPanel.updateOverviewImage(); + } + } + } + + /** * Open the dialog for regex description parsing. */ @Override @@ -5059,14 +5148,13 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener, @Override public void run() { - final jalview.ws.SequenceFetcher sf = jalview.gui.SequenceFetcher - .getSequenceFetcherSingleton(); javax.swing.SwingUtilities.invokeLater(new Runnable() { @Override public void run() { - String[] dbclasses = sf.getNonAlignmentSources(); + String[] dbclasses = jalview.ws.SequenceFetcher.getInstance() + .getNonAlignmentSources(); List otherdb; JMenu dfetch = new JMenu(); JMenu ifetch = new JMenu(); @@ -5076,7 +5164,8 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener, int dbi = 0; for (String dbclass : dbclasses) { - otherdb = sf.getSourceProxy(dbclass); + otherdb = jalview.ws.SequenceFetcher.getInstance() + .getSourceProxy(dbclass); // add a single entry for this class, or submenu allowing 'fetch // all' or pick one if (otherdb == null || otherdb.size() < 1) @@ -5089,9 +5178,9 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener, } if (otherdb.size() == 1) { - final DbSourceProxy[] dassource = otherdb - .toArray(new DbSourceProxy[0]); DbSourceProxy src = otherdb.get(0); + DbSourceProxy[] dassource = new DbSourceProxy[] { + src }; fetchr = new JMenuItem(src.getDbSource()); fetchr.addActionListener(new ActionListener() { @@ -5638,7 +5727,7 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener, } catch (Exception ex) { System.err.println((ex.toString())); - JvOptionPane.showInternalMessageDialog(Desktop.desktop, + JvOptionPane.showInternalMessageDialog(Desktop.getDesktopPane(), MessageManager.getString("label.couldnt_run_groovy_script"), MessageManager.getString("label.groovy_support_failed"), JvOptionPane.ERROR_MESSAGE); @@ -5749,6 +5838,67 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener, } + /** + * BH 2019 from JalviewLite + * + * get sequence feature groups that are hidden or shown + * + * @param visible + * true is visible + * @return list + */ + public String[] getFeatureGroupsOfState(boolean visible) + { + jalview.api.FeatureRenderer fr = null; + if (alignPanel != null + && (fr = alignPanel + .getFeatureRenderer()) != null) + { + List gps = fr.getGroups(visible); + String[] _gps = gps.toArray(new String[gps.size()]); + return _gps; + } + return null; + } + + public void scrollTo(int row, int column) + { + alignPanel.getSeqPanel().scrollTo(row, column); + } + + public void scrollToRow(int row) + { + alignPanel.getSeqPanel().scrollToRow(row); + } + + public void scrollToColumn(int column) + { + alignPanel.getSeqPanel().scrollToColumn(column); + } + + /** + * + * @return list of feature groups on the view + */ + public String[] getFeatureGroups() + { + jalview.api.FeatureRenderer fr = null; + if (alignPanel != null + && (fr = alignPanel.getFeatureRenderer()) != null) + { + List gps = fr.getFeatureGroups(); + String[] _gps = gps.toArray(new String[gps.size()]); + return _gps; + } + return null; + } + + public void select(SequenceGroup sel, ColumnSelection csel, + HiddenColumns hidden) + { + alignPanel.getSeqPanel().selection(sel, csel, hidden, null); + } + } class PrintThread extends Thread @@ -5787,4 +5937,5 @@ class PrintThread extends Thread } } } + } diff --git a/src/jalview/gui/AlignViewport.java b/src/jalview/gui/AlignViewport.java index 7d01222..fb3ec3a 100644 --- a/src/jalview/gui/AlignViewport.java +++ b/src/jalview/gui/AlignViewport.java @@ -206,24 +206,26 @@ public class AlignViewport extends AlignmentViewport */ private void applyViewProperties() { - antiAlias = Cache.getDefault("ANTI_ALIAS", false); - - viewStyle.setShowJVSuffix(Cache.getDefault("SHOW_JVSUFFIX", true)); - setShowAnnotation(Cache.getDefault("SHOW_ANNOTATIONS", true)); - - setRightAlignIds(Cache.getDefault("RIGHT_ALIGN_IDS", false)); - setCentreColumnLabels(Cache.getDefault("CENTRE_COLUMN_LABELS", false)); - autoCalculateConsensus = Cache.getDefault("AUTO_CALC_CONSENSUS", true); - - setPadGaps(Cache.getDefault("PAD_GAPS", true)); - setShowNPFeats(Cache.getDefault("SHOW_NPFEATS_TOOLTIP", true)); - setShowDBRefs(Cache.getDefault("SHOW_DBREFS_TOOLTIP", true)); - viewStyle.setSeqNameItalics(Cache.getDefault("ID_ITALICS", true)); - viewStyle.setWrapAlignment(Cache.getDefault("WRAP_ALIGNMENT", false)); + antiAlias = Cache.getDefault(Preferences.ANTI_ALIAS, false); + + viewStyle.setShowJVSuffix( + Cache.getDefault(Preferences.SHOW_JVSUFFIX, true)); + setShowAnnotation(Cache.getDefault(Preferences.SHOW_ANNOTATIONS, true)); + + setRightAlignIds(Cache.getDefault(Preferences.RIGHT_ALIGN_IDS, false)); + setCentreColumnLabels(Cache.getDefault(Preferences.CENTRE_COLUMN_LABELS, false)); + autoCalculateConsensusAndConservation = Cache.getDefault(Preferences.AUTO_CALC_CONSENSUS, true); + + setPadGaps(Cache.getDefault(Preferences.PAD_GAPS, true)); + setShowNPFeats(Cache.getDefault(Preferences.SHOW_NPFEATS_TOOLTIP, true)); + setShowDBRefs(Cache.getDefault(Preferences.SHOW_DBREFS_TOOLTIP, true)); + viewStyle.setSeqNameItalics(Cache.getDefault(Preferences.ID_ITALICS, true)); + viewStyle.setWrapAlignment( + Cache.getDefault(Preferences.WRAP_ALIGNMENT, false)); viewStyle.setShowUnconserved( - Cache.getDefault("SHOW_UNCONSERVED", false)); - sortByTree = Cache.getDefault("SORT_BY_TREE", false); - followSelection = Cache.getDefault("FOLLOW_SELECTIONS", true); + Cache.getDefault(Preferences.SHOW_UNCONSERVED, false)); + sortByTree = Cache.getDefault(Preferences.SORT_BY_TREE, false); + followSelection = Cache.getDefault(Preferences.FOLLOW_SELECTIONS, true); sortAnnotationsBy = SequenceAnnotationOrder .valueOf(Cache.getDefault(Preferences.SORT_ANNOTATIONS, SequenceAnnotationOrder.NONE.name())); @@ -237,9 +239,10 @@ public class AlignViewport extends AlignmentViewport { applyViewProperties(); - String fontName = Cache.getDefault("FONT_NAME", "SansSerif"); - String fontStyle = Cache.getDefault("FONT_STYLE", Font.PLAIN + ""); - String fontSize = Cache.getDefault("FONT_SIZE", "10"); + String fontName = Cache.getDefault(Preferences.FONT_NAME, "SansSerif"); + String fontStyle = Cache.getDefault(Preferences.FONT_STYLE, + Font.PLAIN + ""); + String fontSize = Cache.getDefault(Preferences.FONT_SIZE, "10"); int style = 0; @@ -255,7 +258,8 @@ public class AlignViewport extends AlignmentViewport setFont(new Font(fontName, style, Integer.parseInt(fontSize)), true); alignment - .setGapCharacter(Cache.getDefault("GAP_SYMBOL", "-").charAt(0)); + .setGapCharacter(Cache.getDefault(Preferences.GAP_SYMBOL, "-") + .charAt(0)); // We must set conservation and consensus before setting colour, // as Blosum and Clustal require this to be done @@ -263,18 +267,22 @@ public class AlignViewport extends AlignmentViewport { if (!alignment.isNucleotide()) { - showConservation = Cache.getDefault("SHOW_CONSERVATION", true); - showQuality = Cache.getDefault("SHOW_QUALITY", true); - showGroupConservation = Cache.getDefault("SHOW_GROUP_CONSERVATION", - false); + showConservation = Cache.getDefault(Preferences.SHOW_CONSERVATION, + true); + showQuality = Cache.getDefault(Preferences.SHOW_QUALITY, true); + showGroupConservation = Cache + .getDefault(Preferences.SHOW_GROUP_CONSERVATION, false); } - showConsensusHistogram = Cache.getDefault("SHOW_CONSENSUS_HISTOGRAM", - true); - showSequenceLogo = Cache.getDefault("SHOW_CONSENSUS_LOGO", false); - normaliseSequenceLogo = Cache.getDefault("NORMALISE_CONSENSUS_LOGO", + showConsensusHistogram = Cache + .getDefault(Preferences.SHOW_CONSENSUS_HISTOGRAM, true); + showSequenceLogo = Cache.getDefault(Preferences.SHOW_CONSENSUS_LOGO, false); - showGroupConsensus = Cache.getDefault("SHOW_GROUP_CONSENSUS", false); - showConsensus = Cache.getDefault("SHOW_IDENTITY", true); + + normaliseSequenceLogo = Cache + .getDefault(Preferences.NORMALISE_CONSENSUS_LOGO, false); + showGroupConsensus = Cache + .getDefault(Preferences.SHOW_GROUP_CONSENSUS, false); + showConsensus = Cache.getDefault(Preferences.SHOW_IDENTITY, true); showOccupancy = Cache.getDefault(Preferences.SHOW_OCCUPANCY, true); } @@ -289,8 +297,8 @@ public class AlignViewport extends AlignmentViewport schemeName = Cache.getDefault(Preferences.DEFAULT_COLOUR, ResidueColourScheme.NONE); } - ColourSchemeI colourScheme = ColourSchemeProperty - .getColourScheme(this, alignment, schemeName); + ColourSchemeI colourScheme = ColourSchemeProperty.getColourScheme(this, + alignment, schemeName); residueShading = new ResidueShader(colourScheme); if (colourScheme instanceof UserColourScheme) @@ -383,9 +391,8 @@ public class AlignViewport extends AlignmentViewport */ if (align != null) { - StructureSelectionManager ssm = StructureSelectionManager - .getStructureSelectionManager(Desktop.instance); - ssm.registerMappings(align.getCodonFrames()); + Desktop.getStructureSelectionManager() + .registerMappings(align.getCodonFrames()); } /* @@ -405,8 +412,8 @@ public class AlignViewport extends AlignmentViewport List mappings = al.getCodonFrames(); if (mappings != null) { - StructureSelectionManager ssm = StructureSelectionManager - .getStructureSelectionManager(Desktop.instance); + StructureSelectionManager ssm = Desktop + .getStructureSelectionManager(); for (AlignedCodonFrame acf : mappings) { if (noReferencesTo(acf)) @@ -531,12 +538,10 @@ public class AlignViewport extends AlignmentViewport @Override public void sendSelection() { - jalview.structure.StructureSelectionManager - .getStructureSelectionManager(Desktop.instance) - .sendSelection(new SequenceGroup(getSelectionGroup()), - new ColumnSelection(getColumnSelection()), - new HiddenColumns(getAlignment().getHiddenColumns()), - this); + Desktop.getStructureSelectionManager().sendSelection( + new SequenceGroup(getSelectionGroup()), + new ColumnSelection(getColumnSelection()), + new HiddenColumns(getAlignment().getHiddenColumns()), this); } /** @@ -577,8 +582,7 @@ public class AlignViewport extends AlignmentViewport @Override public StructureSelectionManager getStructureSelectionManager() { - return StructureSelectionManager - .getStructureSelectionManager(Desktop.instance); + return Desktop.getStructureSelectionManager(); } @Override @@ -747,6 +751,12 @@ public class AlignViewport extends AlignmentViewport firePropertyChange("alignment", null, getAlignment().getSequences()); } + public final static int NO_SPLIT = 0; + + public final static int SPLIT_FRAME = 1; + + public final static int NEW_WINDOW = 2; + /** * Show a dialog with the option to open and link (cDNA <-> protein) as a new * alignment, either as a standalone alignment or in a split frame. Returns @@ -763,54 +773,62 @@ public class AlignViewport extends AlignmentViewport MessageManager.getString("label.new_window"), }; final String question = JvSwingUtils.wrapTooltip(true, MessageManager.getString("label.open_split_window?")); - final AlignViewport us = this; - + /* * options No, Split Window, New Window correspond to * dialog responses 0, 1, 2 (even though JOptionPane shows them * in reverse order) */ - JvOptionPane dialog = JvOptionPane.newOptionDialog(Desktop.desktop) - .setResponseHandler(0, new Runnable() + JvOptionPane dialog = JvOptionPane + .newOptionDialog(Desktop.getDesktopPane()) + .setResponseHandler(NO_SPLIT, new Runnable() { @Override public void run() { - addDataToAlignment(al); + addDataToAlignment(al); } - }).setResponseHandler(1, new Runnable() + }).setResponseHandler(SPLIT_FRAME, new Runnable() { @Override public void run() { - us.openLinkedAlignmentAs(al, title, true); + openLinkedAlignmentAs(getAlignPanel().alignFrame, + new Alignment(getAlignment()), al, title, + SPLIT_FRAME); } - }).setResponseHandler(2, new Runnable() + }).setResponseHandler(NEW_WINDOW, new Runnable() { @Override public void run() { - us.openLinkedAlignmentAs(al, title, false); + openLinkedAlignmentAs(null, getAlignment(), al, title, + NEW_WINDOW); } }); - dialog.showDialog(question, + dialog.showDialog(question, MessageManager.getString("label.open_split_window"), JvOptionPane.DEFAULT_OPTION, JvOptionPane.PLAIN_MESSAGE, null, options, options[0]); } - protected void openLinkedAlignmentAs(AlignmentI al, String title, - boolean newWindowOrSplitPane) - { + /** + * Open a split frame or a new window + * + * @param al + * @param title + * @param mode + * SPLIT_FRAME or NEW_WINDOW + */ + public static void openLinkedAlignmentAs(AlignFrame thisFrame, + AlignmentI thisAlignment, AlignmentI al, String title, int mode) + { /* * Identify protein and dna alignments. Make a copy of this one if opening * in a new split pane. */ - AlignmentI thisAlignment = newWindowOrSplitPane - ? new Alignment(getAlignment()) - : getAlignment(); AlignmentI protein = al.isNucleotide() ? thisAlignment : al; - final AlignmentI cdna = al.isNucleotide() ? al : thisAlignment; + AlignmentI cdna = al.isNucleotide() ? al : thisAlignment; /* * Map sequences. At least one should get mapped as we have already passed @@ -839,7 +857,7 @@ public class AlignViewport extends AlignmentViewport // alignFrame.setFileName(file, format); // } - if (!newWindowOrSplitPane) + if (mode == NEW_WINDOW) { Desktop.addInternalFrame(newAlignFrame, title, AlignFrame.DEFAULT_WIDTH, AlignFrame.DEFAULT_HEIGHT); @@ -847,16 +865,16 @@ public class AlignViewport extends AlignmentViewport try { - newAlignFrame.setMaximum( - jalview.bin.Cache.getDefault("SHOW_FULLSCREEN", false)); + newAlignFrame.setMaximum(jalview.bin.Cache + .getDefault(Preferences.SHOW_FULLSCREEN, false)); } catch (java.beans.PropertyVetoException ex) { } - if (newWindowOrSplitPane) + if (mode == SPLIT_FRAME) { al.alignAs(thisAlignment); - protein = openSplitFrame(newAlignFrame, thisAlignment); + openSplitFrame(thisFrame, newAlignFrame, thisAlignment); } } @@ -870,8 +888,8 @@ public class AlignViewport extends AlignmentViewport * cdna/protein complement alignment to show in the other split half * @return the protein alignment in the split frame */ - protected AlignmentI openSplitFrame(AlignFrame newAlignFrame, - AlignmentI complement) + static protected AlignmentI openSplitFrame(AlignFrame thisFrame, + AlignFrame newAlignFrame, AlignmentI complement) { /* * Make a new frame with a copy of the alignment we are adding to. If this @@ -880,7 +898,7 @@ public class AlignViewport extends AlignmentViewport */ AlignFrame copyMe = new AlignFrame(complement, AlignFrame.DEFAULT_WIDTH, AlignFrame.DEFAULT_HEIGHT); - copyMe.setTitle(getAlignPanel().alignFrame.getTitle()); + copyMe.setTitle(thisFrame.getTitle()); AlignmentI al = newAlignFrame.viewport.getAlignment(); final AlignFrame proteinFrame = al.isNucleotide() ? copyMe diff --git a/src/jalview/gui/AlignmentPanel.java b/src/jalview/gui/AlignmentPanel.java index 9cb690f..b636fa7 100644 --- a/src/jalview/gui/AlignmentPanel.java +++ b/src/jalview/gui/AlignmentPanel.java @@ -23,6 +23,7 @@ package jalview.gui; import jalview.analysis.AnnotationSorter; import jalview.api.AlignViewportI; import jalview.api.AlignmentViewPanel; +import jalview.api.SequenceRenderer; import jalview.bin.Cache; import jalview.bin.Jalview; import jalview.datamodel.AlignmentI; @@ -55,6 +56,7 @@ import java.awt.event.AdjustmentEvent; import java.awt.event.AdjustmentListener; import java.awt.event.ComponentAdapter; import java.awt.event.ComponentEvent; +import java.awt.image.BufferedImage; import java.awt.print.PageFormat; import java.awt.print.Printable; import java.awt.print.PrinterException; @@ -68,7 +70,14 @@ import java.util.List; import javax.swing.SwingUtilities; /** - * DOCUMENT ME! + * The main panel of an AlignFrame, containing holders for the IdPanel, + * SeqPanel, AnnotationLabels (a JPanel), and AnnotationPanel. + * + * Additional holders contain an IdPanelWidthAdjuster space above the idPanel, + * AnnotationScroller (JScrollPane for AnnotationPanel), and vertical and + * horizontal scrollbars. + * + * * * @author $author$ * @version $Revision: 1.161 $ @@ -117,7 +126,8 @@ public class AlignmentPanel extends GAlignmentPanel implements */ public AlignmentPanel(AlignFrame af, final AlignViewport av) { -// setBackground(Color.white); // BH 2019 + setBackground(Color.white); // BH 2019 + setOpaque(true); alignFrame = af; this.av = av; setSeqPanel(new SeqPanel(av, this)); @@ -134,7 +144,11 @@ public class AlignmentPanel extends GAlignmentPanel implements annotationScroller.setViewportView(getAnnotationPanel()); annotationSpaceFillerHolder.add(getAlabels(), BorderLayout.CENTER); - + if (!av.isShowAnnotation()) + { + annotationScroller.setVisible(false); + annotationSpaceFillerHolder.setVisible(false); + } scalePanelHolder.add(getScalePanel(), BorderLayout.CENTER); seqPanelHolder.add(getSeqPanel(), BorderLayout.CENTER); @@ -578,7 +592,7 @@ public class AlignmentPanel extends GAlignmentPanel implements */ public void updateLayout() { - fontChanged(); + fontChanged(); // fires repaint setAnnotationVisible(av.isShowAnnotation()); boolean wrap = av.getWrapAlignment(); ViewportRanges ranges = av.getRanges(); @@ -831,6 +845,7 @@ public class AlignmentPanel extends GAlignmentPanel implements if (overviewPanel != null) { + getAlignment().resetColors(); overviewPanel.updateOverviewImage(); } } @@ -845,6 +860,7 @@ public class AlignmentPanel extends GAlignmentPanel implements @Override public void paintComponent(Graphics g) { + invalidate(); // needed so that the id width adjuster works correctly Dimension d = getIdPanel().getIdCanvas().getPreferredSize(); @@ -1148,13 +1164,13 @@ public class AlignmentPanel extends GAlignmentPanel implements public int getVisibleIdWidth(boolean onscreen) { // see if rendering offscreen - check preferences and calc width accordingly - if (!onscreen && Cache.getDefault("FIGURE_AUTOIDWIDTH", false)) + if (!onscreen && Cache.getDefault(Preferences.FIGURE_AUTOIDWIDTH, false)) { return calculateIdWidth(-1).width + 4; } Integer idwidth = null; if (onscreen || (idwidth = Cache - .getIntegerProperty("FIGURE_FIXEDIDWIDTH")) == null) + .getIntegerProperty(Preferences.FIGURE_FIXEDIDWIDTH)) == null) { int w = getIdPanel().getWidth(); return (w > 0 ? w : calculateIdWidth().width + 4); @@ -1376,8 +1392,7 @@ public class AlignmentPanel extends GAlignmentPanel implements { int seqPanelWidth = getSeqPanel().seqCanvas.getWidth(); - if (System.getProperty("java.awt.headless") != null - && System.getProperty("java.awt.headless").equals("true")) + if (Jalview.isHeadlessMode()) { seqPanelWidth = alignFrame.getWidth() - getVisibleIdWidth() - vscroll.getPreferredSize().width @@ -1723,4 +1738,154 @@ public class AlignmentPanel extends GAlignmentPanel implements return calculationDialog; } + @Override + public SequenceRenderer getSequenceRenderer() + { + return seqPanel.seqCanvas.getSequenceRenderer(); + } + + public boolean scrollTo(int ostart, int end, int seqIndex, + boolean scrollToNearest, boolean redrawOverview) + { + int startv, endv, starts, ends;// , width; + + int start = -1; + if (av.hasHiddenColumns()) + { + AlignmentI al = av.getAlignment(); + start = al.getHiddenColumns().absoluteToVisibleColumn(ostart); + end = al.getHiddenColumns().absoluteToVisibleColumn(end); + if (start == end) + { + if (!scrollToNearest && !al.getHiddenColumns().isVisible(ostart)) + { + // don't scroll - position isn't visible + return false; + } + } + } + else + { + start = ostart; + } + + ViewportRanges ranges = av.getRanges(); + if (!av.getWrapAlignment()) + { + /* + * int spos=av.getStartRes(),sqpos=av.getStartSeq(); if ((startv = + * av.getStartRes()) >= start) { spos=start-1; // seqIn // + * setScrollValues(start - 1, seqIndex); } else if ((endv = + * av.getEndRes()) <= end) { // setScrollValues(spos=startv + 1 + end - + * endv, seqIndex); spos=startv + 1 + end - endv; } else if ((starts = + * av.getStartSeq()) > seqIndex) { setScrollValues(av.getStartRes(), + * seqIndex); } else if ((ends = av.getEndSeq()) <= seqIndex) { + * setScrollValues(av.getStartRes(), starts + seqIndex - ends + 1); } + */ + + // below is scrolling logic up to Jalview 2.8.2 + // if ((av.getStartRes() > end) + // || (av.getEndRes() < start) + // || ((av.getStartSeq() > seqIndex) || (av.getEndSeq() < seqIndex))) + // { + // if (start > av.getAlignment().getWidth() - hextent) + // { + // start = av.getAlignment().getWidth() - hextent; + // if (start < 0) + // { + // start = 0; + // } + // + // } + // if (seqIndex > av.getAlignment().getHeight() - vextent) + // { + // seqIndex = av.getAlignment().getHeight() - vextent; + // if (seqIndex < 0) + // { + // seqIndex = 0; + // } + // } + // setScrollValues(start, seqIndex); + // } + // logic copied from jalview.gui.AlignmentPanel: + if ((startv = ranges.getStartRes()) >= start) + { + /* + * Scroll left to make start of search results visible + */ + setScrollValues(start - 1, seqIndex); + } + else if ((endv = ranges.getEndRes()) <= end) + { + /* + * Scroll right to make end of search results visible + */ + setScrollValues(startv + 1 + end - endv, seqIndex); + } + else if ((starts = ranges.getStartSeq()) > seqIndex) + { + /* + * Scroll up to make start of search results visible + */ + setScrollValues(ranges.getStartRes(), seqIndex); + } + else if ((ends = ranges.getEndSeq()) <= seqIndex) + { + /* + * Scroll down to make end of search results visible + */ + setScrollValues(ranges.getStartRes(), starts + seqIndex - ends + 1); + } + /* + * Else results are already visible - no need to scroll + */ + } + else + { + ranges.scrollToWrappedVisible(start); + } + + paintAlignment(redrawOverview, false); + return true; + } + + @Override + public void overviewDone(BufferedImage miniMe) + { + overviewPanel.canvas.finalizeDraw(miniMe); + } + + + private boolean holdRepaint = false; + + public boolean getHoldRepaint() + { + return holdRepaint; + } + + public void setHoldRepaint(boolean b) + { + if (holdRepaint == b) + { + return; + } + holdRepaint = b; + if (!b) + { + repaint(); + } + } + + @Override + public void repaint() + { + if (holdRepaint) + { + // System.out.println("AP repaint holding"); + // Platform.stackTrace(); + return; + } + super.repaint(); + } + } diff --git a/src/jalview/gui/AnnotationColourChooser.java b/src/jalview/gui/AnnotationColourChooser.java index e89c1c2..a48553e 100644 --- a/src/jalview/gui/AnnotationColourChooser.java +++ b/src/jalview/gui/AnnotationColourChooser.java @@ -283,9 +283,9 @@ public class AnnotationColourChooser extends AnnotationRowFilter private void setDefaultMinMax() { minColour.setBackground( - Cache.getDefaultColour("ANNOTATIONCOLOUR_MIN", Color.orange)); + Cache.getDefaultColour(Preferences.ANNOTATIONCOLOUR_MIN, Color.orange)); maxColour.setBackground( - Cache.getDefaultColour("ANNOTATIONCOLOUR_MAX", Color.red)); + Cache.getDefaultColour(Preferences.ANNOTATIONCOLOUR_MAX, Color.red)); } protected void showColourChooser(JPanel colourPanel, String titleKey) @@ -301,7 +301,7 @@ public class AnnotationColourChooser extends AnnotationRowFilter updateView(); } }; - JalviewColourChooser.showColourChooser(Desktop.getDesktop(), ttl, + JalviewColourChooser.showColourChooser(Desktop.getDesktopPane(), ttl, colourPanel.getBackground(), listener); } diff --git a/src/jalview/gui/AnnotationColumnChooser.java b/src/jalview/gui/AnnotationColumnChooser.java index fbc93b5..a1c082c 100644 --- a/src/jalview/gui/AnnotationColumnChooser.java +++ b/src/jalview/gui/AnnotationColumnChooser.java @@ -79,11 +79,11 @@ public class AnnotationColumnChooser extends AnnotationRowFilter public static final int ACTION_OPTION_SELECT = 1; - public static int ACTION_OPTION_HIDE = 2; + public static final int ACTION_OPTION_HIDE = 2; - public static String NO_GRAPH_VIEW = "0"; + public static final String NO_GRAPH_VIEW = "0"; - public static String GRAPH_VIEW = "1"; + public static final String GRAPH_VIEW = "1"; private int actionOption = ACTION_OPTION_SELECT; diff --git a/src/jalview/gui/AnnotationLabels.java b/src/jalview/gui/AnnotationLabels.java index a0a0df8..72d75b8 100755 --- a/src/jalview/gui/AnnotationLabels.java +++ b/src/jalview/gui/AnnotationLabels.java @@ -82,7 +82,7 @@ public class AnnotationLabels extends JPanel /** * height in pixels for allowing height adjuster to be active */ - private static int HEIGHT_ADJUSTER_HEIGHT = 10; + private static final int HEIGHT_ADJUSTER_HEIGHT = 10; private static final Font font = new Font("Arial", Font.PLAIN, 11); @@ -971,7 +971,7 @@ public class AnnotationLabels extends JPanel seqs, omitHidden, alignmentStartEnd); Toolkit.getDefaultToolkit().getSystemClipboard() - .setContents(new StringSelection(output), Desktop.instance); + .setContents(new StringSelection(output), Desktop.getInstance()); HiddenColumns hiddenColumns = null; @@ -981,7 +981,9 @@ public class AnnotationLabels extends JPanel av.getAlignment().getHiddenColumns()); } - Desktop.jalviewClipboard = new Object[] { seqs, ds, // what is the dataset + Desktop.getInstance().jalviewClipboard = new Object[] { seqs, ds, // what is + // the + // dataset // of a consensus // sequence ? need to // flag diff --git a/src/jalview/gui/AnnotationPanel.java b/src/jalview/gui/AnnotationPanel.java index 4ead210..af7bc26 100755 --- a/src/jalview/gui/AnnotationPanel.java +++ b/src/jalview/gui/AnnotationPanel.java @@ -1133,6 +1133,7 @@ public class AnnotationPanel extends JPanel implements AwtRenderPanelI, gg.dispose(); + fastPaint = true; // Call repaint on alignment panel so that repaints from other alignment @@ -1297,18 +1298,23 @@ public class AnnotationPanel extends JPanel implements AwtRenderPanelI, // Here we only want to fastpaint on a scroll, with resize using a normal // paint, so scroll events are identified as changes to the horizontal or // vertical start value. - if (evt.getPropertyName().equals(ViewportRanges.STARTRES)) + switch (evt.getPropertyName()) { + case ViewportRanges.STARTRES: fastPaint((int) evt.getNewValue() - (int) evt.getOldValue()); - } - else if (evt.getPropertyName().equals(ViewportRanges.STARTRESANDSEQ)) - { + break; + case ViewportRanges.STARTRESANDSEQ: fastPaint(((int[]) evt.getNewValue())[0] - ((int[]) evt.getOldValue())[0]); - } - else if (evt.getPropertyName().equals(ViewportRanges.MOVE_VIEWPORT)) - { + break; + case ViewportRanges.MOVE_VIEWPORT: repaint(); + break; + case ViewportRanges.STARTSEQ: + case ViewportRanges.ENDRES: + case ViewportRanges.ENDSEQ: + // ignore + break; } } diff --git a/src/jalview/gui/AppJmol.java b/src/jalview/gui/AppJmol.java index e13df4a..5687219 100644 --- a/src/jalview/gui/AppJmol.java +++ b/src/jalview/gui/AppJmol.java @@ -238,6 +238,8 @@ public class AppJmol extends StructureViewerBase // TODO: consider waiting until the structure/view is fully loaded before // displaying this.getContentPane().add(renderPanel, java.awt.BorderLayout.CENTER); + this.invalidate(); + this.pack(); jalview.gui.Desktop.addInternalFrame(this, jmb.getViewerTitle(), getBounds().width, getBounds().height); if (scriptWindow == null) @@ -328,7 +330,7 @@ public class AppJmol extends StructureViewerBase for (String s : files) { fileList.append(SPACE).append(QUOTE) - .append(Platform.escapeBackslashes(s)).append(QUOTE); + .append(Platform.escapeString(s)).append(QUOTE); } String filesString = fileList.toString(); @@ -522,7 +524,7 @@ public class AppJmol extends StructureViewerBase addingStructures = true; // already files loaded. for (int c = 0; c < filesInViewer.length; c++) { - if (Platform.pathEquals(filesInViewer[c], file)) + if (filesInViewer[c].equals(file)) { file = null; break; @@ -546,7 +548,7 @@ public class AppJmol extends StructureViewerBase } if (errormsgs.length() > 0) { - JvOptionPane.showInternalMessageDialog(Desktop.desktop, + JvOptionPane.showInternalMessageDialog(Desktop.getDesktopPane(), MessageManager.formatMessage( "label.pdb_entries_couldnt_be_retrieved", new String[] { errormsgs.toString() }), @@ -563,6 +565,7 @@ public class AppJmol extends StructureViewerBase * * @param type */ + @Override public void makePDBImage(ImageMaker.TYPE type) { int width = getWidth(); @@ -626,15 +629,25 @@ public class AppJmol extends StructureViewerBase validate(); } + @SuppressWarnings("serial") class RenderPanel extends JPanel { final Dimension currentSize = new Dimension(); + public RenderPanel() + { + setPreferredSize( + Cache.getDefaultDim(Preferences.STRUCTURE_DIMENSIONS, + Preferences.DEFAULT_STRUCTURE_DIMENSIONS)); + // BH 2019.07.12 suggesting 600,600; current is something like 347 x 323 + } + @Override public void paintComponent(Graphics g) { getSize(currentSize); - + // BH: Note that this size could be slightly different from the size set + // prior to packing. if (jmb != null && jmb.hasFileLoadingError()) { g.setColor(Color.black); diff --git a/src/jalview/gui/AppVarna.java b/src/jalview/gui/AppVarna.java index 3a64716..bb4528f 100644 --- a/src/jalview/gui/AppVarna.java +++ b/src/jalview/gui/AppVarna.java @@ -80,11 +80,11 @@ public class AppVarna extends JInternalFrame * Lookup for sequence and annotation mapped to each RNA in the viewer. Using * a linked hashmap means that order is preserved when saved to the project. */ - private Map models = new LinkedHashMap(); + private Map models = new LinkedHashMap<>(); - private Map offsets = new Hashtable(); + private Map offsets = new Hashtable<>(); - private Map offsetsInv = new Hashtable(); + private Map offsetsInv = new Hashtable<>(); private JSplitPane split; diff --git a/src/jalview/gui/AppVarnaBinding.java b/src/jalview/gui/AppVarnaBinding.java index 7430856..787ed53 100644 --- a/src/jalview/gui/AppVarnaBinding.java +++ b/src/jalview/gui/AppVarnaBinding.java @@ -72,7 +72,7 @@ public class AppVarnaBinding extends JalviewVarnaBinding private ReorderableJList _sideList = null; - private static String errorOpt = "error"; + private final static String errorOpt = "error"; @SuppressWarnings("unused") private boolean _error; @@ -100,7 +100,7 @@ public class AppVarnaBinding extends JalviewVarnaBinding */ private void init() { - DefaultListModel dlm = new DefaultListModel(); + DefaultListModel dlm = new DefaultListModel<>(); int marginTools = 40; @@ -122,6 +122,7 @@ public class AppVarnaBinding extends JalviewVarnaBinding _sideList.setPreferredSize(new Dimension(100, 0)); _sideList.addListSelectionListener(new ListSelectionListener() { + @Override public void valueChanged(ListSelectionEvent evt) { changeSelectedStructure_actionPerformed(evt); @@ -316,7 +317,7 @@ public class AppVarnaBinding extends JalviewVarnaBinding { private DefaultListModel _rnalist; - private List _rnas = new ArrayList(); + private List _rnas = new ArrayList<>(); JList _l; diff --git a/src/jalview/gui/AssociatePdbFileWithSeq.java b/src/jalview/gui/AssociatePdbFileWithSeq.java index fe0aedf..1f540da 100644 --- a/src/jalview/gui/AssociatePdbFileWithSeq.java +++ b/src/jalview/gui/AssociatePdbFileWithSeq.java @@ -20,18 +20,15 @@ */ package jalview.gui; -import jalview.api.StructureSelectionManagerProvider; import jalview.datamodel.PDBEntry; import jalview.datamodel.SequenceI; import jalview.io.DataSourceType; import jalview.io.StructureFile; -import jalview.structure.StructureSelectionManager; import jalview.util.MessageManager; -import javax.swing.JOptionPane; - /** - * GUI related routines for associating PDB files with sequences + * GUI related routines for associating PDB files with sequences. A single + * static method. * * @author JimP * @@ -39,58 +36,56 @@ import javax.swing.JOptionPane; public class AssociatePdbFileWithSeq { + private AssociatePdbFileWithSeq() + { + // inaccessible + } + /** - * assocate the given PDB file with + * Associate the given PDB file name or URL with a sequence. Do not map + * mouse-over events. * - * @param choice + * @param fileName + * or URL + * @param type + * will be DataType.FILE or DataType.URL * @param sequence + * to associate + * @param prompt + * true if the user should be asked what to do if the specified file + * does not seem to contain PDB information (StructureChooser only) + * @return null if file is not found */ - public PDBEntry associatePdbWithSeq(String choice, DataSourceType file, - SequenceI sequence, boolean prompt, - StructureSelectionManagerProvider ssmp) + public static PDBEntry associatePdbWithSeq(String fileName, + DataSourceType type, SequenceI sequence, boolean prompt) { PDBEntry entry = new PDBEntry(); StructureFile pdbfile = null; - pdbfile = StructureSelectionManager.getStructureSelectionManager(ssmp) + pdbfile = Desktop.getStructureSelectionManager() .setMapping(false, new SequenceI[] - { sequence }, null, choice, file); + { sequence }, null, fileName, type); if (pdbfile == null) { // stacktrace already thrown so just return return null; } - if (pdbfile.getId() == null) - { - String reply = null; - - if (prompt) - { - reply = JvOptionPane.showInternalInputDialog(Desktop.desktop, - MessageManager - .getString("label.couldnt_find_pdb_id_in_file"), - MessageManager.getString("label.no_pdb_id_in_file"), - JvOptionPane.QUESTION_MESSAGE); - } - if (reply == null) - { - return null; - } - - entry.setId(reply); - } - else + String id = pdbfile.getId(); + if (id == null && (id = (prompt + ? JvOptionPane.showInternalInputDialog(Desktop.getDesktopPane(), + MessageManager + .getString("label.couldnt_find_pdb_id_in_file"), + MessageManager.getString("label.no_pdb_id_in_file"), + JvOptionPane.QUESTION_MESSAGE) + : null)) == null) { - entry.setId(pdbfile.getId()); + return null; } + entry.setId(id); entry.setType(PDBEntry.Type.FILE); - - if (pdbfile != null) - { - entry.setFile(choice); - sequence.getDatasetSequence().addPDBId(entry); - StructureSelectionManager.getStructureSelectionManager(ssmp) - .registerPDBEntry(entry); - } + entry.setFile(fileName); + sequence.getDatasetSequence().addPDBId(entry); + Desktop.getInstance().getStructureSelectionManager() + .registerPDBEntry(entry); return entry; } } diff --git a/src/jalview/gui/BlogReader.java b/src/jalview/gui/BlogReader.java index 757bb01..c515e6c 100644 --- a/src/jalview/gui/BlogReader.java +++ b/src/jalview/gui/BlogReader.java @@ -537,7 +537,7 @@ public class BlogReader extends JPanel public LaunchJvBrowserOnItem(JList listItems) { super("Open in Browser"); - this.putValue(MNEMONIC_KEY, Integer.valueOf(KeyEvent.VK_O)); + this.putValue(MNEMONIC_KEY, new Integer(KeyEvent.VK_O)); this.putValue(Action.LONG_DESCRIPTION, "Open in Browser"); _listItems = listItems; } diff --git a/src/jalview/gui/CalculationChooser.java b/src/jalview/gui/CalculationChooser.java index 097a5a0..13506a5 100644 --- a/src/jalview/gui/CalculationChooser.java +++ b/src/jalview/gui/CalculationChooser.java @@ -62,8 +62,13 @@ import javax.swing.event.InternalFrameAdapter; import javax.swing.event.InternalFrameEvent; /** - * A dialog where a user can choose and action Tree or PCA calculation options + * A dialog where a user can choose and action Tree or PCA calculation options. + * + * Allows also for dialog-free static methods openPCAPanel(...) and + * openTreePanel(...) for scripted use. + * */ +@SuppressWarnings("serial") public class CalculationChooser extends JPanel { /* @@ -74,7 +79,7 @@ public class CalculationChooser extends JPanel */ private static boolean treeMatchGaps = true; - private static final Font VERDANA_11PT = new Font("Verdana", 0, 11); + private static Font VERDANA_11PT; private static final int MIN_TREE_SELECTION = 3; @@ -102,7 +107,7 @@ public class CalculationChooser extends JPanel private JCheckBox shorterSequence; - final ComboBoxTooltipRenderer renderer = new ComboBoxTooltipRenderer(); + private static ComboBoxTooltipRenderer renderer; // BH was not static List tips = new ArrayList<>(); @@ -112,6 +117,37 @@ public class CalculationChooser extends JPanel private PCAPanel pcaPanel; /** + * Open a new Tree panel on the desktop statically. Params are standard (not + * set by Groovy). No dialog is opened. + * + * @param af + * @param treeType + * @param modelName + * @return null if successful; the string + * "label.you_need_at_least_n_sequences" if number of sequences + * selected is inappropriate + */ + public static Object openTreePanel(AlignFrame af, String treeType, + String modelName) + { + return openTreePanel(af, treeType, modelName, null); + } + + /** + * public static method for JalviewJS API to open a PCAPanel without + * necessarily using a dialog. + * + * @param af + * @param modelName + * @return the PCAPanel, or the string "label.you_need_at_least_n_sequences" + * if number of sequences selected is inappropriate + */ + public static Object openPcaPanel(AlignFrame af, String modelName) + { + return openPcaPanel(af, modelName, null); + } + + /** * Constructor * * @param af @@ -232,6 +268,10 @@ public class CalculationChooser extends JPanel paramsPanel.add(includeGappedColumns); paramsPanel.add(shorterSequence); + if (VERDANA_11PT == null) + { + VERDANA_11PT = new Font("Verdana", 0, 11); + } /* * OK / Cancel buttons */ @@ -380,7 +420,11 @@ public class CalculationChooser extends JPanel */ protected JComboBox buildModelOptionsList() { - final JComboBox scoreModelsCombo = new JComboBox<>(); + JComboBox scoreModelsCombo = new JComboBox<>(); + if (renderer == null) + { + renderer = new ComboBoxTooltipRenderer(); + } scoreModelsCombo.setRenderer(renderer); /* @@ -500,7 +544,8 @@ public class CalculationChooser extends JPanel * for backwards compatibility with Jalview < 2.8 (JAL-2962) */ if (nucleotide && forPca - && Cache.getDefault("BLOSUM62_PCA_FOR_NUCLEOTIDE", false)) + && Cache.getDefault(Preferences.BLOSUM62_PCA_FOR_NUCLEOTIDE, + false)) { filtered.add(scoreModels.getBlosum62()); } @@ -537,6 +582,63 @@ public class CalculationChooser extends JPanel */ protected void openTreePanel(String modelName, SimilarityParamsI params) { + Object ret = openTreePanel(af, + neighbourJoining.isSelected() ? TreeBuilder.NEIGHBOUR_JOINING + : TreeBuilder.AVERAGE_DISTANCE, + modelName, params); + if (ret instanceof String) + { + JvOptionPane.showMessageDialog(this, // was opening on Desktop? + MessageManager.formatMessage( + (String) ret, + MIN_TREE_SELECTION), + MessageManager.getString("label.not_enough_sequences"), + JvOptionPane.WARNING_MESSAGE); + + } + } + + /** + * Open a new PCA panel on the desktop + * + * @param modelName + * @param params + */ + protected void openPcaPanel(String modelName, SimilarityParamsI params) + { + Object ret = openPcaPanel(af, modelName, params); + if (ret instanceof String) + { + JvOptionPane.showInternalMessageDialog(this, + MessageManager.formatMessage( + (String) ret, + MIN_PCA_SELECTION), + MessageManager + .getString("label.sequence_selection_insufficient"), + JvOptionPane.WARNING_MESSAGE); + } + else + { + // only used for test suite + pcaPanel = (PCAPanel) ret; + } + + } + + /** + * Open a new Tree panel on the desktop statically + * + * @param af + * @param treeType + * @param modelName + * @param params + * @return null, or the string "label.you_need_at_least_n_sequences" if number + * of sequences selected is inappropriate + */ + public static Object openTreePanel(AlignFrame af, String treeType, + String modelName, SimilarityParamsI params) + { + /* * gui validation shouldn't allow insufficient sequences here, but leave * this check in in case this method gets exposed programmatically in future @@ -545,56 +647,58 @@ public class CalculationChooser extends JPanel SequenceGroup sg = viewport.getSelectionGroup(); if (sg != null && sg.getSize() < MIN_TREE_SELECTION) { - JvOptionPane.showMessageDialog(Desktop.desktop, - MessageManager.formatMessage( - "label.you_need_at_least_n_sequences", - MIN_TREE_SELECTION), - MessageManager.getString("label.not_enough_sequences"), - JvOptionPane.WARNING_MESSAGE); - return; + return "label.you_need_at_least_n_sequences"; + } + + if (params == null) + { + params = getSimilarityParameters(false); } - String treeType = neighbourJoining.isSelected() - ? TreeBuilder.NEIGHBOUR_JOINING - : TreeBuilder.AVERAGE_DISTANCE; af.newTreePanel(treeType, modelName, params); + return null; } /** - * Open a new PCA panel on the desktop + * public static method for JalviewJS API * + * @param af * @param modelName * @param params + * @return the PCAPanel, or null if number of sequences selected is + * inappropriate */ - protected void openPcaPanel(String modelName, SimilarityParamsI params) + public static Object openPcaPanel(AlignFrame af, String modelName, + SimilarityParamsI params) { + AlignViewport viewport = af.getViewport(); /* * gui validation shouldn't allow insufficient sequences here, but leave * this check in in case this method gets exposed programmatically in future + * + * */ if (((viewport.getSelectionGroup() != null) && (viewport.getSelectionGroup().getSize() < MIN_PCA_SELECTION) && (viewport.getSelectionGroup().getSize() > 0)) || (viewport.getAlignment().getHeight() < MIN_PCA_SELECTION)) { - JvOptionPane.showInternalMessageDialog(this, - MessageManager.formatMessage( - "label.you_need_at_least_n_sequences", - MIN_PCA_SELECTION), - MessageManager - .getString("label.sequence_selection_insufficient"), - JvOptionPane.WARNING_MESSAGE); - return; + return "label.you_need_at_least_n_sequences"; + } + + if (params == null) + { + params = getSimilarityParameters(true); } /* * construct the panel and kick off its calculation thread */ - pcaPanel = new PCAPanel(af.alignPanel, modelName, params); - new Thread(pcaPanel).start(); - + PCAPanel pcap = new PCAPanel(af.alignPanel, modelName, params); + new Thread(pcap).start(); + return pcap; } /** @@ -610,6 +714,7 @@ public class CalculationChooser extends JPanel } } + /** * Returns a data bean holding parameters for similarity (or distance) model * calculation @@ -617,7 +722,8 @@ public class CalculationChooser extends JPanel * @param doPCA * @return */ - protected SimilarityParamsI getSimilarityParameters(boolean doPCA) + public static SimilarityParamsI getSimilarityParameters( + boolean doPCA) { // commented out: parameter choices read from gui widgets // SimilarityParamsI params = new SimilarityParams( @@ -638,6 +744,7 @@ public class CalculationChooser extends JPanel return new SimilarityParams(includeGapGap, matchGap, includeGapResidue, matchOnShortestLength); + } /** @@ -655,6 +762,7 @@ public class CalculationChooser extends JPanel public PCAPanel getPcaPanel() { + // only called for FreeUpMemoryTest return pcaPanel; } } diff --git a/src/jalview/gui/ChimeraViewFrame.java b/src/jalview/gui/ChimeraViewFrame.java index c6d6e97..fff1eed 100644 --- a/src/jalview/gui/ChimeraViewFrame.java +++ b/src/jalview/gui/ChimeraViewFrame.java @@ -336,7 +336,7 @@ public class ChimeraViewFrame extends StructureViewerBase if (!jmb.launchChimera()) { - JvOptionPane.showMessageDialog(Desktop.desktop, + JvOptionPane.showMessageDialog(Desktop.getDesktopPane(), MessageManager.getString("label.chimera_failed"), MessageManager.getString("label.error_loading_file"), JvOptionPane.ERROR_MESSAGE); @@ -481,7 +481,7 @@ public class ChimeraViewFrame extends StructureViewerBase { filePDB.add(thePdbEntry); filePDBpos.add(Integer.valueOf(pi)); - files.append(" \"" + Platform.escapeBackslashes(file) + "\""); + files.append(" \"" + Platform.escapeString(file) + "\""); } } } catch (OutOfMemoryError oomerror) @@ -497,7 +497,7 @@ public class ChimeraViewFrame extends StructureViewerBase if (errormsgs.length() > 0) { - JvOptionPane.showInternalMessageDialog(Desktop.desktop, + JvOptionPane.showInternalMessageDialog(Desktop.getDesktopPane(), MessageManager.formatMessage( "label.pdb_entries_couldnt_be_retrieved", new Object[] { errormsgs.toString() }), diff --git a/src/jalview/gui/ColourMenuHelper.java b/src/jalview/gui/ColourMenuHelper.java index 6eab07d..5528e75 100644 --- a/src/jalview/gui/ColourMenuHelper.java +++ b/src/jalview/gui/ColourMenuHelper.java @@ -158,7 +158,7 @@ public class ColourMenuHelper ActionListener al = radioItem.getActionListeners()[0]; radioItem.removeActionListener(al); int option = JvOptionPane.showInternalConfirmDialog( - Desktop.desktop, + Desktop.getDesktopPane(), MessageManager .getString("label.remove_from_default_list"), MessageManager @@ -281,7 +281,7 @@ public class ColourMenuHelper static void updatePreferences() { StringBuilder coloursFound = new StringBuilder(); - String[] files = Cache.getProperty("USER_DEFINED_COLOURS").split("\\|"); + String[] files = Cache.getProperty(Preferences.USER_DEFINED_COLOURS).split("\\|"); /* * the property does not include the scheme name, it is in the file; @@ -310,11 +310,11 @@ public class ColourMenuHelper if (coloursFound.toString().length() > 1) { - Cache.setProperty("USER_DEFINED_COLOURS", coloursFound.toString()); + Cache.setProperty(Preferences.USER_DEFINED_COLOURS, coloursFound.toString()); } else { - Cache.applicationProperties.remove("USER_DEFINED_COLOURS"); + Cache.removePropertyNoSave(Preferences.USER_DEFINED_COLOURS); } } } diff --git a/src/jalview/gui/ComboBoxTooltipRenderer.java b/src/jalview/gui/ComboBoxTooltipRenderer.java index 684f965..a601ed6 100644 --- a/src/jalview/gui/ComboBoxTooltipRenderer.java +++ b/src/jalview/gui/ComboBoxTooltipRenderer.java @@ -48,7 +48,8 @@ public class ComboBoxTooltipRenderer extends DefaultListCellRenderer JComponent comp = (JComponent) super.getListCellRendererComponent(list, value, index, isSelected, cellHasFocus); - if (-1 < index && null != value && null != tooltips) + // BH 2019.07.07 restricting this to mouse moves over the selected target + if (isSelected && -1 < index && null != value && null != tooltips) { list.setToolTipText(tooltips.get(index)); } diff --git a/src/jalview/gui/Console.java b/src/jalview/gui/Console.java index 2e88eeb..f44dae1 100644 --- a/src/jalview/gui/Console.java +++ b/src/jalview/gui/Console.java @@ -136,7 +136,7 @@ public class Console extends WindowAdapter } quit = false; // signals the Threads that they should exit - // Starting two seperate threads to read from the PipedInputStreams + // Starting two separate threads to read from the PipedInputStreams // reader = new Thread(this); reader.setDaemon(true); @@ -313,7 +313,8 @@ public class Console extends WindowAdapter initConsole(false); JalviewAppender jappender = new JalviewAppender(); jappender.setLayout(new SimpleLayout()); - JalviewAppender.setTextArea(textArea); + // BH 2019 JalviewAppender.setTextArea(textArea); + jappender.setTextArea(textArea); org.apache.log4j.Logger.getRootLogger().addAppender(jappender); } diff --git a/src/jalview/gui/CrossRefAction.java b/src/jalview/gui/CrossRefAction.java index b5275e8..f607686 100644 --- a/src/jalview/gui/CrossRefAction.java +++ b/src/jalview/gui/CrossRefAction.java @@ -34,7 +34,6 @@ import jalview.datamodel.SequenceI; import jalview.ext.ensembl.EnsemblInfo; import jalview.ext.ensembl.EnsemblMap; import jalview.io.gff.SequenceOntologyI; -import jalview.structure.StructureSelectionManager; import jalview.util.DBRefUtils; import jalview.util.MapList; import jalview.util.MappingUtils; @@ -108,7 +107,8 @@ public class CrossRefAction implements Runnable /* * get display scheme (if any) to apply to features */ - FeatureSettingsModelI featureColourScheme = new SequenceFetcher() + FeatureSettingsModelI featureColourScheme = SequenceFetcher + .getInstance() .getFeatureColourScheme(source); AlignmentI xrefsAlignment = makeCrossReferencesAlignment(dataset, @@ -141,7 +141,7 @@ public class CrossRefAction implements Runnable */ AlignFrame newFrame = new AlignFrame(xrefsAlignment, AlignFrame.DEFAULT_WIDTH, AlignFrame.DEFAULT_HEIGHT); - if (Cache.getDefault("HIDE_INTRONS", true)) + if (Cache.getDefault(Preferences.HIDE_INTRONS, true)) { newFrame.hideFeatureColumns(SequenceOntologyI.EXON, false); } @@ -276,7 +276,7 @@ public class CrossRefAction implements Runnable return; } - Set ensemblDivisions = new EnsemblInfo().getDivisions(); + Set ensemblDivisions = EnsemblInfo.getDivisions(); /* * first look for direct dbrefs from sequence to Ensembl @@ -436,14 +436,12 @@ public class CrossRefAction implements Runnable copyAlignment .setGapCharacter(alignFrame.viewport.getGapCharacter()); - StructureSelectionManager ssm = StructureSelectionManager - .getStructureSelectionManager(Desktop.instance); - /* * register any new mappings for sequence mouseover etc * (will not duplicate any previously registered mappings) */ - ssm.registerMappings(dataset.getCodonFrames()); + Desktop.getStructureSelectionManager() + .registerMappings(dataset.getCodonFrames()); if (copyAlignment.getHeight() <= 0) { diff --git a/src/jalview/gui/CutAndPasteTransfer.java b/src/jalview/gui/CutAndPasteTransfer.java index d328a0d..3514b75 100644 --- a/src/jalview/gui/CutAndPasteTransfer.java +++ b/src/jalview/gui/CutAndPasteTransfer.java @@ -234,7 +234,7 @@ public class CutAndPasteTransfer extends GCutAndPasteTransfer .println(MessageManager.getString("label.couldnt_read_data")); if (!Jalview.isHeadlessMode()) { - JvOptionPane.showInternalMessageDialog(Desktop.desktop, + JvOptionPane.showInternalMessageDialog(Desktop.getDesktopPane(), AppletFormatAdapter.getSupportedFormats(), MessageManager.getString("label.couldnt_read_data"), JvOptionPane.WARNING_MESSAGE); @@ -253,7 +253,7 @@ public class CutAndPasteTransfer extends GCutAndPasteTransfer } catch (IOException ex) { - JvOptionPane.showInternalMessageDialog(Desktop.desktop, MessageManager + JvOptionPane.showInternalMessageDialog(Desktop.getDesktopPane(), MessageManager .formatMessage("label.couldnt_read_pasted_text", new String[] { ex.toString() }), MessageManager.getString("label.error_parsing_text"), @@ -330,7 +330,8 @@ public class CutAndPasteTransfer extends GCutAndPasteTransfer try { af.setMaximum( - jalview.bin.Cache.getDefault("SHOW_FULLSCREEN", false)); + jalview.bin.Cache.getDefault(Preferences.SHOW_FULLSCREEN, + false)); } catch (Exception ex) { } @@ -342,7 +343,7 @@ public class CutAndPasteTransfer extends GCutAndPasteTransfer .println(MessageManager.getString("label.couldnt_read_data")); if (!Jalview.isHeadlessMode()) { - JvOptionPane.showInternalMessageDialog(Desktop.desktop, + JvOptionPane.showInternalMessageDialog(Desktop.getDesktopPane(), AppletFormatAdapter.getSupportedFormats(), MessageManager.getString("label.couldnt_read_data"), JvOptionPane.WARNING_MESSAGE); diff --git a/src/jalview/gui/Desktop.java b/src/jalview/gui/Desktop.java index 9dd46d6..ace7529 100644 --- a/src/jalview/gui/Desktop.java +++ b/src/jalview/gui/Desktop.java @@ -22,6 +22,9 @@ package jalview.gui; import jalview.api.AlignViewportI; import jalview.api.AlignmentViewPanel; +import jalview.api.StructureSelectionManagerProvider; +import jalview.bin.ApplicationSingletonProvider; +import jalview.bin.ApplicationSingletonProvider.ApplicationSingletonI; import jalview.bin.Cache; import jalview.bin.Jalview; import jalview.gui.ImageExporter.ImageWriterI; @@ -36,6 +39,7 @@ import jalview.io.FormatAdapter; import jalview.io.IdentifyFile; import jalview.io.JalviewFileChooser; import jalview.io.JalviewFileView; +import jalview.jbgui.GDesktop; import jalview.jbgui.GSplitFrame; import jalview.jbgui.GStructureViewer; import jalview.project.Jalview2XML; @@ -47,6 +51,7 @@ import jalview.util.MessageManager; import jalview.util.Platform; import jalview.util.UrlConstants; import jalview.viewmodel.AlignmentViewport; +import jalview.ws.jws1.Discoverer; import jalview.ws.params.ParamManager; import jalview.ws.utils.UrlDownloadClient; @@ -82,11 +87,9 @@ import java.beans.PropertyChangeListener; import java.io.BufferedInputStream; import java.io.File; import java.io.FileOutputStream; -import java.io.FileWriter; import java.io.IOException; import java.net.URL; import java.util.ArrayList; -import java.util.HashMap; import java.util.Hashtable; import java.util.List; import java.util.ListIterator; @@ -108,6 +111,7 @@ import javax.swing.JCheckBox; import javax.swing.JComboBox; import javax.swing.JComponent; import javax.swing.JDesktopPane; +import javax.swing.JFrame; import javax.swing.JInternalFrame; import javax.swing.JLabel; import javax.swing.JMenuItem; @@ -133,30 +137,28 @@ import org.stackoverflowusers.file.WindowsShortcut; * @author $author$ * @version $Revision: 1.155 $ */ -public class Desktop extends jalview.jbgui.GDesktop +@SuppressWarnings("serial") +public class Desktop extends GDesktop implements DropTargetListener, ClipboardOwner, IProgressIndicator, - jalview.api.StructureSelectionManagerProvider + StructureSelectionManagerProvider, ApplicationSingletonI { - private static int DEFAULT_MIN_WIDTH = 300; - private static int DEFAULT_MIN_HEIGHT = 250; + private final static int DEFAULT_MIN_WIDTH = 300; - private static int ALIGN_FRAME_DEFAULT_MIN_WIDTH = 600; + private final static int DEFAULT_MIN_HEIGHT = 250; - private static int ALIGN_FRAME_DEFAULT_MIN_HEIGHT = 70; + private final static int ALIGN_FRAME_DEFAULT_MIN_WIDTH = 600; - private static final String EXPERIMENTAL_FEATURES = "EXPERIMENTAL_FEATURES"; + private final static int ALIGN_FRAME_DEFAULT_MIN_HEIGHT = 70; - protected static final String CONFIRM_KEYBOARD_QUIT = "CONFIRM_KEYBOARD_QUIT"; - - public static HashMap savingFiles = new HashMap<>(); + private final static String EXPERIMENTAL_FEATURES = "EXPERIMENTAL_FEATURES"; private JalviewChangeSupport changeSupport = new JalviewChangeSupport(); /** * news reader - null if it was never started. */ - private BlogReader jvnews = null; + BlogReader jvnews = null; private File projectFile; @@ -195,16 +197,16 @@ public class Desktop extends jalview.jbgui.GDesktop listener); } - /** Singleton Desktop instance */ - public static Desktop instance; - - public static MyDesktopPane desktop; + public static MyDesktopPane getDesktopPane() + { + Desktop desktop = Desktop.getInstance(); + return desktop == null ? null : desktop.desktopPane; + } - public static MyDesktopPane getDesktop() + public static StructureSelectionManager getStructureSelectionManager() { - // BH 2018 could use currentThread() here as a reference to a - // Hashtable in JavaScript - return desktop; + return StructureSelectionManager + .getStructureSelectionManager(getInstance()); } static int openFrameCount = 0; @@ -213,13 +215,22 @@ public class Desktop extends jalview.jbgui.GDesktop static final int yOffset = 30; - public static jalview.ws.jws1.Discoverer discoverer; + public Discoverer discoverer; + + public Object[] jalviewClipboard; + + public boolean internalCopy = false; + + private static int fileLoadingCount = 0; - public static Object[] jalviewClipboard; + public JInternalFrame conservationSlider; - public static boolean internalCopy = false; + public JInternalFrame PIDSlider; - static int fileLoadingCount = 0; + /** + * just an instance (for testng, probably); no actual frames + */ + private boolean instanceOnly; class MyDesktopManager implements DesktopManager { @@ -240,7 +251,7 @@ public class Desktop extends jalview.jbgui.GDesktop } catch (NullPointerException npe) { Point p = getMousePosition(); - instance.showPasteMenu(p.x, p.y); + showPasteMenu(p.x, p.y); } } @@ -288,14 +299,14 @@ public class Desktop extends jalview.jbgui.GDesktop public void endDraggingFrame(JComponent f) { delegate.endDraggingFrame(f); - desktop.repaint(); + desktopPane.repaint(); } @Override public void endResizingFrame(JComponent f) { delegate.endResizingFrame(f); - desktop.repaint(); + desktopPane.repaint(); } @Override @@ -344,100 +355,89 @@ public class Desktop extends jalview.jbgui.GDesktop } + public MyDesktopPane desktopPane; + + /** + * Answers an 'application scope' singleton instance of this class. Separate + * SwingJS 'applets' running in the same browser page will each have a + * distinct instance of Desktop. + * + * @return + */ + public static Desktop getInstance() + { + return Jalview.isHeadlessMode() ? null + : (Desktop) ApplicationSingletonProvider + .getInstance(Desktop.class); + } + + /** + * For testing. + * + * @param forInstance + */ + public Desktop(boolean forInstance) + { + + Cache.initLogger(); + instanceOnly = true; + } + /** - * Creates a new Desktop object. + * Private constructor enforces singleton pattern. It is called by reflection + * from ApplicationSingletonProvider.getInstance(). */ - public Desktop() + @SuppressWarnings("unused") + private Desktop() { - super(); + Cache.initLogger(); + try + { /** * A note to implementors. It is ESSENTIAL that any activities that might * block are spawned off as threads rather than waited for during this * constructor. */ - instance = this; if (!Platform.isJS()) { doVamsasClientCheck(); } - + doConfigureStructurePrefs(); setTitle("Jalview " + jalview.bin.Cache.getProperty("VERSION")); - /* - if (!Platform.isAMac()) - { - // this.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE); - } - else - { - this.setDefaultCloseOperation(WindowConstants.DO_NOTHING_ON_CLOSE); - } - */ - - try - { - if (!Platform.isJS()) - /* - * @j2sIgnore - */ - { - APQHandlers.setAPQHandlers(this); - } - } catch (Exception e) - { - System.out.println("Cannot set APQHandlers"); - // e.printStackTrace(); - } catch (Throwable t) - { - System.out.println("Cannot set APQHandlers"); - // t.printStackTrace(); - } - - - addWindowListener(new WindowAdapter() - { - - @Override - public void windowClosing(WindowEvent ev) - { - quit(); - } - }); - + setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); boolean selmemusage = jalview.bin.Cache.getDefault("SHOW_MEMUSAGE", false); - boolean showjconsole = jalview.bin.Cache.getDefault("SHOW_JAVA_CONSOLE", false); - desktop = new MyDesktopPane(selmemusage); - + desktopPane = new MyDesktopPane(selmemusage); + showMemusage.setSelected(selmemusage); - desktop.setBackground(Color.white); - + desktopPane.setBackground(Color.white); getContentPane().setLayout(new BorderLayout()); // alternate config - have scrollbars - see notes in JAL-153 // JScrollPane sp = new JScrollPane(); // sp.getViewport().setView(desktop); // getContentPane().add(sp, BorderLayout.CENTER); - + // BH 2018 - just an experiment to try unclipped JInternalFrames. if (Platform.isJS()) { getRootPane().putClientProperty("swingjs.overflow.hidden", "false"); } - - getContentPane().add(desktop, BorderLayout.CENTER); - desktop.setDragMode(JDesktopPane.OUTLINE_DRAG_MODE); - + + getContentPane().add(desktopPane, BorderLayout.CENTER); + desktopPane.setDragMode(JDesktopPane.OUTLINE_DRAG_MODE); + // This line prevents Windows Look&Feel resizing all new windows to maximum // if previous window was maximised - desktop.setDesktopManager(new MyDesktopManager( + desktopPane.setDesktopManager(new MyDesktopManager( (Platform.isWindowsAndNotJS() ? new DefaultDesktopManager() : Platform.isAMacAndNotJS() ? new AquaInternalFrameManager( - desktop.getDesktopManager()) - : desktop.getDesktopManager()))); - + desktopPane.getDesktopManager()) + : desktopPane.getDesktopManager()))); + Rectangle dims = getLastKnownDimensions(""); if (dims != null) { @@ -450,7 +450,7 @@ public class Desktop extends jalview.jbgui.GDesktop int yPos = Math.max(5, (screenSize.height - 650) / 2); setBounds(xPos, yPos, 900, 650); } - + if (!Platform.isJS()) /** * Java only @@ -458,7 +458,7 @@ public class Desktop extends jalview.jbgui.GDesktop * @j2sIgnore */ { - + jconsole = new Console(this, showjconsole); // add essential build information jconsole.setHeader("Jalview Version: " @@ -470,27 +470,20 @@ public class Desktop extends jalview.jbgui.GDesktop + "Java version: " + System.getProperty("java.version") + "\n" + System.getProperty("os.arch") + " " + System.getProperty("os.name") + " " - + System.getProperty("os.version") - + (jalview.bin.Cache.getProperty("VERSION").equals("DEVELOPMENT") - ? "\nJava path:" - + System.getProperty( - "java.home") - + File.separator + "bin" - + File.separator + "java" - : "")); - + + System.getProperty("os.version")); + showConsole(showjconsole); - + showNews.setVisible(false); - + experimentalFeatures.setSelected(showExperimental()); - + getIdentifiersOrgData(); - + checkURLLinks(); - + // Spawn a thread that shows the splashscreen - + SwingUtilities.invokeLater(new Runnable() { @Override @@ -499,9 +492,10 @@ public class Desktop extends jalview.jbgui.GDesktop new SplashScreen(); } }); - + // Thread off a new instance of the file chooser - this reduces the time - // it takes to open it later on. + // it + // takes to open it later on. new Thread(new Runnable() { @Override @@ -518,7 +512,7 @@ public class Desktop extends jalview.jbgui.GDesktop changeSupport.addJalviewPropertyChangeListener("services", new PropertyChangeListener() { - + @Override public void propertyChange(PropertyChangeEvent evt) { @@ -526,13 +520,13 @@ public class Desktop extends jalview.jbgui.GDesktop + evt.getNewValue()); JalviewServicesChanged(evt); } - + }); - + } - - this.setDropTarget(new java.awt.dnd.DropTarget(desktop, this)); - + + this.setDropTarget(new java.awt.dnd.DropTarget(desktopPane, this)); + this.addWindowListener(new WindowAdapter() { @Override @@ -541,7 +535,7 @@ public class Desktop extends jalview.jbgui.GDesktop quit(); } }); - + MouseAdapter ma; this.addMouseListener(ma = new MouseAdapter() { @@ -553,7 +547,7 @@ public class Desktop extends jalview.jbgui.GDesktop showPasteMenu(evt.getX(), evt.getY()); } } - + @Override public void mouseReleased(MouseEvent evt) { @@ -563,8 +557,11 @@ public class Desktop extends jalview.jbgui.GDesktop } } }); - desktop.addMouseListener(ma); - + desktopPane.addMouseListener(ma); + } catch (Throwable t) + { + t.printStackTrace(); + } } /** @@ -628,10 +625,10 @@ public class Desktop extends jalview.jbgui.GDesktop public void run() { Cache.log.debug("Downloading data from identifiers.org"); - UrlDownloadClient client = new UrlDownloadClient(); + // UrlDownloadClient client = new UrlDownloadClient(); try { - client.download(IdOrgSettings.getUrl(), + UrlDownloadClient.download(IdOrgSettings.getUrl(), IdOrgSettings.getDownloadLocation()); } catch (IOException e) { @@ -649,7 +646,7 @@ public class Desktop extends jalview.jbgui.GDesktop showNews(showNews.isSelected()); } - void showNews(boolean visible) + protected void showNews(boolean visible) { Cache.log.debug((visible ? "Showing" : "Hiding") + " news."); showNews.setSelected(visible); @@ -661,10 +658,10 @@ public class Desktop extends jalview.jbgui.GDesktop public void run() { long now = System.currentTimeMillis(); - Desktop.instance.setProgressBar( + setProgressBar( MessageManager.getString("status.refreshing_news"), now); jvnews.refreshNews(); - Desktop.instance.setProgressBar(null, now); + setProgressBar(null, now); jvnews.showNews(); } }).start(); @@ -769,7 +766,7 @@ public class Desktop extends jalview.jbgui.GDesktop } } - void showPasteMenu(int x, int y) + protected void showPasteMenu(int x, int y) { JPopupMenu popup = new JPopupMenu(); JMenuItem item = new JMenuItem( @@ -802,7 +799,7 @@ public class Desktop extends jalview.jbgui.GDesktop FileFormatI format = new IdentifyFile().identify(file, DataSourceType.PASTE); - new FileLoader().LoadFile(file, DataSourceType.PASTE, format); + new FileLoader().loadFile(file, DataSourceType.PASTE, format); } } catch (Exception ex) @@ -897,13 +894,14 @@ public class Desktop extends jalview.jbgui.GDesktop int w, int h, boolean resizable, boolean ignoreMinSize) { + // TODO: allow callers to determine X and Y position of frame (eg. via // bounds object). // TODO: consider fixing method to update entries in the window submenu with // the current window title frame.setTitle(title); - if (frame.getWidth() < 1 || frame.getHeight() < 1) + if (w > 0 && (frame.getWidth() < 1 || frame.getHeight() < 1)) { frame.setSize(w, h); } @@ -911,8 +909,7 @@ public class Desktop extends jalview.jbgui.GDesktop // A HEADLESS STATE WHEN NO DESKTOP EXISTS. MUST RETURN // IF JALVIEW IS RUNNING HEADLESS // /////////////////////////////////////////////// - if (instance == null || (System.getProperty("java.awt.headless") != null - && System.getProperty("java.awt.headless").equals("true"))) + if (Jalview.isHeadlessMode() || Desktop.getInstance().instanceOnly) { return; } @@ -952,13 +949,13 @@ public class Desktop extends jalview.jbgui.GDesktop * add an entry for the new frame in the Window menu * (and remove it when the frame is closed) */ - final JMenuItem menuItem = new JMenuItem(title); + JMenuItem menuItem = new JMenuItem(title); frame.addInternalFrameListener(new InternalFrameAdapter() { @Override public void internalFrameActivated(InternalFrameEvent evt) { - JInternalFrame itf = desktop.getSelectedFrame(); + JInternalFrame itf = getDesktopPane().getSelectedFrame(); if (itf != null) { if (itf instanceof AlignFrame) @@ -990,7 +987,7 @@ public class Desktop extends jalview.jbgui.GDesktop { menuItem.removeActionListener(menuItem.getActionListeners()[0]); } - windowMenu.remove(menuItem); + Desktop.getInstance().windowMenu.remove(menuItem); } }); @@ -1012,9 +1009,9 @@ public class Desktop extends jalview.jbgui.GDesktop setKeyBindings(frame); - desktop.add(frame); + getDesktopPane().add(frame); - windowMenu.add(menuItem); + Desktop.getInstance().windowMenu.add(menuItem); frame.toFront(); try @@ -1039,7 +1036,6 @@ public class Desktop extends jalview.jbgui.GDesktop */ private static void setKeyBindings(JInternalFrame frame) { - @SuppressWarnings("serial") final Action closeAction = new AbstractAction() { @Override @@ -1055,7 +1051,7 @@ public class Desktop extends jalview.jbgui.GDesktop KeyStroke ctrlWKey = KeyStroke.getKeyStroke(KeyEvent.VK_W, InputEvent.CTRL_DOWN_MASK); KeyStroke cmdWKey = KeyStroke.getKeyStroke(KeyEvent.VK_W, - jalview.util.ShortcutKeyMaskExWrapper.getMenuShortcutKeyMaskEx()); + Toolkit.getDefaultToolkit().getMenuShortcutKeyMask()); InputMap inputMap = frame .getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW); @@ -1072,7 +1068,7 @@ public class Desktop extends jalview.jbgui.GDesktop { if (!internalCopy) { - Desktop.jalviewClipboard = null; + Desktop.getInstance().jalviewClipboard = null; } internalCopy = false; @@ -1151,7 +1147,7 @@ public class Desktop extends jalview.jbgui.GDesktop { Platform.cacheFileData((File) file); } - new FileLoader().LoadFile(null, file, protocol, format); + new FileLoader().loadFile(null, file, protocol, format); } } catch (Exception ex) @@ -1174,7 +1170,7 @@ public class Desktop extends jalview.jbgui.GDesktop { String fileFormat = Cache.getProperty("DEFAULT_FILE_FORMAT"); JalviewFileChooser chooser = JalviewFileChooser - .forRead(Cache.getProperty("LAST_DIRECTORY"), fileFormat, BackupFiles.getEnabled()); + .forRead(Cache.getProperty("LAST_DIRECTORY"), fileFormat, true); chooser.setFileView(new JalviewFileView()); chooser.setDialogTitle( @@ -1208,7 +1204,7 @@ public class Desktop extends jalview.jbgui.GDesktop } } - new FileLoader().LoadFile(viewport, selectedFile, + new FileLoader().loadFile(viewport, selectedFile, DataSourceType.FILE, format); } }); @@ -1282,12 +1278,12 @@ public class Desktop extends jalview.jbgui.GDesktop { if (viewport != null) { - new FileLoader().LoadFile(viewport, url, DataSourceType.URL, + new FileLoader().loadFile(viewport, url, DataSourceType.URL, FileFormat.Jalview); } else { - new FileLoader().LoadFile(url, DataSourceType.URL, + new FileLoader().loadFile(url, DataSourceType.URL, FileFormat.Jalview); } } @@ -1307,7 +1303,8 @@ public class Desktop extends jalview.jbgui.GDesktop { String msg = MessageManager .formatMessage("label.couldnt_locate", url); - JvOptionPane.showInternalMessageDialog(Desktop.desktop, msg, + JvOptionPane.showInternalMessageDialog(Desktop.getDesktopPane(), + msg, MessageManager.getString("label.url_not_found"), JvOptionPane.WARNING_MESSAGE); @@ -1316,19 +1313,20 @@ public class Desktop extends jalview.jbgui.GDesktop if (viewport != null) { - new FileLoader().LoadFile(viewport, url, DataSourceType.URL, + new FileLoader().loadFile(viewport, url, DataSourceType.URL, format); } else { - new FileLoader().LoadFile(url, DataSourceType.URL, format); + new FileLoader().loadFile(url, DataSourceType.URL, format); } } } }; String dialogOption = MessageManager .getString("label.input_alignment_from_url"); - JvOptionPane.newOptionDialog(desktop).setResponseHandler(0, action) + JvOptionPane.newOptionDialog(getDesktopPane()) + .setResponseHandler(0, action) .showInternalDialog(panel, dialogOption, JvOptionPane.YES_NO_CANCEL_OPTION, JvOptionPane.PLAIN_MESSAGE, null, options, @@ -1414,7 +1412,7 @@ public class Desktop extends jalview.jbgui.GDesktop public void aboutMenuItem_actionPerformed(ActionEvent e) { // StringBuffer message = getAboutMessage(false); - // JvOptionPane.showInternalMessageDialog(Desktop.desktop, + // JvOptionPane.showInternalMessageDialog(Desktop.getDesktop(), // // message.toString(), "About Jalview", JvOptionPane.INFORMATION_MESSAGE); new Thread(new Runnable() @@ -1523,8 +1521,12 @@ public class Desktop extends jalview.jbgui.GDesktop @Override public void closeAll_actionPerformed(ActionEvent e) { + if (desktopPane == null) + { + return; + } // TODO show a progress bar while closing? - JInternalFrame[] frames = desktop.getAllFrames(); + JInternalFrame[] frames = desktopPane.getAllFrames(); for (int i = 0; i < frames.length; i++) { try @@ -1545,12 +1547,7 @@ public class Desktop extends jalview.jbgui.GDesktop * reset state of singleton objects as appropriate (clear down session state * when all windows are closed) */ - StructureSelectionManager ssm = StructureSelectionManager - .getStructureSelectionManager(this); - if (ssm != null) - { - ssm.resetAll(); - } + getStructureSelectionManager().resetAll(); } @Override @@ -1595,7 +1592,7 @@ public class Desktop extends jalview.jbgui.GDesktop @Override protected void showMemusage_actionPerformed(ActionEvent e) { - desktop.showMemoryUsage(showMemusage.isSelected()); + getDesktopPane().showMemoryUsage(showMemusage.isSelected()); } /* @@ -1632,7 +1629,7 @@ public class Desktop extends jalview.jbgui.GDesktop void reorderAssociatedWindows(boolean minimize, boolean close) { - JInternalFrame[] frames = desktop.getAllFrames(); + JInternalFrame[] frames = getDesktopPane().getAllFrames(); if (frames == null || frames.length < 1) { return; @@ -1816,7 +1813,7 @@ public class Desktop extends jalview.jbgui.GDesktop saveState_actionPerformed(true); } - private void setProjectFile(File choice) + protected void setProjectFile(File choice) { this.projectFile = choice; } @@ -1838,7 +1835,7 @@ public class Desktop extends jalview.jbgui.GDesktop "Jalview Project (old)" }; JalviewFileChooser chooser = new JalviewFileChooser( Cache.getProperty("LAST_DIRECTORY"), suffix, desc, - "Jalview Project", true, BackupFiles.getEnabled()); // last two booleans: allFiles, + "Jalview Project", true, true); // last two booleans: allFiles, // allowBackupFiles chooser.setFileView(new JalviewFileView()); chooser.setDialogTitle(MessageManager.getString("label.restore_state")); @@ -1866,7 +1863,7 @@ public class Desktop extends jalview.jbgui.GDesktop { Cache.log.error( "Problems whilst loading project from " + choice, ex); - JvOptionPane.showMessageDialog(Desktop.desktop, + JvOptionPane.showMessageDialog(Desktop.getDesktopPane(), MessageManager.formatMessage( "label.error_whilst_loading_project_from", new Object[] @@ -1909,7 +1906,7 @@ public class Desktop extends jalview.jbgui.GDesktop { progressPanel = new JPanel(new GridLayout(1, 1)); totalProgressCount = 0; - instance.getContentPane().add(progressPanel, BorderLayout.SOUTH); + getContentPane().add(progressPanel, BorderLayout.SOUTH); } JPanel thisprogress = new JPanel(new BorderLayout(10, 5)); JProgressBar progressBar = new JProgressBar(); @@ -1922,7 +1919,7 @@ public class Desktop extends jalview.jbgui.GDesktop ((GridLayout) progressPanel.getLayout()).setRows( ((GridLayout) progressPanel.getLayout()).getRows() + 1); ++totalProgressCount; - instance.validate(); + validate(); return thisprogress; } @@ -1976,7 +1973,7 @@ public class Desktop extends jalview.jbgui.GDesktop */ public static AlignmentPanel[] getAlignmentPanels(String alignmentId) { - if (Desktop.desktop == null) + if (Desktop.getDesktopPane() == null) { // no frames created and in headless mode // TODO: verify that frames are recoverable when in headless mode @@ -2018,7 +2015,7 @@ public class Desktop extends jalview.jbgui.GDesktop public static AlignmentViewport[] getViewports(String sequenceSetId) { List viewp = new ArrayList<>(); - if (desktop != null) + if (getDesktopPane() != null) { AlignFrame[] frames = Desktop.getAlignFrames(); @@ -2104,7 +2101,7 @@ public class Desktop extends jalview.jbgui.GDesktop { source.viewport.setGatherViewsHere(true); source.viewport.setExplodedGeometry(source.getBounds()); - JInternalFrame[] frames = desktop.getAllFrames(); + JInternalFrame[] frames = getAllFrames(); String viewId = source.viewport.getSequenceSetId(); for (int t = 0; t < frames.length; t++) @@ -2161,7 +2158,7 @@ public class Desktop extends jalview.jbgui.GDesktop String fle = chooser.getSelectedFile().toString(); if (!vamsasImport(chooser.getSelectedFile())) { - JvOptionPane.showInternalMessageDialog(Desktop.desktop, + JvOptionPane.showInternalMessageDialog(Desktop.getDesktopPane(), MessageManager.formatMessage( "label.couldnt_import_as_vamsas_session", new Object[] @@ -2462,7 +2459,7 @@ public class Desktop extends jalview.jbgui.GDesktop removeProgressPanel(progpanel); if (warnmsg != null) { - JvOptionPane.showInternalMessageDialog(Desktop.desktop, + JvOptionPane.showInternalMessageDialog(Desktop.getDesktopPane(), warnmsg, warnttl, JvOptionPane.ERROR_MESSAGE); } @@ -2499,7 +2496,7 @@ public class Desktop extends jalview.jbgui.GDesktop public JInternalFrame[] getAllFrames() { - return desktop.getAllFrames(); + return desktopPane.getAllFrames(); } /** @@ -2538,7 +2535,7 @@ public class Desktop extends jalview.jbgui.GDesktop while (li.hasNext()) { String link = li.next(); - if (link.contains(jalview.util.UrlConstants.SEQUENCE_ID) + if (link.contains(UrlConstants.SEQUENCE_ID) && !UrlConstants.isDefaultString(link)) { check = true; @@ -2585,7 +2582,7 @@ public class Desktop extends jalview.jbgui.GDesktop }); msgPanel.add(jcb); - JvOptionPane.showMessageDialog(Desktop.desktop, msgPanel, + JvOptionPane.showMessageDialog(desktopPane, msgPanel, MessageManager .getString("label.SEQUENCE_ID_no_longer_used"), JvOptionPane.WARNING_MESSAGE); @@ -2700,11 +2697,11 @@ public class Desktop extends jalview.jbgui.GDesktop { if (Jalview.isHeadlessMode()) { - // Desktop.desktop is null in headless mode - return new AlignFrame[] { Jalview.currentAlignFrame }; + // Desktop.getDesktop() is null in headless mode + return new AlignFrame[] { Jalview.getCurrentAlignFrame() }; } - JInternalFrame[] frames = Desktop.desktop.getAllFrames(); + JInternalFrame[] frames = Desktop.getDesktopPane().getAllFrames(); if (frames == null) { @@ -2749,7 +2746,7 @@ public class Desktop extends jalview.jbgui.GDesktop */ public GStructureViewer[] getJmols() { - JInternalFrame[] frames = Desktop.desktop.getAllFrames(); + JInternalFrame[] frames = Desktop.getDesktopPane().getAllFrames(); if (frames == null) { @@ -2785,7 +2782,7 @@ public class Desktop extends jalview.jbgui.GDesktop } catch (Exception ex) { jalview.bin.Cache.log.error("Groovy Shell Creation failed.", ex); - JvOptionPane.showInternalMessageDialog(Desktop.desktop, + JvOptionPane.showInternalMessageDialog(desktopPane, MessageManager.getString("label.couldnt_create_groovy_shell"), MessageManager.getString("label.groovy_support_failed"), @@ -2796,7 +2793,7 @@ public class Desktop extends jalview.jbgui.GDesktop /** * Open the Groovy console */ - void openGroovyConsole() + private void openGroovyConsole() { if (groovyConsole == null) { @@ -2845,7 +2842,7 @@ public class Desktop extends jalview.jbgui.GDesktop { getRootPane().getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW) .put(KeyStroke.getKeyStroke(KeyEvent.VK_Q, - jalview.util.ShortcutKeyMaskExWrapper.getMenuShortcutKeyMaskEx()), + Toolkit.getDefaultToolkit().getMenuShortcutKeyMask()), "Quit"); getRootPane().getActionMap().put("Quit", new AbstractAction() { @@ -2904,18 +2901,18 @@ public class Desktop extends jalview.jbgui.GDesktop progressBarHandlers = new Hashtable<>(); } - if (progressBars.get(Long.valueOf(id)) != null) + if (progressBars.get(new Long(id)) != null) { - JPanel panel = progressBars.remove(Long.valueOf(id)); - if (progressBarHandlers.contains(Long.valueOf(id))) + JPanel panel = progressBars.remove(new Long(id)); + if (progressBarHandlers.contains(new Long(id))) { - progressBarHandlers.remove(Long.valueOf(id)); + progressBarHandlers.remove(new Long(id)); } removeProgressPanel(panel); } else { - progressBars.put(Long.valueOf(id), addProgressPanel(message)); + progressBars.put(new Long(id), addProgressPanel(message)); } } @@ -2930,13 +2927,13 @@ public class Desktop extends jalview.jbgui.GDesktop final IProgressIndicatorHandler handler) { if (progressBarHandlers == null - || !progressBars.containsKey(Long.valueOf(id))) + || !progressBars.containsKey(new Long(id))) { throw new Error(MessageManager.getString( "error.call_setprogressbar_before_registering_handler")); } - progressBarHandlers.put(Long.valueOf(id), handler); - final JPanel progressPanel = progressBars.get(Long.valueOf(id)); + progressBarHandlers.put(new Long(id), handler); + final JPanel progressPanel = progressBars.get(new Long(id)); if (handler.canCancel()) { JButton cancel = new JButton( @@ -2982,7 +2979,7 @@ public class Desktop extends jalview.jbgui.GDesktop */ public static AlignFrame getAlignFrameFor(AlignViewportI viewport) { - if (desktop != null) + if (getDesktopPane() != null) { AlignmentPanel[] aps = getAlignmentPanels( viewport.getSequenceSetId()); @@ -3043,8 +3040,8 @@ public class Desktop extends jalview.jbgui.GDesktop // todo: changesupport handlers need to be transferred if (discoverer == null) { - discoverer = new jalview.ws.jws1.Discoverer(); - // register PCS handler for desktop. + discoverer = Discoverer.getInstance(); + // register PCS handler for getDesktop(). discoverer.addPropertyChangeListener(changeSupport); } // JAL-940 - disabled JWS1 service configuration - always start discoverer @@ -3054,7 +3051,7 @@ public class Desktop extends jalview.jbgui.GDesktop if (Cache.getDefault("SHOW_JWS2_SERVICES", true)) { - t2 = jalview.ws.jws2.Jws2Discoverer.getDiscoverer() + t2 = jalview.ws.jws2.Jws2Discoverer.getInstance() .startDiscoverer(changeSupport); } Thread t3 = null; @@ -3087,7 +3084,7 @@ public class Desktop extends jalview.jbgui.GDesktop { if (evt.getNewValue() == null || evt.getNewValue() instanceof Vector) { - final String ermsg = jalview.ws.jws2.Jws2Discoverer.getDiscoverer() + final String ermsg = jalview.ws.jws2.Jws2Discoverer.getInstance() .getErrorMessages(); if (ermsg != null) { @@ -3126,7 +3123,7 @@ public class Desktop extends jalview.jbgui.GDesktop * * jd.waitForInput(); */ - JvOptionPane.showConfirmDialog(Desktop.desktop, + JvOptionPane.showConfirmDialog(Desktop.getDesktopPane(), new JLabel("
    " + ermsg + "
    " + "

    It may be that you have invalid JABA URLs
    in your web service preferences," @@ -3152,7 +3149,7 @@ public class Desktop extends jalview.jbgui.GDesktop } } - private Runnable serviceChangedDialog = null; + Runnable serviceChangedDialog = null; /** * start a thread to open a URL in the configured browser. Pops up a warning @@ -3163,7 +3160,7 @@ public class Desktop extends jalview.jbgui.GDesktop */ public static void showUrl(final String url) { - showUrl(url, Desktop.instance); + showUrl(url, Desktop.getInstance()); } /** @@ -3189,10 +3186,10 @@ public class Desktop extends jalview.jbgui.GDesktop .formatMessage("status.opening_params", new Object[] { url }), this.hashCode()); } - jalview.util.BrowserLauncher.openURL(url); + BrowserLauncher.openURL(url); } catch (Exception ex) { - JvOptionPane.showInternalMessageDialog(Desktop.desktop, + JvOptionPane.showInternalMessageDialog(Desktop.getDesktopPane(), MessageManager .getString("label.web_browser_not_found_unix"), MessageManager.getString("label.web_browser_not_found"), @@ -3208,15 +3205,16 @@ public class Desktop extends jalview.jbgui.GDesktop }).start(); } - public static WsParamSetManager wsparamManager = null; + private WsParamSetManager wsparamManager = null; public static ParamManager getUserParameterStore() { - if (wsparamManager == null) + Desktop d = Desktop.getInstance(); + if (d.wsparamManager == null) { - wsparamManager = new WsParamSetManager(); + d.wsparamManager = new WsParamSetManager(); } - return wsparamManager; + return d.wsparamManager; } /** @@ -3261,14 +3259,16 @@ public class Desktop extends jalview.jbgui.GDesktop /** * flag indicating if dialogExecutor should try to acquire a permit */ - private volatile boolean dialogPause = true; + volatile boolean dialogPause = true; /** * pause the queue */ - private java.util.concurrent.Semaphore block = new Semaphore(0); + java.util.concurrent.Semaphore block = new Semaphore(0); + + private groovy.ui.Console groovyConsole; - private static groovy.ui.Console groovyConsole; + public StructureViewer lastTargetedView; /** * add another dialog thread to the queue @@ -3291,7 +3291,7 @@ public class Desktop extends jalview.jbgui.GDesktop { } } - if (instance == null) + if (instanceOnly) { return; } @@ -3455,7 +3455,7 @@ public class Desktop extends jalview.jbgui.GDesktop String topViewId = myTopFrame.viewport.getSequenceSetId(); String bottomViewId = myBottomFrame.viewport.getSequenceSetId(); - JInternalFrame[] frames = desktop.getAllFrames(); + JInternalFrame[] frames = desktopPane.getAllFrames(); for (JInternalFrame frame : frames) { if (frame instanceof SplitFrame && frame != source) @@ -3500,7 +3500,8 @@ public class Desktop extends jalview.jbgui.GDesktop public static groovy.ui.Console getGroovyConsole() { - return groovyConsole; + Desktop desktop = Desktop.getInstance(); + return desktop == null ? null : desktop.groovyConsole; } /** @@ -3518,6 +3519,7 @@ public class Desktop extends jalview.jbgui.GDesktop * - the payload from the drop event * @throws Exception */ + @SuppressWarnings("unchecked") public static void transferFromDropTarget(List files, List protocols, DropTargetDropEvent evt, Transferable t) throws Exception @@ -3587,7 +3589,7 @@ public class Desktop extends jalview.jbgui.GDesktop { // Works on Windows and MacOSX Cache.log.debug("Drop handled as javaFileListFlavor"); - for (Object file : (List) t + for (Object file : (List) t .getTransferData(DataFlavor.javaFileListFlavor)) { files.add(file); @@ -3751,7 +3753,7 @@ public class Desktop extends jalview.jbgui.GDesktop Class structureViewerClass) { List result = new ArrayList<>(); - JInternalFrame[] frames = Desktop.instance.getAllFrames(); + JInternalFrame[] frames = getAllFrames(); for (JInternalFrame frame : frames) { @@ -3770,4 +3772,5 @@ public class Desktop extends jalview.jbgui.GDesktop } return result; } + } diff --git a/src/jalview/gui/FeatureEditor.java b/src/jalview/gui/FeatureEditor.java index d547c58..4fe9a65 100644 --- a/src/jalview/gui/FeatureEditor.java +++ b/src/jalview/gui/FeatureEditor.java @@ -99,7 +99,12 @@ public class FeatureEditor * * @param alignPanel * @param seqs + * one or more Sequence if create is true; a singleton if create is + * false * @param feats + * a list of new SequenceFeature instances if create is true, + * otherwise a list of known features for this sequence at this + * position * @param create * if true create a new feature, else amend or delete an existing * feature @@ -222,7 +227,7 @@ public class FeatureEditor updateColourButton(mainPanel, colour, featureColour); }; }; - JalviewColourChooser.showColourChooser(Desktop.getDesktop(), + JalviewColourChooser.showColourChooser(Desktop.getDesktopPane(), title, featureColour.getColour(), listener); } else @@ -412,7 +417,7 @@ public class FeatureEditor * set dialog action handlers for OK (create/Amend) and Cancel options * also for Delete if applicable (when amending features) */ - JvOptionPane dialog = JvOptionPane.newOptionDialog(Desktop.desktop) + JvOptionPane dialog = JvOptionPane.newOptionDialog(Desktop.getDesktopPane()) .setResponseHandler(0, okAction).setResponseHandler(2, cancelAction); if (!forCreate) { @@ -482,6 +487,7 @@ public class FeatureEditor { boolean useLastDefaults = features.get(0).getType() == null; + @Override public void run() { final String enteredType = name.getText().trim(); @@ -538,6 +544,7 @@ public class FeatureEditor { Runnable deleteAction = new Runnable() { + @Override public void run() { SequenceFeature sf = features.get(featureIndex); @@ -646,6 +653,7 @@ public class FeatureEditor String featureGroup = group.getText(); + @Override public void run() { final String enteredType = name.getText().trim(); diff --git a/src/jalview/gui/FeatureRenderer.java b/src/jalview/gui/FeatureRenderer.java index 0553fef..61d3266 100644 --- a/src/jalview/gui/FeatureRenderer.java +++ b/src/jalview/gui/FeatureRenderer.java @@ -30,6 +30,7 @@ import java.awt.Color; */ public class FeatureRenderer extends jalview.renderer.seqfeatures.FeatureRenderer + implements jalview.api.FeatureRenderer { Color resBoxColour; @@ -44,11 +45,10 @@ public class FeatureRenderer { super(alignPanel.av); this.ap = alignPanel; - if (alignPanel.getSeqPanel() != null - && alignPanel.getSeqPanel().seqCanvas != null - && alignPanel.getSeqPanel().seqCanvas.fr != null) + SeqPanel sp = alignPanel.getSeqPanel(); + if (sp != null && sp.seqCanvas != null && sp.seqCanvas.fr != null) { - transferSettings(alignPanel.getSeqPanel().seqCanvas.fr); + transferSettings(sp.seqCanvas.fr); } } } diff --git a/src/jalview/gui/FeatureSettings.java b/src/jalview/gui/FeatureSettings.java index 9fe2e92..f81ecce 100644 --- a/src/jalview/gui/FeatureSettings.java +++ b/src/jalview/gui/FeatureSettings.java @@ -705,7 +705,7 @@ public class FeatureSettings extends JPanel data[dataIndex][FILTER_COLUMN] = featureFilter == null ? new FeatureMatcherSet() : featureFilter; - data[dataIndex][SHOW_COLUMN] = Boolean.valueOf( + data[dataIndex][SHOW_COLUMN] = new Boolean( af.getViewport().getFeaturesDisplayed().isVisible(type)); dataIndex++; displayableTypes.remove(type); @@ -732,7 +732,7 @@ public class FeatureSettings extends JPanel data[dataIndex][FILTER_COLUMN] = featureFilter == null ? new FeatureMatcherSet() : featureFilter; - data[dataIndex][SHOW_COLUMN] = Boolean.valueOf(true); + data[dataIndex][SHOW_COLUMN] = new Boolean(true); dataIndex++; displayableTypes.remove(type); } diff --git a/src/jalview/gui/FeatureTypeSettings.java b/src/jalview/gui/FeatureTypeSettings.java index cbfe80f..c3887ff 100644 --- a/src/jalview/gui/FeatureTypeSettings.java +++ b/src/jalview/gui/FeatureTypeSettings.java @@ -22,7 +22,6 @@ package jalview.gui; import jalview.api.AlignmentViewPanel; import jalview.api.FeatureColourI; -import jalview.bin.Cache; import jalview.datamodel.GraphLine; import jalview.datamodel.features.FeatureAttributes; import jalview.datamodel.features.FeatureAttributes.Datatype; @@ -40,6 +39,7 @@ import java.awt.BorderLayout; import java.awt.Color; import java.awt.Dimension; import java.awt.FlowLayout; +import java.awt.Graphics; import java.awt.GridLayout; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; @@ -64,7 +64,6 @@ import javax.swing.JPanel; import javax.swing.JRadioButton; import javax.swing.JSlider; import javax.swing.JTextField; -import javax.swing.border.EmptyBorder; import javax.swing.border.LineBorder; import javax.swing.event.ChangeEvent; import javax.swing.event.ChangeListener; @@ -165,7 +164,7 @@ public class FeatureTypeSettings extends JalviewDialog JPanel maxColour = new JPanel(); - private JComboBox threshold = new JComboBox<>(); + private JComboBox threshold = new JComboBox<>(); JSlider slider = new JSlider(); @@ -182,17 +181,17 @@ public class FeatureTypeSettings extends JalviewDialog /* * choice of option for 'colour for no value' */ - private JComboBox noValueCombo; + private JComboBox noValueCombo; /* * choice of what to colour by text (Label or attribute) */ - private JComboBox colourByTextCombo; + private JComboBox colourByTextCombo; /* * choice of what to colour by range (Score or attribute) */ - private JComboBox colourByRangeCombo; + private JComboBox colourByRangeCombo; private JRadioButton andFilters; @@ -1122,7 +1121,7 @@ public class FeatureTypeSettings extends JalviewDialog * @param withRange * @param withText */ - protected JComboBox populateAttributesDropdown( + protected JComboBox populateAttributesDropdown( List attNames, boolean withRange, boolean withText) { List displayAtts = new ArrayList<>(); @@ -1161,11 +1160,9 @@ public class FeatureTypeSettings extends JalviewDialog tooltips.add(desc == null ? "" : desc); } - // now convert String List to Object List for buildComboWithTooltips - List displayAttsObjects = new ArrayList<>(displayAtts); - JComboBox attCombo = JvSwingUtils - .buildComboWithTooltips(displayAttsObjects, tooltips); - + JComboBox attCombo = JvSwingUtils + .buildComboWithTooltips(displayAtts, tooltips); + return attCombo; } @@ -1343,8 +1340,8 @@ public class FeatureTypeSettings extends JalviewDialog * drop-down choice of attribute, with description as a tooltip * if we can obtain it */ - final JComboBox attCombo = populateAttributesDropdown(attNames, - true, true); + JComboBox attCombo = populateAttributesDropdown(attNames, true, + true); String filterBy = setSelectedAttribute(attCombo, filter); JComboBox condCombo = new JComboBox<>(); @@ -1445,13 +1442,20 @@ public class FeatureTypeSettings extends JalviewDialog if (!patternField.isEnabled() || (pattern != null && pattern.trim().length() > 0)) { - JButton removeCondition = new JButton("\u2717"); // Dingbats cursive x - removeCondition.setBorder(new EmptyBorder(0, 0, 0, 0)); + JButton removeCondition = new JButton("\u2717") + { + @Override + public void paint(Graphics g) + { + g.setColor(Color.black); + g.drawString("\u2717", 2, 14); // Dingbats cursive x + } + }; removeCondition.setBackground(Color.WHITE); + removeCondition.setOpaque(true); removeCondition.setPreferredSize(new Dimension(23, 17)); - removeCondition.setToolTipText( - MessageManager.getString("label.delete_condition")); - removeCondition.setBorder(new EmptyBorder(0, 0, 0, 0)); + removeCondition + .setToolTipText(MessageManager.getString("label.delete_row")); removeCondition.addActionListener(new ActionListener() { @Override @@ -1474,7 +1478,7 @@ public class FeatureTypeSettings extends JalviewDialog * @param attCombo * @param filter */ - private String setSelectedAttribute(JComboBox attCombo, + private String setSelectedAttribute(JComboBox attCombo, FeatureMatcherI filter) { String item = null; @@ -1691,19 +1695,11 @@ public class FeatureTypeSettings extends JalviewDialog * @param valueField * @param filterIndex */ - protected boolean updateFilter(JComboBox attCombo, + protected boolean updateFilter(JComboBox attCombo, JComboBox condCombo, JTextField valueField, int filterIndex) { - String attName; - try - { - attName = (String) attCombo.getSelectedItem(); - } catch (Exception e) - { - Cache.log.error("Problem casting Combo box entry to String"); - attName = attCombo.getSelectedItem().toString(); - } + String attName = (String) attCombo.getSelectedItem(); Condition cond = (Condition) condCombo.getSelectedItem(); String pattern = valueField.getText().trim(); diff --git a/src/jalview/gui/Finder.java b/src/jalview/gui/Finder.java index a1693f7..2a6adda 100755 --- a/src/jalview/gui/Finder.java +++ b/src/jalview/gui/Finder.java @@ -176,7 +176,7 @@ public class Finder extends GFinder */ boolean getFocusedViewport() { - if (focusfixed || Desktop.desktop == null) + if (focusfixed || Desktop.getDesktopPane() == null) { if (ap != null && av != null) { @@ -187,7 +187,7 @@ public class Finder extends GFinder } // now checks further down the window stack to fix bug // https://mantis.lifesci.dundee.ac.uk/view.php?id=36008 - JInternalFrame[] frames = Desktop.desktop.getAllFrames(); + JInternalFrame[] frames = Desktop.getDesktopPane().getAllFrames(); for (int f = 0; f < frames.length; f++) { JInternalFrame alignFrame = frames[f]; diff --git a/src/jalview/gui/FontChooser.java b/src/jalview/gui/FontChooser.java index 92cc4c6..9bb133c 100755 --- a/src/jalview/gui/FontChooser.java +++ b/src/jalview/gui/FontChooser.java @@ -215,7 +215,11 @@ public class FontChooser extends GFontChooser { if (ap.getOverviewPanel() != null) { - ap.getOverviewPanel().updateOverviewImage(); + // changes size of rectangle + // BH 2019.07.29 -- updateOverviewImage forces a redraw, but all we are + // doing is changing the box size. + + ap.getOverviewPanel().repaint();// updateOverviewImage(); } } } @@ -408,10 +412,10 @@ public class FontChooser extends GFontChooser @Override public void defaultButton_actionPerformed() { - Cache.setProperty("FONT_NAME", fontName.getSelectedItem().toString()); - Cache.setProperty("FONT_STYLE", fontStyle.getSelectedIndex() + ""); - Cache.setProperty("FONT_SIZE", fontSize.getSelectedItem().toString()); - Cache.setProperty("ANTI_ALIAS", + Cache.setProperty(Preferences.FONT_NAME, fontName.getSelectedItem().toString()); + Cache.setProperty(Preferences.FONT_STYLE, fontStyle.getSelectedIndex() + ""); + Cache.setProperty(Preferences.FONT_SIZE, fontSize.getSelectedItem().toString()); + Cache.setProperty(Preferences.ANTI_ALIAS, Boolean.toString(smoothFont.isSelected())); Cache.setProperty(Preferences.SCALE_PROTEIN_TO_CDNA, Boolean.toString(scaleAsCdna.isSelected())); diff --git a/src/jalview/gui/IdCanvas.java b/src/jalview/gui/IdCanvas.java index 4057cef..e5a5946 100755 --- a/src/jalview/gui/IdCanvas.java +++ b/src/jalview/gui/IdCanvas.java @@ -579,21 +579,45 @@ public class IdCanvas extends JPanel implements ViewportListenerI @Override public void propertyChange(PropertyChangeEvent evt) { + // BH just clarifying logic String propertyName = evt.getPropertyName(); - if (propertyName.equals(ViewportRanges.STARTSEQ) - || (av.getWrapAlignment() - && propertyName.equals(ViewportRanges.STARTRES))) - { + switch (propertyName) { + case ViewportRanges.STARTSEQ: fastPaint((int) evt.getNewValue() - (int) evt.getOldValue()); - } - else if (propertyName.equals(ViewportRanges.STARTRESANDSEQ)) - { + return; + case ViewportRanges.STARTRES: + if (av.getWrapAlignment()) + { + fastPaint((int) evt.getNewValue() - (int) evt.getOldValue()); + } + return; + case ViewportRanges.STARTRESANDSEQ: fastPaint(((int[]) evt.getNewValue())[1] - ((int[]) evt.getOldValue())[1]); - } - else if (propertyName.equals(ViewportRanges.MOVE_VIEWPORT)) - { + return; + case ViewportRanges.MOVE_VIEWPORT: repaint(); + return; + case ViewportRanges.ENDRES: + case ViewportRanges.ENDSEQ: + // ignore ?? + return; } +// BH 2019.07.27 was: +// if (propertyName.equals(ViewportRanges.STARTSEQ) +// || (av.getWrapAlignment() +// && propertyName.equals(ViewportRanges.STARTRES))) +// { +// fastPaint((int) evt.getNewValue() - (int) evt.getOldValue()); +// } +// else if (propertyName.equals(ViewportRanges.STARTRESANDSEQ)) +// { +// fastPaint(((int[]) evt.getNewValue())[1] +// - ((int[]) evt.getOldValue())[1]); +// } +// else if (propertyName.equals(ViewportRanges.MOVE_VIEWPORT)) +// { +// repaint(); + // } } } diff --git a/src/jalview/gui/IdPanel.java b/src/jalview/gui/IdPanel.java index 6b312ad..dadf25a 100755 --- a/src/jalview/gui/IdPanel.java +++ b/src/jalview/gui/IdPanel.java @@ -246,7 +246,7 @@ public class IdPanel extends JPanel jalview.util.BrowserLauncher.openURL(url); } catch (Exception ex) { - JvOptionPane.showInternalMessageDialog(Desktop.desktop, + JvOptionPane.showInternalMessageDialog(Desktop.getDesktopPane(), MessageManager.getString("label.web_browser_not_found_unix"), MessageManager.getString("label.web_browser_not_found"), JvOptionPane.WARNING_MESSAGE); @@ -456,7 +456,8 @@ public class IdPanel extends JPanel } PopupMenu pop = new PopupMenu(alignPanel, sq, features, - Preferences.getGroupURLLinks()); + Preferences.getGroupURLLinks() // empty list; not implemented + ); pop.show(this, e.getX(), e.getY()); } diff --git a/src/jalview/gui/IdwidthAdjuster.java b/src/jalview/gui/IdwidthAdjuster.java index 0cffc3b..2c273ad 100755 --- a/src/jalview/gui/IdwidthAdjuster.java +++ b/src/jalview/gui/IdwidthAdjuster.java @@ -24,10 +24,8 @@ import jalview.api.AlignViewportI; import java.awt.Color; import java.awt.Cursor; -import java.awt.Graphics; +import java.awt.event.MouseAdapter; import java.awt.event.MouseEvent; -import java.awt.event.MouseListener; -import java.awt.event.MouseMotionListener; import javax.swing.JPanel; @@ -37,157 +35,77 @@ import javax.swing.JPanel; * @author $author$ * @version $Revision$ */ +@SuppressWarnings("serial") public class IdwidthAdjuster extends JPanel - implements MouseListener, MouseMotionListener { - boolean active = false; int oldX = 0; - AlignmentPanel ap; - /** - * Creates a new IdwidthAdjuster object. + * Creates a new IdwidthAdjuster object above the id panel that can be dragged + * to change the panel's width * * @param ap - * DOCUMENT ME! - */ - public IdwidthAdjuster(AlignmentPanel ap) - { - this.ap = ap; - setBackground(Color.white); - addMouseListener(this); - addMouseMotionListener(this); - } - - /** - * DOCUMENT ME! - * - * @param evt - * DOCUMENT ME! - */ - @Override - public void mousePressed(MouseEvent evt) - { - oldX = evt.getX(); - } - - /** - * DOCUMENT ME! - * - * @param evt - * DOCUMENT ME! - */ - @Override - public void mouseReleased(MouseEvent evt) - { - active = false; - repaint(); - - /* - * If in a SplitFrame with co-scaled alignments, set the other's id width to - * match - */ - final AlignViewportI viewport = ap.getAlignViewport(); - if (viewport.getCodingComplement() != null - && viewport.isScaleProteinAsCdna()) - { - viewport.getCodingComplement().setIdWidth(viewport.getIdWidth()); - SplitFrame sf = (SplitFrame) ap.alignFrame.getSplitViewContainer(); - sf.repaint(); - } - - } - - /** - * DOCUMENT ME! - * - * @param evt - * DOCUMENT ME! - */ - @Override - public void mouseEntered(MouseEvent evt) - { - active = true; - repaint(); - } - - /** - * DOCUMENT ME! + * The associated AlignmentPanel * - * @param evt - * DOCUMENT ME! */ - @Override - public void mouseExited(MouseEvent evt) - { - active = false; - repaint(); - } - - /** - * DOCUMENT ME! - * - * @param evt - * DOCUMENT ME! - */ - @Override - public void mouseDragged(MouseEvent evt) + public IdwidthAdjuster(AlignmentPanel ap) { - active = true; + // BH 2019.07.01 no need for overridden paintComponent, especially as it was + // overriding paint(g) so + // allowing strange component painting in its place. - final AlignViewportI viewport = ap.getAlignViewport(); - int curwidth = viewport.getIdWidth(); - int dif = evt.getX() - oldX; - - final int newWidth = curwidth + dif; - if ((newWidth > 20) || (dif > 0)) - { - viewport.setIdWidth(newWidth); - - ap.paintAlignment(true, false); - } - - oldX = evt.getX(); - } - - /** - * DOCUMENT ME! - * - * @param evt - * DOCUMENT ME! - */ - @Override - public void mouseMoved(MouseEvent evt) - { - } + setBackground(Color.white); + setOpaque(true); - /** - * DOCUMENT ME! - * - * @param evt - * DOCUMENT ME! - */ - @Override - public void mouseClicked(MouseEvent evt) - { - } + setCursor(Cursor.getPredefinedCursor(Cursor.W_RESIZE_CURSOR)); - /** - * DOCUMENT ME! - * - * @param g - * DOCUMENT ME! - */ - @Override - public void paintComponent(Graphics g) - { - g.setColor(Color.white); - g.fillRect(0, 0, getWidth(), getHeight()); + // BH 2019.07.01 MouseAdapter is cleaner - no need for fields active or ap - if (active) + MouseAdapter ma = (new MouseAdapter() { - setCursor(Cursor.getPredefinedCursor(Cursor.W_RESIZE_CURSOR)); - } + @Override + public void mousePressed(MouseEvent evt) + { + oldX = evt.getX(); + } + + @Override + public void mouseDragged(MouseEvent evt) + { + AlignViewportI viewport = ap.getAlignViewport(); + int curwidth = viewport.getIdWidth(); + int dif = evt.getX() - oldX; + int newWidth = curwidth + dif; + if ((newWidth > 20) || (dif > 0)) + { + viewport.setIdWidth(newWidth); + ap.paintAlignment(true, false); + } + oldX = evt.getX(); + } + + @Override + public void mouseReleased(MouseEvent evt) + { + + // If in a SplitFrame with co-scaled alignments, set the other's id + // width to match + + AlignViewportI viewport = ap.getAlignViewport(); + if (viewport.getCodingComplement() != null + && viewport.isScaleProteinAsCdna()) + { + viewport.getCodingComplement().setIdWidth(viewport.getIdWidth()); + SplitFrame sf = (SplitFrame) ap.alignFrame + .getSplitViewContainer(); + sf.repaint(); + } + + } + + }); + addMouseListener(ma); + addMouseMotionListener(ma); } } diff --git a/src/jalview/gui/JalviewAppender.java b/src/jalview/gui/JalviewAppender.java index 1d7064b..c1140a1 100644 --- a/src/jalview/gui/JalviewAppender.java +++ b/src/jalview/gui/JalviewAppender.java @@ -33,17 +33,20 @@ import org.apache.log4j.spi.LoggingEvent; public class JalviewAppender extends WriterAppender { - static private JTextArea jTextArea = null; + // BH 2019 was static + + private JTextArea jTextArea = null; /** Set the target JTextArea for the logging information to appear. */ - static public void setTextArea(JTextArea jTextArea) + public void setTextArea(JTextArea jTextArea) { - JalviewAppender.jTextArea = jTextArea; + this.jTextArea = jTextArea; } /** * Format and then append the loggingEvent to the stored JTextArea. */ + @Override public void append(LoggingEvent loggingEvent) { final String message = this.layout.format(loggingEvent); @@ -51,6 +54,7 @@ public class JalviewAppender extends WriterAppender // Append formatted message to textarea using the Swing Thread. SwingUtilities.invokeLater(new Runnable() { + @Override public void run() { if (jTextArea != null) diff --git a/src/jalview/gui/JalviewDialog.java b/src/jalview/gui/JalviewDialog.java index 1d7bf3d..eb69230 100644 --- a/src/jalview/gui/JalviewDialog.java +++ b/src/jalview/gui/JalviewDialog.java @@ -77,12 +77,12 @@ public abstract class JalviewDialog extends JPanel protected void initDialogFrame(Container content, boolean modal, boolean block, String title, int width, int height) { - - frame = new JDialog(Desktop.instance, modal); + Desktop desktop = Desktop.getInstance(); + frame = new JDialog(desktop, modal); frame.setTitle(title); - if (Desktop.instance != null) + if (desktop != null) { - Rectangle deskr = Desktop.instance.getBounds(); + Rectangle deskr = desktop.getBounds(); frame.setBounds(new Rectangle((int) (deskr.getCenterX() - width / 2), (int) (deskr.getCenterY() - height / 2), width, height)); } diff --git a/src/jalview/gui/JvSwingUtils.java b/src/jalview/gui/JvSwingUtils.java index 41287d2..7dd8e6c 100644 --- a/src/jalview/gui/JvSwingUtils.java +++ b/src/jalview/gui/JvSwingUtils.java @@ -56,12 +56,16 @@ import javax.swing.border.TitledBorder; */ public final class JvSwingUtils { + public static final String HTML_PREFIX = "
    "; + + /** * wrap a bare html safe string to around 60 characters per line using a CSS * style class specifying word-wrap and break-word * * @param enclose - * if true, add <html> wrapper tags + * if true, add <html> wrapper tags (currently false for only + * two references -- both in Jws2Discoverer -- * @param ttext * * @return @@ -72,8 +76,19 @@ public final class JvSwingUtils "Tootip text to format must not be null!"); ttext = ttext.trim(); boolean maxLengthExceeded = false; - - if (ttext.contains("
    ")) + boolean isHTML = ttext.startsWith(""); + if (isHTML) + { + ttext = ttext.substring(6); + } + if (ttext.endsWith("")) + { + isHTML = true; + ttext = ttext.substring(0, ttext.length() - 7); + } + boolean hasBR = ttext.contains("
    "); + enclose |= isHTML || hasBR; + if (hasBR) { String[] htmllines = ttext.split("
    "); for (String line : htmllines) @@ -94,21 +109,12 @@ public final class JvSwingUtils { return enclose ? "" + ttext + "" : ttext; } - - return (enclose ? "" : "") - - // BH 2018 - - + "
    " - -// + "

    " - + // BH 2018,2019 + return (enclose + ? HTML_PREFIX + ttext - - + "

    " -// + "

    " - + ((enclose ? "" : "")); + + "
    " + : ttext); } @@ -330,13 +336,13 @@ public final class JvSwingUtils * @param entries * @param tooltips */ - public static JComboBox buildComboWithTooltips( - List entries, List tooltips) + public static JComboBox buildComboWithTooltips( + List entries, List tooltips) { - JComboBox combo = new JComboBox<>(); + JComboBox combo = new JComboBox<>(); final ComboBoxTooltipRenderer renderer = new ComboBoxTooltipRenderer(); combo.setRenderer(renderer); - for (Object attName : entries) + for (String attName : entries) { combo.addItem(attName); } diff --git a/src/jalview/gui/LineartOptions.java b/src/jalview/gui/LineartOptions.java index d55733c..62bdd35 100644 --- a/src/jalview/gui/LineartOptions.java +++ b/src/jalview/gui/LineartOptions.java @@ -86,7 +86,7 @@ public class LineartOptions extends JPanel ex.printStackTrace(); } - dialog = JvOptionPane.newOptionDialog(Desktop.desktop); + dialog = JvOptionPane.newOptionDialog(Desktop.getDesktopPane()); } /** @@ -188,7 +188,7 @@ public class LineartOptions extends JPanel } else { - Cache.applicationProperties.remove(preferencesKey); + Cache.removePropertyNoSave(preferencesKey); } } diff --git a/src/jalview/gui/MenuChooser.java b/src/jalview/gui/MenuChooser.java deleted file mode 100644 index 0e42a7a..0000000 --- a/src/jalview/gui/MenuChooser.java +++ /dev/null @@ -1,99 +0,0 @@ -/* - * Jalview - A Sequence Alignment Editor and Viewer ($$Version-Rel$$) - * Copyright (C) $$Year-Rel$$ The Jalview Authors - * - * This file is part of Jalview. - * - * Jalview is free software: you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation, either version 3 - * of the License, or (at your option) any later version. - * - * Jalview is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty - * of MERCHANTABILITY or FITNESS FOR A PARTICULAR - * PURPOSE. See the GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with Jalview. If not, see . - * The Jalview Authors are detailed in the 'AUTHORS' file. - */ -package jalview.gui; - -import java.awt.BorderLayout; -import java.awt.Color; -import java.awt.event.ActionEvent; -import java.awt.event.ActionListener; - -import javax.swing.JButton; -import javax.swing.JFrame; -import javax.swing.JLabel; -import javax.swing.JPanel; - -public class MenuChooser implements ActionListener -{ - public static boolean protein; - - private JFrame choosemenu = new JFrame("Animation"); - - private JButton bouton = new JButton("bouton 1"); - - private JButton bouton2 = new JButton("bouton 2"); - - private JPanel container = new JPanel(); - - private JLabel label = new JLabel("Le JLabel"); - - public MenuChooser() - { - - choosemenu.setSize(300, 300); - choosemenu.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE); - choosemenu.setLocationRelativeTo(null); - - container.setBackground(Color.white); - container.setLayout(new BorderLayout()); - - // On ajoute notre Fenetre à la liste des auditeurs de notre Bouton - bouton.addActionListener(this); - bouton2.addActionListener(this); - - JPanel south = new JPanel(); - south.add(bouton); - south.add(bouton2); - container.add(south, BorderLayout.SOUTH); - - // On change la couleur de police - label.setForeground(Color.blue); - // Et on change l'alignement du texte grâce aux attributs static de la - // classe JLabel - label.setHorizontalAlignment(JLabel.CENTER); - - container.add(label, BorderLayout.NORTH); - - choosemenu.setContentPane(container); - choosemenu.setVisible(true); - - } - - // ... - - // ******************************************************************************* - // LA VOILAAAAAAAAAAAAAA - // ******************************************************************************* - /** - * C'est la méthode qui sera appelée lors d'un clic sur notre bouton - */ - public void actionPerformed(ActionEvent arg0) - { - - if (arg0.getSource() == bouton) - protein = false; - label.setText("RNA menu"); - - if (arg0.getSource() == bouton2) - label.setText("Protein menu"); - protein = true; - } - -} diff --git a/src/jalview/gui/OOMWarning.java b/src/jalview/gui/OOMWarning.java index 02c8fe1..dc5d0f5 100644 --- a/src/jalview/gui/OOMWarning.java +++ b/src/jalview/gui/OOMWarning.java @@ -72,7 +72,7 @@ public class OOMWarning implements Runnable public OOMWarning(String string, OutOfMemoryError oomerror) { - this(string, oomerror, Desktop.desktop); + this(string, oomerror, Desktop.getDesktopPane()); } @Override diff --git a/src/jalview/gui/OverviewCanvas.java b/src/jalview/gui/OverviewCanvas.java index ca27a9c..de55996 100644 --- a/src/jalview/gui/OverviewCanvas.java +++ b/src/jalview/gui/OverviewCanvas.java @@ -22,6 +22,7 @@ package jalview.gui; import jalview.api.AlignViewportI; import jalview.bin.Cache; +import jalview.datamodel.AlignmentI; import jalview.renderer.OverviewRenderer; import jalview.renderer.OverviewResColourFinder; import jalview.viewmodel.OverviewDimensions; @@ -33,6 +34,7 @@ import java.awt.image.BufferedImage; import javax.swing.JPanel; +@SuppressWarnings("serial") public class OverviewCanvas extends JPanel { private static final Color TRANS_GREY = new Color(100, 100, 100, 25); @@ -43,11 +45,9 @@ public class OverviewCanvas extends JPanel private volatile boolean updaterunning = false; - private boolean dispose = false; + private boolean disposed = false; - private BufferedImage miniMe; - - private BufferedImage lastMiniMe = null; + BufferedImage lastMiniMe = null; // Can set different properties in this seqCanvas than // main visible SeqCanvas @@ -65,13 +65,26 @@ public class OverviewCanvas extends JPanel private ProgressPanel progressPanel; - public OverviewCanvas(OverviewDimensions overviewDims, + private boolean showSequenceFeatures; + + private boolean showAnnotation; + + private jalview.api.FeatureRenderer featureRenderer; + + private OverviewPanel panel; + + private boolean showProgress; + + public OverviewCanvas(OverviewPanel panel, + OverviewDimensions overviewDims, AlignViewportI alignvp, ProgressPanel pp) { + this.panel = panel; od = overviewDims; + lastMiniMe = null; av = alignvp; progressPanel = pp; - + showProgress = (pp != null); sr = new SequenceRenderer(av); sr.renderGaps = false; fr = new jalview.renderer.seqfeatures.FeatureRenderer(av); @@ -84,6 +97,7 @@ public class OverviewCanvas extends JPanel cf = new OverviewResColourFinder(useLegacy, gapCol, hiddenCol); setSize(od.getWidth(), od.getHeight()); + setPreferredSize(getSize()); // BH 2019.07.29 added } /** @@ -95,6 +109,7 @@ public class OverviewCanvas extends JPanel public void resetOviewDims(OverviewDimensions overviewDims) { od = overviewDims; + lastMiniMe = null; } /** @@ -107,20 +122,27 @@ public class OverviewCanvas extends JPanel { if (updaterunning) { - restart = true; - if (or != null) - { - or.setRedraw(true); - } + setRestart("restartDraw"); } else { updaterunning = true; + restart = false; } return restart; } } + private void setRestart(String why) + { + // System.out.println("OC restart true " + why); + restart = true; + if (or != null) + { + or.setRedraw(true); + } + } + /** * Draw the overview sequences * @@ -128,145 +150,173 @@ public class OverviewCanvas extends JPanel * true if sequence features are to be shown * @param showAnnotation * true if the annotation is to be shown - * @param transferRenderer + * @param featureRenderer * the renderer to transfer feature colouring from */ public void draw(boolean showSequenceFeatures, boolean showAnnotation, - FeatureRenderer transferRenderer) + jalview.api.FeatureRenderer featureRenderer) { - miniMe = null; - + this.showSequenceFeatures = showSequenceFeatures; + this.showAnnotation = showAnnotation; + this.featureRenderer = featureRenderer; if (showSequenceFeatures) { - fr.transferSettings(transferRenderer); + fr.transferSettings(featureRenderer); } - setPreferredSize(new Dimension(od.getWidth(), od.getHeight())); + AlignmentI al = av.getAlignment(); + or = new OverviewRenderer(panel.ap, fr, od, al, av.getResidueShading(), + cf, showProgress); + if (showProgress) + { + or.addPropertyChangeListener(progressPanel); + } + or.drawMiniMe(); + } - or = new OverviewRenderer(fr, od, av.getAlignment(), - av.getResidueShading(), cf); - - or.addPropertyChangeListener(progressPanel); - - miniMe = or.draw(od.getRows(av.getAlignment()), - od.getColumns(av.getAlignment())); - - Graphics mg = miniMe.getGraphics(); + synchronized void finalizeDraw(BufferedImage miniMe) + { - if (showAnnotation) + if (showProgress && or != null) { - mg.translate(0, od.getSequencesHeight()); - or.drawGraph(mg, av.getAlignmentConservationAnnotation(), - od.getGraphHeight(), od.getColumns(av.getAlignment())); - mg.translate(0, -od.getSequencesHeight()); + or.removePropertyChangeListener(progressPanel); } - - or.removePropertyChangeListener(progressPanel); - or = null; if (restart) { + or = null; restart = false; - if (!dispose) + if (!disposed) { - draw(showSequenceFeatures, showAnnotation, transferRenderer); + draw(showSequenceFeatures, showAnnotation, featureRenderer); } } else { + if (showAnnotation && or != null) + { + or.drawGraph(av.getAlignmentConservationAnnotation()); + } + or = null; updaterunning = false; lastMiniMe = miniMe; + repaint(); } } @Override public void paintComponent(Graphics g) { - //super.paintComponent(g); + int w = getWidth(); + int h = getHeight(); + if (w == 0 || od.getBoxWidth() <= 0) + { + // BH 2019.07.27 removes two unnecessary paints, since boxwidth can be -1 + // or 0 during early-stage painting + return; + } + + boolean drawMe = (lastMiniMe != null); if (restart) { - if (lastMiniMe == null) + if (drawMe) { - g.setColor(Color.white); - g.fillRect(0, 0, getWidth(), getHeight()); + g.drawImage(lastMiniMe, 0, 0, w, h, this); } else { - g.drawImage(lastMiniMe, 0, 0, getWidth(), getHeight(), this); + g.setColor(Color.white); + g.fillRect(0, 0, w, h); } g.setColor(TRANS_GREY); - g.fillRect(0, 0, getWidth(), getHeight()); + g.fillRect(0, 0, w, h); + drawMe = false; } - else if (lastMiniMe != null) + else if (drawMe) { // is this a resize? - if ((getWidth() > 0) && (getHeight() > 0) - && ((getWidth() != od.getWidth()) - || (getHeight() != od.getHeight()))) + if (w != od.getWidth() || h != od.getHeight()) { - // if there is annotation, scale the alignment and annotation - // separately - if (od.getGraphHeight() > 0 - && od.getSequencesHeight() > 0 // BH 2019 - ) - { - BufferedImage topImage = lastMiniMe.getSubimage(0, 0, - od.getWidth(), od.getSequencesHeight()); - BufferedImage bottomImage = lastMiniMe.getSubimage(0, - od.getSequencesHeight(), od.getWidth(), - od.getGraphHeight()); - - // must be done at this point as we rely on using old width/height - // above, and new width/height below - od.setWidth(getWidth()); - od.setHeight(getHeight()); - - // stick the images back together so lastMiniMe is consistent in the - // event of a repaint - BUT probably not thread safe - lastMiniMe = new BufferedImage(od.getWidth(), od.getHeight(), - BufferedImage.TYPE_INT_RGB); - Graphics lg = lastMiniMe.getGraphics(); - lg.drawImage(topImage, 0, 0, od.getWidth(), - od.getSequencesHeight(), null); - lg.drawImage(bottomImage, 0, od.getSequencesHeight(), - od.getWidth(), od.getGraphHeight(), this); - lg.dispose(); - } - else - { - od.setWidth(getWidth()); - od.setHeight(getHeight()); - } - - // make sure the box is in the right place - od.setBoxPosition(av.getAlignment().getHiddenSequences(), - av.getAlignment().getHiddenColumns()); + + lastMiniMe = null; + return; + // // if there is annotation, scale the alignment and annotation + // // separately + // if (od.getGraphHeight() <= 0 && od.getSequencesHeight() <= 0) + // { + // od.setWidth(w); + // od.setHeight(h); + // return; + // } + // try + // { + // BufferedImage topImage = lastMiniMe.getSubimage(0, 0, + // od.getWidth(), od.getSequencesHeight()); + // + // BufferedImage bottomImage = lastMiniMe.getSubimage(0, + // od.getSequencesHeight(), od.getWidth(), + // od.getGraphHeight()); + // + // // must be done at this point as we rely on using old width/height + // // above, and new width/height below + // od.setWidth(w); + // od.setHeight(h); + // + // // stick the images back together so lastMiniMe is consistent in the + // // event of a repaint - BUT probably not thread safe + // + // // right -- this fails with fast user action. + // + // lastMiniMe = new BufferedImage(w, h, BufferedImage.TYPE_INT_RGB); + // Graphics lg = lastMiniMe.getGraphics(); + // lg.drawImage(topImage, 0, 0, w, od.getSequencesHeight(), null); + // lg.drawImage(bottomImage, 0, od.getSequencesHeight(), w, + // od.getGraphHeight(), this); + // lg.dispose(); + // + // } catch (RasterFormatException e) + // { + // System.out.println("OC Raster Exception " + lastMiniMe.getWidth() + // + "/" + w + "," + lastMiniMe.getHeight() + "/" + h + " " + // + od.getSequencesHeight() + " " + od.getGraphHeight()); + // } + // BH 2019: removed -- this is now taken care of using vpbox in + // OverviewDimension + // // make sure the box is in the right place + // od.setBoxPosition(av.getAlignment().getHiddenSequences(), + // av.getAlignment().getHiddenColumns()); } - // fall back to normal behaviour - g.drawImage(lastMiniMe, 0, 0, getWidth(), getHeight(), this); } - else + + if (drawMe) { - g.drawImage(lastMiniMe, 0, 0, getWidth(), getHeight(), this); + g.drawImage(lastMiniMe, 0, 0, w, h, this); } - // draw the box g.setColor(Color.red); + // System.out.println("OC paintComponent nd=" + ndraw + " nr=" + nrepaint + // + " np=" + ++npaint); od.drawBox(g); } + // private int ndraw, npaint, nrepaint; + + // @Override + // public void repaint() + // { + // System.out.println("OC repaint " + (++nrepaint)); + // super.repaint(); + // } public void dispose() { - dispose = true; + disposed = true; od = null; + lastMiniMe = null; synchronized (this) { - restart = true; - if (or != null) - { - or.setRedraw(true); - } + setRestart("dispose"); } } + } diff --git a/src/jalview/gui/OverviewPanel.java b/src/jalview/gui/OverviewPanel.java index a5aaf7c..5694c3d 100755 --- a/src/jalview/gui/OverviewPanel.java +++ b/src/jalview/gui/OverviewPanel.java @@ -20,6 +20,8 @@ */ package jalview.gui; +import jalview.api.AlignViewportI; +import jalview.api.AlignmentViewPanel; import jalview.bin.Cache; import jalview.renderer.OverviewRenderer; import jalview.util.MessageManager; @@ -61,11 +63,11 @@ public class OverviewPanel extends JPanel { protected OverviewDimensions od; - private OverviewCanvas oviewCanvas; + OverviewCanvas canvas; - protected AlignViewport av; + protected AlignViewportI av; - private AlignmentPanel ap; + AlignmentViewPanel ap; protected JCheckBoxMenuItem displayToggle; @@ -75,71 +77,50 @@ public class OverviewPanel extends JPanel protected ProgressPanel progressPanel; + private Dimension dim; + + private boolean showProgress = !Platform.isJS(); // Jalview.getInstance().getShowStatus() + /** * Creates a new OverviewPanel object. * * @param alPanel * The alignment panel which is shown in the overview panel */ - public OverviewPanel(AlignmentPanel alPanel) + public OverviewPanel(AlignmentViewPanel alPanel, Dimension dim) { - this.av = alPanel.av; + this.av = alPanel.getAlignViewport(); this.ap = alPanel; + this.dim = dim; showHidden = Cache.getDefault(Preferences.SHOW_OV_HIDDEN_AT_START, false); - if (showHidden) - { - od = new OverviewDimensionsShowHidden(av.getRanges(), - (av.isShowAnnotation() - && av.getAlignmentConservationAnnotation() != null)); - } - else - { - od = new OverviewDimensionsHideHidden(av.getRanges(), - (av.isShowAnnotation() - && av.getAlignmentConservationAnnotation() != null)); - } - + createOverviewDimensions(); setLayout(new BorderLayout()); progressPanel = new ProgressPanel(OverviewRenderer.UPDATE, MessageManager.getString("label.oview_calc"), getWidth()); - this.add(progressPanel, BorderLayout.SOUTH); - oviewCanvas = new OverviewCanvas(od, av, progressPanel); - - add(oviewCanvas, BorderLayout.CENTER); + if (showProgress) // BH 2019 + { + add(progressPanel, BorderLayout.SOUTH); + } + canvas = new OverviewCanvas(this, od, av, + showProgress ? progressPanel : null); + canvas.setPreferredSize(canvas.getSize()); + add(canvas, BorderLayout.CENTER); av.getRanges().addPropertyChangeListener(this); // without this the overview window does not size to fit the overview canvas - setPreferredSize(new Dimension(od.getWidth(), od.getHeight())); - + // BH - no,no! - This does not include the progressPanel! + // BH the problem was that OverviewCanvas.setPreferredSize() had not been set. + // setPreferredSize(new Dimension(od.getWidth(), od.getHeight())); + addComponentListener(new ComponentAdapter() { @Override public void componentResized(ComponentEvent evt) { - // Resize is called on the initial display of the overview. - // This code adjusts sizes to account for the progress bar if it has not - // already been accounted for, which triggers another resize call for - // the correct sizing, at which point the overview image is updated. - // (This avoids a double recalculation of the image.) - if (getWidth() == od.getWidth() && getHeight() == od.getHeight() - + progressPanel.getHeight()) - { - updateOverviewImage(); - } - else - { - if ((getWidth() > 0) && (getHeight() > 0)) - { - od.setWidth(getWidth()); - od.setHeight(getHeight() - progressPanel.getHeight()); - } - - setPreferredSize(new Dimension(od.getWidth(), - od.getHeight() + progressPanel.getHeight())); - } + resizePanel(); } }); @@ -195,37 +176,39 @@ public class OverviewPanel extends JPanel @Override public void mousePressed(MouseEvent evt) { - - if (Platform.isWinRightButton(evt)) { - showPopupMenu(evt); - return; - } - if (SwingUtilities.isRightMouseButton(evt)) { - return; + + if (Platform.isWinRightButton(evt)) + { + showPopupMenu(evt); + return; } - // don't do anything if the mouse press is in the overview's box - // (wait to see if it's a drag instead) - // otherwise update the viewport - if (!od.isPositionInBox(evt.getX(), evt.getY())) - { - draggingBox = false; + if (SwingUtilities.isRightMouseButton(evt)) + { + return; + } + // don't do anything if the mouse press is in the overview's box + // (wait to see if it's a drag instead) + // otherwise update the viewport + if (!od.isPositionInBox(evt.getX(), evt.getY())) + { + draggingBox = false; - // display drag cursor at mouse position - setCursor(Cursor.getPredefinedCursor(Cursor.MOVE_CURSOR)); + // display drag cursor at mouse position + setCursor(Cursor.getPredefinedCursor(Cursor.MOVE_CURSOR)); - od.updateViewportFromMouse(evt.getX(), evt.getY(), - av.getAlignment().getHiddenSequences(), - av.getAlignment().getHiddenColumns()); - getParent().setCursor( - Cursor.getPredefinedCursor(Cursor.HAND_CURSOR)); - } - else - { - draggingBox = true; - od.setDragPoint(evt.getX(), evt.getY(), - av.getAlignment().getHiddenSequences(), - av.getAlignment().getHiddenColumns()); - } + od.updateViewportFromMouse(evt.getX(), evt.getY(), + av.getAlignment().getHiddenSequences(), + av.getAlignment().getHiddenColumns()); + getParent().setCursor( + Cursor.getPredefinedCursor(Cursor.HAND_CURSOR)); + } + else + { + draggingBox = true; + od.setDragPoint(evt.getX(), evt.getY(), + av.getAlignment().getHiddenSequences(), + av.getAlignment().getHiddenColumns()); + } } @Override @@ -245,14 +228,71 @@ public class OverviewPanel extends JPanel }); - /* - * Javascript does not call componentResized on initial display, - * so do the update here - */ - if (Platform.isJS()) + // /* + // * Javascript does not call componentResized on initial display, + // * so do the update here + // */ + // if (Platform.isJS()) + // { + // updateOverviewImage(); + // } + } + + protected void resizePanel() + { + int ph = (progressPanel.getParent() == null ? 0 + : progressPanel.getHeight()); + // Resize is called on the initial display of the overview. + // This code adjusts sizes to account for the progress bar if it has not + // already been accounted for, which triggers another resize call for + // the correct sizing, at which point the overview image is updated. + // (This avoids a double recalculation of the image.) + if (getWidth() == od.getWidth() && getHeight() == od.getHeight() + ph) + { + if (canvas.lastMiniMe == null) + { + updateOverviewImage(); + } + } + else + { + int w = getWidth(); + int h = getHeight(); + if ((w > 0) && (h > 0)) + { + if (dim != null) + { + dim.setSize(w, h - ph); + } + od.setWidth(w); + od.setHeight(h - ph); + updateOverviewImage(); + } + // BH 2019.07.29 this is unnecessary -- it is what layout managers are + // for: + // setPreferredSize(new Dimension(od.getWidth(), od.getHeight() + + // ph)); + } + } + + /** + * Create the appropriate type of OverViewDimensions, with the desired size. + */ + private void createOverviewDimensions() + { + boolean showAnnotation = (av.isShowAnnotation() + && av.getAlignmentConservationAnnotation() != null); + if (showHidden) + { + od = new OverviewDimensionsShowHidden(av.getRanges(), showAnnotation, + dim); + } + else { - updateOverviewImage(); + od = new OverviewDimensionsHideHidden(av.getRanges(), showAnnotation, + dim); } + } /* @@ -285,31 +325,32 @@ public class OverviewPanel extends JPanel */ protected void toggleHiddenColumns() { - if (showHidden) - { - showHidden = false; - od = new OverviewDimensionsHideHidden(av.getRanges(), - (av.isShowAnnotation() - && av.getAlignmentConservationAnnotation() != null)); - } - else - { - showHidden = true; - od = new OverviewDimensionsShowHidden(av.getRanges(), - (av.isShowAnnotation() - && av.getAlignmentConservationAnnotation() != null)); - } - oviewCanvas.resetOviewDims(od); + showHidden = !showHidden; + createOverviewDimensions(); + canvas.resetOviewDims(od); updateOverviewImage(); setBoxPosition(); } /** - * Updates the overview image when the related alignment panel is updated + * Updates the overview image when the related alignment panel is updated. + * + * Cases: + * + * AlignFrame.setFeatureGroupState + * + * AlignmentPanel.paintAlignment(true,...) (117 references) + * + * OverviewPanel..componentResized() OverviewPanel.toggleHiddenColumns() + * + * PopupMenu for action.reveal_sequences, action.reveal_all + * + * SliderPanel.mouseReleased() + * */ public void updateOverviewImage() { - if (oviewCanvas == null) + if (canvas == null) { /* * panel has been disposed @@ -317,37 +358,36 @@ public class OverviewPanel extends JPanel return; } + int ph = (progressPanel.getParent() == null ? 0 + : progressPanel.getHeight()); + if ((getWidth() > 0) && (getHeight() > 0)) { od.setWidth(getWidth()); - od.setHeight(getHeight() - progressPanel.getHeight()); + od.setHeight(getHeight() - ph); } - - setPreferredSize(new Dimension(od.getWidth(), - od.getHeight() + progressPanel.getHeight())); - if (oviewCanvas.restartDraw()) + setPreferredSize(new Dimension(od.getWidth(), od.getHeight() + ph)); + + if (canvas.restartDraw()) { return; } Thread thread = new Thread(this); thread.start(); - repaint(); - - } @Override public void run() { - if (oviewCanvas != null) + if (canvas != null) { - oviewCanvas.draw(av.isShowSequenceFeatures(), + setBoxPosition(); + canvas.draw(av.isShowSequenceFeatures(), (av.isShowAnnotation() && av.getAlignmentConservationAnnotation() != null), - ap.getSeqPanel().seqCanvas.getFeatureRenderer()); - setBoxPosition(); + ap.getFeatureRenderer()); } } @@ -360,6 +400,7 @@ public class OverviewPanel extends JPanel { if (od != null) { + od.updateBox(); int oldX = od.getBoxX(); int oldY = od.getBoxY(); int oldWidth = od.getBoxWidth(); @@ -400,14 +441,15 @@ public class OverviewPanel extends JPanel av.getRanges().removePropertyChangeListener(this); } - oviewCanvas.dispose(); + canvas.dispose(); /* * close the parent frame (which also removes it from the * Desktop Windows menu) */ - ((JInternalFrame) SwingUtilities.getAncestorOfClass( - JInternalFrame.class, (this))).setClosed(true); + ((JInternalFrame) SwingUtilities + .getAncestorOfClass(JInternalFrame.class, (this))) + .setClosed(true); } catch (PropertyVetoException e) { // ignore @@ -415,7 +457,7 @@ public class OverviewPanel extends JPanel { progressPanel = null; av = null; - oviewCanvas = null; + canvas = null; ap = null; od = null; } diff --git a/src/jalview/gui/PCAPanel.java b/src/jalview/gui/PCAPanel.java index 96a8b0d..d1e7565 100644 --- a/src/jalview/gui/PCAPanel.java +++ b/src/jalview/gui/PCAPanel.java @@ -572,11 +572,11 @@ public class PCAPanel extends GPCAPanel // } // // JPanel progressPanel; - // Long lId = Long.valueOf(id); + // Long lId = new Long(id); // GridLayout layout = (GridLayout) statusPanel.getLayout(); // if (progressBars.get(lId) != null) // { - // progressPanel = (JPanel) progressBars.get(Long.valueOf(id)); + // progressPanel = (JPanel) progressBars.get(new Long(id)); // statusPanel.remove(progressPanel); // progressBars.remove(lId); // progressPanel = null; @@ -615,13 +615,13 @@ public class PCAPanel extends GPCAPanel final IProgressIndicatorHandler handler) { progressBar.registerHandler(id, handler); - // if (progressBarHandlers == null || !progressBars.contains(Long.valueOf(id))) + // if (progressBarHandlers == null || !progressBars.contains(new Long(id))) // { // throw new // Error(MessageManager.getString("error.call_setprogressbar_before_registering_handler")); // } - // progressBarHandlers.put(Long.valueOf(id), handler); - // final JPanel progressPanel = (JPanel) progressBars.get(Long.valueOf(id)); + // progressBarHandlers.put(new Long(id), handler); + // final JPanel progressPanel = (JPanel) progressBars.get(new Long(id)); // if (handler.canCancel()) // { // JButton cancel = new JButton( diff --git a/src/jalview/gui/PopupMenu.java b/src/jalview/gui/PopupMenu.java index ad33110..3145f7c 100644 --- a/src/jalview/gui/PopupMenu.java +++ b/src/jalview/gui/PopupMenu.java @@ -304,10 +304,10 @@ public class PopupMenu extends JPopupMenu implements ColourChangeListener { try { - jalview.util.BrowserLauncher.openURL(url); + Platform.openURL(url); } catch (Exception ex) { - JvOptionPane.showInternalMessageDialog(Desktop.desktop, + JvOptionPane.showInternalMessageDialog(Desktop.getDesktopPane(), MessageManager.getString("label.web_browser_not_found_unix"), MessageManager.getString("label.web_browser_not_found"), JvOptionPane.WARNING_MESSAGE); @@ -317,7 +317,9 @@ public class PopupMenu extends JPopupMenu implements ColourChangeListener } /** - * add a late bound groupURL item to the given linkMenu + * For the popup menu on the idPanel. + * + * Add a late bound groupURL item to the given linkMenu * * @param linkMenu * @param label @@ -349,6 +351,15 @@ public class PopupMenu extends JPopupMenu implements ColourChangeListener { try { + // Object[] { int[] { number of matches seqs }, + // boolean[] { which matched }, + // StringBuffer[] { segment generated from inputs }, + // String[] { url } + // } + + // TODO bug: urlstub is { int[], boolean[] } but constructFrom + // requires something else. + showLink(urlgenerator.constructFrom(urlstub)); } catch (UrlStringTooLongException e2) { @@ -388,6 +399,7 @@ public class PopupMenu extends JPopupMenu implements ColourChangeListener * non-positional features if in the Id panel, features at the * clicked residue if in the sequence panel * @param groupLinks + * not implemented -- empty list */ public PopupMenu(final AlignmentPanel alignPanel, final SequenceI seq, List features, List groupLinks) @@ -658,6 +670,7 @@ public class PopupMenu extends JPopupMenu implements ColourChangeListener // add any groupURLs to the groupURL submenu and make it visible if (groupLinks != null && groupLinks.size() > 0) { + // not implemented -- empty list buildGroupURLMenu(sg, groupLinks); } // Add a 'show all structures' for the current selection @@ -983,6 +996,12 @@ public class PopupMenu extends JPopupMenu implements ColourChangeListener showOrHideMenu.add(item); } + /** + * + * @param sg + * @param groupLinks + * not implemented -- empty list + */ private void buildGroupURLMenu(SequenceGroup sg, List groupLinks) { @@ -1044,9 +1063,15 @@ public class PopupMenu extends JPopupMenu implements ColourChangeListener } } } + if (groupLinks.size() == 0) + { + return; + } // now create group links for all distinct ID/sequence sets. boolean addMenu = false; // indicates if there are any group links to give // to user + + // not implmeented -- empty list for (String link : groupLinks) { GroupUrlLink urlLink = null; @@ -1099,6 +1124,7 @@ public class PopupMenu extends JPopupMenu implements ColourChangeListener { urlset = urlLink.makeUrlStubs(ids, seqstr, "FromJalview" + System.currentTimeMillis(), false); + // { int[], boolean[] } only here } catch (UrlStringTooLongException e) { } @@ -1127,7 +1153,6 @@ public class PopupMenu extends JPopupMenu implements ColourChangeListener groupLinksMenu.add(linkMenus[m]); } } - groupMenu.add(groupLinksMenu); } } @@ -1985,7 +2010,7 @@ public class PopupMenu extends JPopupMenu implements ColourChangeListener refresh(); }; }; - JalviewColourChooser.showColourChooser(Desktop.getDesktop(), + JalviewColourChooser.showColourChooser(Desktop.getDesktopPane(), title, Color.BLUE, listener); } diff --git a/src/jalview/gui/Preferences.java b/src/jalview/gui/Preferences.java index 94f67f6..b1206a2 100755 --- a/src/jalview/gui/Preferences.java +++ b/src/jalview/gui/Preferences.java @@ -25,7 +25,6 @@ import jalview.bin.Cache; import jalview.gui.Help.HelpId; import jalview.gui.StructureViewer.ViewerType; import jalview.io.BackupFiles; -import jalview.io.BackupFilesPresetEntry; import jalview.io.FileFormatI; import jalview.io.JalviewFileChooser; import jalview.io.JalviewFileView; @@ -38,6 +37,7 @@ import jalview.urls.UrlLinkTableModel; import jalview.urls.api.UrlProviderFactoryI; import jalview.urls.api.UrlProviderI; import jalview.urls.desktop.DesktopUrlProviderFactory; +import jalview.util.BrowserLauncher; import jalview.util.MessageManager; import jalview.util.Platform; import jalview.util.UrlConstants; @@ -81,43 +81,139 @@ import ext.edu.ucsf.rbvi.strucviz2.StructureManager; * @author $author$ * @version $Revision$ */ +@SuppressWarnings("serial") public class Preferences extends GPreferences { - public static final String ENABLE_SPLIT_FRAME = "ENABLE_SPLIT_FRAME"; + public static final String ADD_SS_ANN = "ADD_SS_ANN"; - public static final String SCALE_PROTEIN_TO_CDNA = "SCALE_PROTEIN_TO_CDNA"; + public static final String ADD_TEMPFACT_ANN = "ADD_TEMPFACT_ANN"; + + public static final String ALLOW_UNPUBLISHED_PDB_QUERYING = "ALLOW_UNPUBLISHED_PDB_QUERYING"; + + public static final String ANNOTATIONCOLOUR_MAX = "ANNOTATIONCOLOUR_MAX"; + + public static final String ANNOTATIONCOLOUR_MIN = "ANNOTATIONCOLOUR_MIN"; + + public static final String ANTI_ALIAS = "ANTI_ALIAS"; + + public static final String AUTO_CALC_CONSENSUS = "AUTO_CALC_CONSENSUS"; + + public static final String AUTOASSOCIATE_PDBANDSEQS = "AUTOASSOCIATE_PDBANDSEQS"; + + public static final String CENTRE_COLUMN_LABELS = "CENTRE_COLUMN_LABELS"; + + public static final String CHIMERA_PATH = "CHIMERA_PATH"; + + public static final String DBREFFETCH_USEPICR = "DBREFFETCH_USEPICR"; public static final String DEFAULT_COLOUR = "DEFAULT_COLOUR"; + public static final String DEFAULT_COLOUR_NUC = "DEFAULT_COLOUR_NUC"; + public static final String DEFAULT_COLOUR_PROT = "DEFAULT_COLOUR_PROT"; - public static final String DEFAULT_COLOUR_NUC = "DEFAULT_COLOUR_NUC"; + public static final String ENABLE_SPLIT_FRAME = "ENABLE_SPLIT_FRAME"; - public static final String ADD_TEMPFACT_ANN = "ADD_TEMPFACT_ANN"; + public static final String FIGURE_AUTOIDWIDTH = "FIGURE_AUTOIDWIDTH"; - public static final String ADD_SS_ANN = "ADD_SS_ANN"; + public static final String FIGURE_FIXEDIDWIDTH = "FIGURE_FIXEDIDWIDTH"; - public static final String USE_RNAVIEW = "USE_RNAVIEW"; + public static final String FOLLOW_SELECTIONS = "FOLLOW_SELECTIONS"; - public static final String STRUCT_FROM_PDB = "STRUCT_FROM_PDB"; + public static final String FONT_NAME = "FONT_NAME"; - public static final String STRUCTURE_DISPLAY = "STRUCTURE_DISPLAY"; + public static final String FONT_SIZE = "FONT_SIZE"; - public static final String CHIMERA_PATH = "CHIMERA_PATH"; + public static final String FONT_STYLE = "FONT_STYLE"; - public static final String SORT_ANNOTATIONS = "SORT_ANNOTATIONS"; + public static final String GAP_COLOUR = "GAP_COLOUR"; + + public static final String GAP_SYMBOL = "GAP_SYMBOL"; + + public static final String HIDDEN_COLOUR = "HIDDEN_COLOUR"; + + public static final String HIDE_INTRONS = "HIDE_INTRONS"; + + public static final String ID_ITALICS = "ID_ITALICS"; + + public static final String ID_ORG_HOSTURL = "ID_ORG_HOSTURL"; + + public static final String MAP_WITH_SIFTS = "MAP_WITH_SIFTS"; + + public static final String NOQUESTIONNAIRES = "NOQUESTIONNAIRES"; + + public static final String NORMALISE_CONSENSUS_LOGO = "NORMALISE_CONSENSUS_LOGO"; + + public static final String NORMALISE_LOGO = "NORMALISE_LOGO"; + + public static final String PAD_GAPS = "PAD_GAPS"; + + public static final String PDB_DOWNLOAD_FORMAT = "PDB_DOWNLOAD_FORMAT"; + + public static final String QUESTIONNAIRE = "QUESTIONNAIRE"; + + public static final String RELAXEDSEQIDMATCHING = "RELAXEDSEQIDMATCHING"; + + public static final String RIGHT_ALIGN_IDS = "RIGHT_ALIGN_IDS"; + + public static final String SCALE_PROTEIN_TO_CDNA = "SCALE_PROTEIN_TO_CDNA"; + + public static final String SHOW_ANNOTATIONS = "SHOW_ANNOTATIONS"; public static final String SHOW_AUTOCALC_ABOVE = "SHOW_AUTOCALC_ABOVE"; + public static final String SHOW_CONSENSUS = "SHOW_CONSENSUS"; + + public static final String SHOW_CONSENSUS_HISTOGRAM = "SHOW_CONSENSUS_HISTOGRAM"; + + public static final String SHOW_CONSENSUS_LOGO = "SHOW_CONSENSUS_LOGO"; + + public static final String SHOW_CONSERVATION = "SHOW_CONSERVATION"; + + public static final String SHOW_DBREFS_TOOLTIP = "SHOW_DBREFS_TOOLTIP"; + + public static final String SHOW_GROUP_CONSENSUS = "SHOW_GROUP_CONSENSUS"; + + public static final String SHOW_GROUP_CONSERVATION = "SHOW_GROUP_CONSERVATION"; + + public static final String SHOW_JVSUFFIX = "SHOW_JVSUFFIX"; + + public static final String SHOW_NPFEATS_TOOLTIP = "SHOW_NPFEATS_TOOLTIP"; + public static final String SHOW_OCCUPANCY = "SHOW_OCCUPANCY"; public static final String SHOW_OV_HIDDEN_AT_START = "SHOW_OV_HIDDEN_AT_START"; + public static final String SHOW_OVERVIEW = "SHOW_OVERVIEW"; + + public static final String SHOW_QUALITY = "SHOW_QUALITY"; + + public static final String SHOW_UNCONSERVED = "SHOW_UNCONSERVED"; + + public static final String SORT_ALIGNMENT = "SORT_ALIGNMENT"; + + public static final String SORT_ANNOTATIONS = "SORT_ANNOTATIONS"; + + public static final String SORT_BY_TREE = "SORT_BY_TREE"; + + public static final String STRUCT_FROM_PDB = "STRUCT_FROM_PDB"; + + public static final String STRUCTURE_DISPLAY = "STRUCTURE_DISPLAY"; + + public static final String STRUCTURE_DIMENSIONS = "STRUCTURE_DIMENSIONS"; + + public static final String UNIPROT_DOMAIN = "UNIPROT_DOMAIN"; + + public static final String USE_FULL_SO = "USE_FULL_SO"; + public static final String USE_LEGACY_GAP = "USE_LEGACY_GAP"; - public static final String GAP_COLOUR = "GAP_COLOUR"; + public static final String USE_RNAVIEW = "USE_RNAVIEW"; + + public static final String USER_DEFINED_COLOURS = "USER_DEFINED_COLOURS"; + + public static final String WRAP_ALIGNMENT = "WRAP_ALIGNMENT"; - public static final String HIDDEN_COLOUR = "HIDDEN_COLOUR"; private static final int MIN_FONT_SIZE = 1; @@ -127,9 +223,9 @@ public class Preferences extends GPreferences * Holds name and link separated with | character. Sequence ID must be * $SEQUENCE_ID$ or $SEQUENCE_ID=/.possible | chars ./=$ */ - public static UrlProviderI sequenceUrlLinks; + public static UrlProviderI sequenceUrlLinks; // must be nonfinal for test - public static UrlLinkTableModel dataModel; + public final static UrlLinkTableModel dataModel; /** * Holds name and link separated with | character. Sequence IDS and Sequences @@ -139,7 +235,17 @@ public class Preferences extends GPreferences * (TODO: proper escape for using | to separate ids or sequences */ - public static List groupURLLinks; + public static final List groupURLLinks; // not implemented + + public static final String BLOSUM62_PCA_FOR_NUCLEOTIDE = "BLOSUM62_PCA_FOR_NUCLEOTIDE"; + + public static final String SHOW_IDENTITY = "SHOW_IDENTITY"; + + public static final String SHOW_FULLSCREEN = "SHOW_FULLSCREEN"; + + public static final Dimension DEFAULT_STRUCTURE_DIMENSIONS = new Dimension( + 600, 600); + static { // get links selected to be in the menu (SEQUENCE_LINKS) @@ -165,7 +271,7 @@ public class Preferences extends GPreferences * .properties file as '|' separated strings */ - groupURLLinks = new ArrayList<>(); + groupURLLinks = new ArrayList<>(); // not implemented } JInternalFrame frame; @@ -200,11 +306,13 @@ public class Preferences extends GPreferences wsPrefs = new WsPreferences(); wsTab.add(wsPrefs, BorderLayout.CENTER); } - int width = 500, height = 450; + int width = 500, height = 510; // BH 2019.07.12 added 60 to height + // (structure panel was too small anyway, and I added a default dimension + // for Jmol if (Platform.isAMacAndNotJS()) { width = 570; - height = 480; + height = 540; // BH 2019.07.12 added 30 } Desktop.addInternalFrame(frame, @@ -214,30 +322,30 @@ public class Preferences extends GPreferences /* * Set Visual tab defaults */ - seqLimit.setSelected(Cache.getDefault("SHOW_JVSUFFIX", true)); - rightAlign.setSelected(Cache.getDefault("RIGHT_ALIGN_IDS", false)); - fullScreen.setSelected(Cache.getDefault("SHOW_FULLSCREEN", false)); - annotations.setSelected(Cache.getDefault("SHOW_ANNOTATIONS", true)); - - conservation.setSelected(Cache.getDefault("SHOW_CONSERVATION", true)); - quality.setSelected(Cache.getDefault("SHOW_QUALITY", true)); - identity.setSelected(Cache.getDefault("SHOW_IDENTITY", true)); - openoverv.setSelected(Cache.getDefault("SHOW_OVERVIEW", false)); + seqLimit.setSelected(Cache.getDefault(SHOW_JVSUFFIX, true)); + rightAlign.setSelected(Cache.getDefault(RIGHT_ALIGN_IDS, false)); + fullScreen.setSelected(Cache.getDefault(SHOW_FULLSCREEN, false)); + annotations.setSelected(Cache.getDefault(SHOW_ANNOTATIONS, true)); + + conservation.setSelected(Cache.getDefault(SHOW_CONSERVATION, true)); + quality.setSelected(Cache.getDefault(SHOW_QUALITY, true)); + identity.setSelected(Cache.getDefault(SHOW_IDENTITY, true)); + openoverv.setSelected(Cache.getDefault(SHOW_OVERVIEW, false)); showUnconserved - .setSelected(Cache.getDefault("SHOW_UNCONSERVED", false)); + .setSelected(Cache.getDefault(SHOW_UNCONSERVED, false)); showOccupancy.setSelected(Cache.getDefault(SHOW_OCCUPANCY, false)); showGroupConsensus - .setSelected(Cache.getDefault("SHOW_GROUP_CONSENSUS", false)); + .setSelected(Cache.getDefault(SHOW_GROUP_CONSENSUS, false)); showGroupConservation.setSelected( - Cache.getDefault("SHOW_GROUP_CONSERVATION", false)); + Cache.getDefault(SHOW_GROUP_CONSERVATION, false)); showConsensHistogram.setSelected( - Cache.getDefault("SHOW_CONSENSUS_HISTOGRAM", true)); + Cache.getDefault(SHOW_CONSENSUS_HISTOGRAM, true)); showConsensLogo - .setSelected(Cache.getDefault("SHOW_CONSENSUS_LOGO", false)); + .setSelected(Cache.getDefault(SHOW_CONSENSUS_LOGO, false)); showNpTooltip - .setSelected(Cache.getDefault("SHOW_NPFEATS_TOOLTIP", true)); + .setSelected(Cache.getDefault(SHOW_NPFEATS_TOOLTIP, true)); showDbRefTooltip - .setSelected(Cache.getDefault("SHOW_DBREFS_TOOLTIP", true)); + .setSelected(Cache.getDefault(SHOW_DBREFS_TOOLTIP, true)); String[] fonts = java.awt.GraphicsEnvironment .getLocalGraphicsEnvironment().getAvailableFontFamilyNames(); @@ -255,28 +363,28 @@ public class Preferences extends GPreferences fontStyleCB.addItem("bold"); fontStyleCB.addItem("italic"); - fontNameCB.setSelectedItem(Cache.getDefault("FONT_NAME", "SansSerif")); - fontSizeCB.setSelectedItem(Cache.getDefault("FONT_SIZE", "10")); + fontNameCB.setSelectedItem(Cache.getDefault(FONT_NAME, "SansSerif")); + fontSizeCB.setSelectedItem(Cache.getDefault(FONT_SIZE, "10")); fontStyleCB.setSelectedItem( - Cache.getDefault("FONT_STYLE", Font.PLAIN + "")); + Cache.getDefault(FONT_STYLE, Font.PLAIN + "")); - smoothFont.setSelected(Cache.getDefault("ANTI_ALIAS", false)); + smoothFont.setSelected(Cache.getDefault(ANTI_ALIAS, false)); scaleProteinToCdna .setSelected(Cache.getDefault(SCALE_PROTEIN_TO_CDNA, false)); - idItalics.setSelected(Cache.getDefault("ID_ITALICS", true)); + idItalics.setSelected(Cache.getDefault(ID_ITALICS, true)); - wrap.setSelected(Cache.getDefault("WRAP_ALIGNMENT", false)); + wrap.setSelected(Cache.getDefault(WRAP_ALIGNMENT, false)); gapSymbolCB.addItem("-"); gapSymbolCB.addItem("."); - gapSymbolCB.setSelectedItem(Cache.getDefault("GAP_SYMBOL", "-")); + gapSymbolCB.setSelectedItem(Cache.getDefault(GAP_SYMBOL, "-")); sortby.addItem("No sort"); sortby.addItem("Id"); sortby.addItem("Pairwise Identity"); - sortby.setSelectedItem(Cache.getDefault("SORT_ALIGNMENT", "No sort")); + sortby.setSelectedItem(Cache.getDefault(SORT_ALIGNMENT, "No sort")); sortAnnBy.addItem(SequenceAnnotationOrder.NONE.toString()); sortAnnBy @@ -317,9 +425,9 @@ public class Preferences extends GPreferences newProp = Cache.getDefault(DEFAULT_COLOUR_NUC, null); nucColour.setSelectedItem(newProp != null ? newProp : oldProp); minColour.setBackground( - Cache.getDefaultColour("ANNOTATIONCOLOUR_MIN", Color.orange)); + Cache.getDefaultColour(ANNOTATIONCOLOUR_MIN, Color.orange)); maxColour.setBackground( - Cache.getDefaultColour("ANNOTATIONCOLOUR_MAX", Color.red)); + Cache.getDefaultColour(ANNOTATIONCOLOUR_MAX, Color.red)); /* * Set overview panel defaults @@ -349,6 +457,10 @@ public class Preferences extends GPreferences addTempFactor.setEnabled(structSelected); structViewer.setSelectedItem( Cache.getDefault(STRUCTURE_DISPLAY, ViewerType.JMOL.name())); + Dimension d = Cache.getDefaultDim(STRUCTURE_DIMENSIONS, + DEFAULT_STRUCTURE_DIMENSIONS); + String s = d.width + "," + d.height; + structureDimensions.setText(s); chimeraPath.setText(Cache.getDefault(CHIMERA_PATH, "")); chimeraPath.addActionListener(new ActionListener() { @@ -359,7 +471,7 @@ public class Preferences extends GPreferences } }); - if (Cache.getDefault("MAP_WITH_SIFTS", false)) + if (Cache.getDefault(MAP_WITH_SIFTS, false)) { siftsMapping.setSelected(true); } @@ -369,7 +481,7 @@ public class Preferences extends GPreferences } SiftsSettings - .setMapWithSifts(Cache.getDefault("MAP_WITH_SIFTS", false)); + .setMapWithSifts(Cache.getDefault(MAP_WITH_SIFTS, false)); /* * Set Connections tab defaults @@ -505,7 +617,7 @@ public class Preferences extends GPreferences usagestats.setSelected(Cache.getDefault("USAGESTATS", false)); // note antisense here: default is true questionnaire - .setSelected(Cache.getProperty("NOQUESTIONNAIRES") == null); + .setSelected(Cache.getProperty(NOQUESTIONNAIRES) == null); versioncheck.setSelected(Cache.getDefault("VERSION_CHECK", true)); /* @@ -514,10 +626,10 @@ public class Preferences extends GPreferences setupOutputCombo(epsRendering, "EPS_RENDERING"); setupOutputCombo(htmlRendering, "HTML_RENDERING"); setupOutputCombo(svgRendering, "SVG_RENDERING"); - autoIdWidth.setSelected(Cache.getDefault("FIGURE_AUTOIDWIDTH", false)); + autoIdWidth.setSelected(Cache.getDefault(FIGURE_AUTOIDWIDTH, false)); userIdWidth.setEnabled(!autoIdWidth.isSelected()); userIdWidthlabel.setEnabled(!autoIdWidth.isSelected()); - Integer wi = Cache.getIntegerProperty("FIGURE_FIXEDIDWIDTH"); + Integer wi = Cache.getIntegerProperty(FIGURE_FIXEDIDWIDTH); userIdWidth.setText(wi == null ? "" : wi.toString()); // TODO: refactor to use common enum via FormatAdapter and allow extension // for new flat file formats @@ -536,9 +648,9 @@ public class Preferences extends GPreferences * Set Editing tab defaults */ autoCalculateConsCheck - .setSelected(Cache.getDefault("AUTO_CALC_CONSENSUS", true)); - padGaps.setSelected(Cache.getDefault("PAD_GAPS", false)); - sortByTree.setSelected(Cache.getDefault("SORT_BY_TREE", false)); + .setSelected(Cache.getDefault(AUTO_CALC_CONSENSUS, true)); + padGaps.setSelected(Cache.getDefault(PAD_GAPS, false)); + sortByTree.setSelected(Cache.getDefault(SORT_BY_TREE, false)); annotations_actionPerformed(null); // update the display of the annotation // settings @@ -547,10 +659,7 @@ public class Preferences extends GPreferences /* * Set Backups tab defaults */ - if (!Platform.isJS()) - { - loadLastSavedBackupsOptions(); - } + loadLastSavedBackupsOptions(); } /** @@ -603,65 +712,65 @@ public class Preferences extends GPreferences /* * Save Visual settings */ - Cache.applicationProperties.setProperty("SHOW_JVSUFFIX", + Cache.setPropertyNoSave(SHOW_JVSUFFIX, Boolean.toString(seqLimit.isSelected())); - Cache.applicationProperties.setProperty("RIGHT_ALIGN_IDS", + Cache.setPropertyNoSave(RIGHT_ALIGN_IDS, Boolean.toString(rightAlign.isSelected())); - Cache.applicationProperties.setProperty("SHOW_FULLSCREEN", + Cache.setPropertyNoSave(SHOW_FULLSCREEN, Boolean.toString(fullScreen.isSelected())); - Cache.applicationProperties.setProperty("SHOW_OVERVIEW", + Cache.setPropertyNoSave(SHOW_OVERVIEW, Boolean.toString(openoverv.isSelected())); - Cache.applicationProperties.setProperty("SHOW_ANNOTATIONS", + Cache.setPropertyNoSave(SHOW_ANNOTATIONS, Boolean.toString(annotations.isSelected())); - Cache.applicationProperties.setProperty("SHOW_CONSERVATION", + Cache.setPropertyNoSave(SHOW_CONSERVATION, Boolean.toString(conservation.isSelected())); - Cache.applicationProperties.setProperty("SHOW_QUALITY", + Cache.setPropertyNoSave(SHOW_QUALITY, Boolean.toString(quality.isSelected())); - Cache.applicationProperties.setProperty("SHOW_IDENTITY", + Cache.setPropertyNoSave(SHOW_IDENTITY, Boolean.toString(identity.isSelected())); - Cache.applicationProperties.setProperty("GAP_SYMBOL", + Cache.setPropertyNoSave(GAP_SYMBOL, gapSymbolCB.getSelectedItem().toString()); - Cache.applicationProperties.setProperty("FONT_NAME", + Cache.setPropertyNoSave(FONT_NAME, fontNameCB.getSelectedItem().toString()); - Cache.applicationProperties.setProperty("FONT_STYLE", + Cache.setPropertyNoSave(FONT_STYLE, fontStyleCB.getSelectedItem().toString()); - Cache.applicationProperties.setProperty("FONT_SIZE", + Cache.setPropertyNoSave(FONT_SIZE, fontSizeCB.getSelectedItem().toString()); - Cache.applicationProperties.setProperty("ID_ITALICS", + Cache.setPropertyNoSave(ID_ITALICS, Boolean.toString(idItalics.isSelected())); - Cache.applicationProperties.setProperty("SHOW_UNCONSERVED", + Cache.setPropertyNoSave(SHOW_UNCONSERVED, Boolean.toString(showUnconserved.isSelected())); - Cache.applicationProperties.setProperty(SHOW_OCCUPANCY, + Cache.setPropertyNoSave(SHOW_OCCUPANCY, Boolean.toString(showOccupancy.isSelected())); - Cache.applicationProperties.setProperty("SHOW_GROUP_CONSENSUS", + Cache.setPropertyNoSave(SHOW_GROUP_CONSENSUS, Boolean.toString(showGroupConsensus.isSelected())); - Cache.applicationProperties.setProperty("SHOW_GROUP_CONSERVATION", + Cache.setPropertyNoSave(SHOW_GROUP_CONSERVATION, Boolean.toString(showGroupConservation.isSelected())); - Cache.applicationProperties.setProperty("SHOW_CONSENSUS_HISTOGRAM", + Cache.setPropertyNoSave(SHOW_CONSENSUS_HISTOGRAM, Boolean.toString(showConsensHistogram.isSelected())); - Cache.applicationProperties.setProperty("SHOW_CONSENSUS_LOGO", + Cache.setPropertyNoSave(SHOW_CONSENSUS_LOGO, Boolean.toString(showConsensLogo.isSelected())); - Cache.applicationProperties.setProperty("ANTI_ALIAS", + Cache.setPropertyNoSave(ANTI_ALIAS, Boolean.toString(smoothFont.isSelected())); - Cache.applicationProperties.setProperty(SCALE_PROTEIN_TO_CDNA, + Cache.setPropertyNoSave(SCALE_PROTEIN_TO_CDNA, Boolean.toString(scaleProteinToCdna.isSelected())); - Cache.applicationProperties.setProperty("SHOW_NPFEATS_TOOLTIP", + Cache.setPropertyNoSave(SHOW_NPFEATS_TOOLTIP, Boolean.toString(showNpTooltip.isSelected())); - Cache.applicationProperties.setProperty("SHOW_DBREFS_TOOLTIP", + Cache.setPropertyNoSave(SHOW_DBREFS_TOOLTIP, Boolean.toString(showDbRefTooltip.isSelected())); - Cache.applicationProperties.setProperty("WRAP_ALIGNMENT", + Cache.setPropertyNoSave(WRAP_ALIGNMENT, Boolean.toString(wrap.isSelected())); - Cache.applicationProperties.setProperty("STARTUP_FILE", + Cache.setPropertyNoSave("STARTUP_FILE", startupFileTextfield.getText()); - Cache.applicationProperties.setProperty("SHOW_STARTUP_FILE", + Cache.setPropertyNoSave("SHOW_STARTUP_FILE", Boolean.toString(startupCheckbox.isSelected())); - Cache.applicationProperties.setProperty("SORT_ALIGNMENT", + Cache.setPropertyNoSave(SORT_ALIGNMENT, sortby.getSelectedItem().toString()); // convert description of sort order to enum name for save @@ -669,24 +778,24 @@ public class Preferences extends GPreferences .forDescription(sortAnnBy.getSelectedItem().toString()); if (annSortOrder != null) { - Cache.applicationProperties.setProperty(SORT_ANNOTATIONS, + Cache.setPropertyNoSave(SORT_ANNOTATIONS, annSortOrder.name()); } final boolean showAutocalcFirst = sortAutocalc.getSelectedIndex() == 0; - Cache.applicationProperties.setProperty(SHOW_AUTOCALC_ABOVE, + Cache.setPropertyNoSave(SHOW_AUTOCALC_ABOVE, Boolean.valueOf(showAutocalcFirst).toString()); /* * Save Colours settings */ - Cache.applicationProperties.setProperty(DEFAULT_COLOUR_PROT, + Cache.setPropertyNoSave(DEFAULT_COLOUR_PROT, protColour.getSelectedItem().toString()); - Cache.applicationProperties.setProperty(DEFAULT_COLOUR_NUC, + Cache.setPropertyNoSave(DEFAULT_COLOUR_NUC, nucColour.getSelectedItem().toString()); - Cache.setColourProperty("ANNOTATIONCOLOUR_MIN", + Cache.setColourProperty(ANNOTATIONCOLOUR_MIN, minColour.getBackground()); - Cache.setColourProperty("ANNOTATIONCOLOUR_MAX", + Cache.setColourProperty(ANNOTATIONCOLOUR_MAX, maxColour.getBackground()); /* @@ -694,73 +803,79 @@ public class Preferences extends GPreferences */ Cache.setColourProperty(GAP_COLOUR, gapColour.getBackground()); Cache.setColourProperty(HIDDEN_COLOUR, hiddenColour.getBackground()); - Cache.applicationProperties.setProperty(USE_LEGACY_GAP, + Cache.setPropertyNoSave(USE_LEGACY_GAP, Boolean.toString(useLegacyGap.isSelected())); - Cache.applicationProperties.setProperty(SHOW_OV_HIDDEN_AT_START, + Cache.setPropertyNoSave(SHOW_OV_HIDDEN_AT_START, Boolean.toString(showHiddenAtStart.isSelected())); /* * Save Structure settings */ - Cache.applicationProperties.setProperty(ADD_TEMPFACT_ANN, + Cache.setPropertyNoSave(ADD_TEMPFACT_ANN, Boolean.toString(addTempFactor.isSelected())); - Cache.applicationProperties.setProperty(ADD_SS_ANN, + Cache.setPropertyNoSave(ADD_SS_ANN, Boolean.toString(addSecondaryStructure.isSelected())); - Cache.applicationProperties.setProperty(USE_RNAVIEW, + Cache.setPropertyNoSave(USE_RNAVIEW, Boolean.toString(useRnaView.isSelected())); - Cache.applicationProperties.setProperty(STRUCT_FROM_PDB, + Cache.setPropertyNoSave(STRUCT_FROM_PDB, Boolean.toString(structFromPdb.isSelected())); - Cache.applicationProperties.setProperty(STRUCTURE_DISPLAY, + Cache.setPropertyNoSave(STRUCTURE_DISPLAY, structViewer.getSelectedItem().toString()); + Cache.setPropertyNoSave(STRUCTURE_DIMENSIONS, + structureDimensions.getText()); // BH 2019.07.12 Cache.setOrRemove(CHIMERA_PATH, chimeraPath.getText()); - Cache.applicationProperties.setProperty("MAP_WITH_SIFTS", + Cache.setPropertyNoSave(MAP_WITH_SIFTS, Boolean.toString(siftsMapping.isSelected())); SiftsSettings.setMapWithSifts(siftsMapping.isSelected()); /* * Save Output settings */ - Cache.applicationProperties.setProperty("EPS_RENDERING", + Cache.setPropertyNoSave("EPS_RENDERING", ((OptionsParam) epsRendering.getSelectedItem()).getCode()); - Cache.applicationProperties.setProperty("HTML_RENDERING", + Cache.setPropertyNoSave("HTML_RENDERING", ((OptionsParam) htmlRendering.getSelectedItem()).getCode()); - Cache.applicationProperties.setProperty("SVG_RENDERING", + Cache.setPropertyNoSave("SVG_RENDERING", ((OptionsParam) svgRendering.getSelectedItem()).getCode()); - /* - * Save Connections settings + if (!Platform.isJS()) + /** + * @j2sNative */ - Cache.setOrRemove("DEFAULT_BROWSER", defaultBrowser.getText()); - - jalview.util.BrowserLauncher.resetBrowser(); + { + // Java only + // Save Connections settings + Cache.setOrRemove("DEFAULT_BROWSER", defaultBrowser.getText()); + BrowserLauncher.resetBrowser(); + } // save user-defined and selected links String menuLinks = sequenceUrlLinks.writeUrlsAsString(true); if (menuLinks.isEmpty()) { - Cache.applicationProperties.remove("SEQUENCE_LINKS"); + Cache.removePropertyNoSave("SEQUENCE_LINKS"); } else { - Cache.applicationProperties.setProperty("SEQUENCE_LINKS", + Cache.setPropertyNoSave("SEQUENCE_LINKS", menuLinks.toString()); } String nonMenuLinks = sequenceUrlLinks.writeUrlsAsString(false); if (nonMenuLinks.isEmpty()) { - Cache.applicationProperties.remove("STORED_LINKS"); + Cache.removePropertyNoSave("STORED_LINKS"); } else { - Cache.applicationProperties.setProperty("STORED_LINKS", + Cache.setPropertyNoSave("STORED_LINKS", nonMenuLinks.toString()); } - Cache.applicationProperties.setProperty("DEFAULT_URL", + Cache.setPropertyNoSave("DEFAULT_URL", sequenceUrlLinks.getPrimaryUrlId()); - Cache.applicationProperties.setProperty("USE_PROXY", + Cache.setPropertyNoSave("USE_PROXY", Boolean.toString(useProxy.isSelected())); Cache.setOrRemove("PROXY_SERVER", proxyServerTB.getText()); @@ -787,52 +902,50 @@ public class Preferences extends GPreferences } if (!questionnaire.isSelected()) { - Cache.setProperty("NOQUESTIONNAIRES", "true"); + Cache.setProperty(NOQUESTIONNAIRES, "true"); } else { // special - made easy to edit a property file to disable questionnaires // by just adding the given line - Cache.removeProperty("NOQUESTIONNAIRES"); + Cache.removeProperty(NOQUESTIONNAIRES); } /* * Save Output settings */ - Cache.applicationProperties.setProperty("BLC_JVSUFFIX", + Cache.setPropertyNoSave("BLC_JVSUFFIX", Boolean.toString(blcjv.isSelected())); - Cache.applicationProperties.setProperty("CLUSTAL_JVSUFFIX", + Cache.setPropertyNoSave("CLUSTAL_JVSUFFIX", Boolean.toString(clustaljv.isSelected())); - Cache.applicationProperties.setProperty("FASTA_JVSUFFIX", + Cache.setPropertyNoSave("FASTA_JVSUFFIX", Boolean.toString(fastajv.isSelected())); - Cache.applicationProperties.setProperty("MSF_JVSUFFIX", + Cache.setPropertyNoSave("MSF_JVSUFFIX", Boolean.toString(msfjv.isSelected())); - Cache.applicationProperties.setProperty("PFAM_JVSUFFIX", + Cache.setPropertyNoSave("PFAM_JVSUFFIX", Boolean.toString(pfamjv.isSelected())); - Cache.applicationProperties.setProperty("PILEUP_JVSUFFIX", + Cache.setPropertyNoSave("PILEUP_JVSUFFIX", Boolean.toString(pileupjv.isSelected())); - Cache.applicationProperties.setProperty("PIR_JVSUFFIX", + Cache.setPropertyNoSave("PIR_JVSUFFIX", Boolean.toString(pirjv.isSelected())); - Cache.applicationProperties.setProperty("PIR_MODELLER", + Cache.setPropertyNoSave("PIR_MODELLER", Boolean.toString(modellerOutput.isSelected())); - Cache.applicationProperties.setProperty("EXPORT_EMBBED_BIOJSON", + Cache.setPropertyNoSave("EXPORT_EMBBED_BIOJSON", Boolean.toString(embbedBioJSON.isSelected())); - jalview.io.PIRFile.useModellerOutput = modellerOutput.isSelected(); - - Cache.applicationProperties.setProperty("FIGURE_AUTOIDWIDTH", + Cache.setPropertyNoSave(FIGURE_AUTOIDWIDTH, Boolean.toString(autoIdWidth.isSelected())); userIdWidth_actionPerformed(); - Cache.applicationProperties.setProperty("FIGURE_FIXEDIDWIDTH", + Cache.setPropertyNoSave("FIGURE_FIXEDIDWIDTH", userIdWidth.getText()); /* * Save Editing settings */ - Cache.applicationProperties.setProperty("AUTO_CALC_CONSENSUS", + Cache.setPropertyNoSave(AUTO_CALC_CONSENSUS, Boolean.toString(autoCalculateConsCheck.isSelected())); - Cache.applicationProperties.setProperty("SORT_BY_TREE", + Cache.setPropertyNoSave(SORT_BY_TREE, Boolean.toString(sortByTree.isSelected())); - Cache.applicationProperties.setProperty("PAD_GAPS", + Cache.setPropertyNoSave(PAD_GAPS, Boolean.toString(padGaps.isSelected())); if (!Platform.isJS()) @@ -843,32 +956,25 @@ public class Preferences extends GPreferences /* * Save Backups settings */ - Cache.applicationProperties.setProperty(BackupFiles.ENABLED, - Platform.isJS() ? Boolean.FALSE.toString() - : Boolean.toString(enableBackupFiles.isSelected())); - if (!Platform.isJS()) - { - int preset = getComboIntStringKey(backupfilesPresetsCombo); - Cache.applicationProperties.setProperty(BackupFiles.NS + "_PRESET", - Integer.toString(preset)); - - if (preset == BackupFilesPresetEntry.BACKUPFILESSCHEMECUSTOM) - { - BackupFilesPresetEntry customBFPE = getBackupfilesCurrentEntry(); - BackupFilesPresetEntry.backupfilesPresetEntriesValues.put( - BackupFilesPresetEntry.BACKUPFILESSCHEMECUSTOM, customBFPE); - Cache.applicationProperties.setProperty( - BackupFilesPresetEntry.CUSTOMCONFIG, customBFPE.toString()); - } - - BackupFilesPresetEntry savedBFPE = BackupFilesPresetEntry.backupfilesPresetEntriesValues - .get(preset); - Cache.applicationProperties.setProperty( - BackupFilesPresetEntry.SAVEDCONFIG, savedBFPE.toString()); - } + Cache.setPropertyNoSave(BackupFiles.CONFIRM_DELETE_OLD, + Boolean.toString(backupfilesConfirmDelete.isSelected())); + Cache.setPropertyNoSave(BackupFiles.ENABLED, + Boolean.toString(enableBackupFiles.isSelected())); + Cache.setPropertyNoSave(BackupFiles.NO_MAX, + Boolean.toString(backupfilesKeepAll.isSelected())); + Cache.setPropertyNoSave(BackupFiles.REVERSE_ORDER, + Boolean.toString(suffixReverse.isSelected())); + Cache.setPropertyNoSave(BackupFiles.SUFFIX, + suffixTemplate.getText()); + Cache.setPropertyNoSave(BackupFiles.ROLL_MAX, + Integer.toString(getSpinnerInt(backupfilesRollMaxSpinner, 4))); + Cache.setPropertyNoSave(BackupFiles.SUFFIX_DIGITS, + Integer.toString(getSpinnerInt(suffixDigitsSpinner, 3))); + Cache.setPropertyNoSave(BackupFiles.NS + "_PRESET", + Integer.toString(getComboIntStringKey(backupfilesPresetsCombo))); Cache.saveProperties(); - Desktop.instance.doConfigureStructurePrefs(); + Desktop.getInstance().doConfigureStructurePrefs(); try { frame.setClosed(true); @@ -877,6 +983,43 @@ public class Preferences extends GPreferences } } + public static void setAppletDefaults() + { + + // http://www.jalview.org/old/v2_8/examples/appletParameters.html + + // showConservation true or false Default is true. + // showQuality true or false Default is true. + // showConsensus true or false Default is true. + // showFeatureSettings true or false Shows the feature settings window when + // startin + // showTreeBootstraps true or false (default is true) show or hide branch + // bootstraps + // showTreeDistances true or false (default is true) show or hide branch + // lengths + // showUnlinkedTreeNodes true or false (default is false) indicate if + // unassociated nodes should be highlighted in the tree view + // showUnconserved true of false (default is false) When true, only gaps and + // symbols different to the consensus sequence ions of the alignment + // showGroupConsensus true of false (default is false) When true, shows + // consensus annotation row for any groups on the alignment. (since 2.7) + // showGroupConservation true of false (default is false) When true, shows + // amino-acid property conservation annotation row for any groups on the + // showConsensusHistogram true of false (default is true) When true, shows + // the percentage occurence of the consensus symbol for each column as a + // showSequenceLogo true of false (default is false) When true, shows a + // sequence logo above the consensus sequence (overlaid above the Consensus + + Cache.setPropertyNoSave(SHOW_CONSERVATION, "true"); + Cache.setPropertyNoSave(SHOW_QUALITY, "false"); + Cache.setPropertyNoSave(SHOW_CONSENSUS, "true"); + Cache.setPropertyNoSave(SHOW_UNCONSERVED, "false"); + Cache.setPropertyNoSave(SHOW_GROUP_CONSERVATION, "false"); + Cache.setPropertyNoSave(SHOW_GROUP_CONSENSUS, "false"); + + // TODO -- just a start here + } + /** * Do any necessary validation before saving settings. Return focus to the * first tab which fails validation. @@ -921,7 +1064,7 @@ public class Preferences extends GPreferences FileFormatI format = chooser.getSelectedFormat(); if (format != null) { - Cache.applicationProperties.setProperty("DEFAULT_FILE_FORMAT", + Cache.setPropertyNoSave("DEFAULT_FILE_FORMAT", format.getName()); } startupFileTextfield @@ -979,7 +1122,7 @@ public class Preferences extends GPreferences boolean valid = false; while (!valid) { - if (JvOptionPane.showInternalConfirmDialog(Desktop.desktop, link, + if (JvOptionPane.showInternalConfirmDialog(Desktop.getDesktopPane(), link, MessageManager.getString("label.new_sequence_url_link"), JvOptionPane.OK_CANCEL_OPTION, -1, null) == JvOptionPane.OK_OPTION) @@ -1031,7 +1174,7 @@ public class Preferences extends GPreferences boolean valid = false; while (!valid) { - if (JvOptionPane.showInternalConfirmDialog(Desktop.desktop, link, + if (JvOptionPane.showInternalConfirmDialog(Desktop.getDesktopPane(), link, MessageManager.getString("label.edit_sequence_url_link"), JvOptionPane.OK_CANCEL_OPTION, -1, null) == JvOptionPane.OK_OPTION) @@ -1118,6 +1261,11 @@ public class Preferences extends GPreferences super.showunconserved_actionPerformed(e); } + /** + * not implemented -- returns empty list + * + * @return + */ public static List getGroupURLLinks() { return groupURLLinks; @@ -1204,7 +1352,7 @@ public class Preferences extends GPreferences } catch (NumberFormatException x) { userIdWidth.setText(""); - JvOptionPane.showInternalMessageDialog(Desktop.desktop, + JvOptionPane.showInternalMessageDialog(Desktop.getDesktopPane(), MessageManager .getString("warn.user_defined_width_requirements"), MessageManager.getString("label.invalid_id_column_width"), @@ -1223,14 +1371,14 @@ public class Preferences extends GPreferences * Returns true if chimera path is to a valid executable, else show an error * dialog. */ - private boolean validateChimeraPath() + protected boolean validateChimeraPath() { if (chimeraPath.getText().trim().length() > 0) { File f = new File(chimeraPath.getText()); if (!f.canExecute()) { - JvOptionPane.showInternalMessageDialog(Desktop.desktop, + JvOptionPane.showInternalMessageDialog(Desktop.getDesktopPane(), MessageManager.getString("label.invalid_chimera_path"), MessageManager.getString("label.invalid_name"), JvOptionPane.ERROR_MESSAGE); @@ -1269,7 +1417,7 @@ public class Preferences extends GPreferences if (!found) { String[] options = { "OK", "Help" }; - int showHelp = JvOptionPane.showInternalOptionDialog(Desktop.desktop, + int showHelp = JvOptionPane.showInternalOptionDialog(Desktop.getDesktopPane(), JvSwingUtils.wrapTooltip(true, MessageManager.getString("label.chimera_missing")), "", JvOptionPane.YES_NO_OPTION, JvOptionPane.WARNING_MESSAGE, @@ -1342,7 +1490,7 @@ public class Preferences extends GPreferences } } - private class UrlListSelectionHandler implements ListSelectionListener + protected class UrlListSelectionHandler implements ListSelectionListener { @Override diff --git a/src/jalview/gui/PromptUserConfig.java b/src/jalview/gui/PromptUserConfig.java index cb59452..77d83a8 100644 --- a/src/jalview/gui/PromptUserConfig.java +++ b/src/jalview/gui/PromptUserConfig.java @@ -200,7 +200,7 @@ public class PromptUserConfig implements Runnable } try { - int reply = JvOptionPane.showConfirmDialog(Desktop.desktop, // component, + int reply = JvOptionPane.showConfirmDialog(Desktop.getDesktopPane(), // component, dialogText, dialogTitle, (allowCancel) ? JvOptionPane.YES_NO_CANCEL_OPTION : JvOptionPane.YES_NO_OPTION, diff --git a/src/jalview/gui/RotatableCanvas.java b/src/jalview/gui/RotatableCanvas.java index 561fb3c..dc0cdb4 100755 --- a/src/jalview/gui/RotatableCanvas.java +++ b/src/jalview/gui/RotatableCanvas.java @@ -630,7 +630,7 @@ public class RotatableCanvas extends JPanel implements MouseListener, int yDelta = yPos - mouseY; // Check if this is a rectangle drawing drag - if ((evt.getModifiersEx() & InputEvent.BUTTON2_DOWN_MASK) != 0) + if ((evt.getModifiers() & InputEvent.BUTTON2_MASK) != 0) { // rectx2 = evt.getX(); // recty2 = evt.getY(); diff --git a/src/jalview/gui/ScalePanel.java b/src/jalview/gui/ScalePanel.java index a6b4b49..b06647d 100755 --- a/src/jalview/gui/ScalePanel.java +++ b/src/jalview/gui/ScalePanel.java @@ -54,6 +54,7 @@ import javax.swing.ToolTipManager; * The panel containing the sequence ruler (when not in wrapped mode), and * supports a range of mouse operations to select, hide or reveal columns. */ +@SuppressWarnings("serial") public class ScalePanel extends JPanel implements MouseMotionListener, MouseListener, ViewportListenerI { @@ -187,7 +188,8 @@ public class ScalePanel extends JPanel }); pop.add(item); - if (av.getAlignment().getHiddenColumns().hasMultiHiddenColumnRegions()) + if (av.getAlignment().getHiddenColumns() + .hasMultiHiddenColumnRegions()) { item = new JMenuItem(MessageManager.getString("action.reveal_all")); item.addActionListener(new ActionListener() @@ -287,8 +289,7 @@ public class ScalePanel extends JPanel // todo res calculation should be a method on AlignViewport int xCords = Math.max(0, evt.getX()); // prevent negative X coordinates ViewportRanges ranges = av.getRanges(); - int res = (xCords / av.getCharWidth()) - + ranges.getStartRes(); + int res = (xCords / av.getCharWidth()) + ranges.getStartRes(); res = Math.min(res, ranges.getEndRes()); if (av.hasHiddenColumns()) { @@ -435,7 +436,8 @@ public class ScalePanel extends JPanel @Override public void paintComponent(Graphics g) { - //super.paintComponent(g); // BH 2019 + + // super.paintComponent(g); // BH 2019 /* * shouldn't get called in wrapped mode as the scale above is @@ -523,10 +525,11 @@ public class ScalePanel extends JPanel gg.fillPolygon( new int[] - { -1 + res * avCharWidth - avCharHeight / 4, - -1 + res * avCharWidth + avCharHeight / 4, - -1 + res * avCharWidth }, new int[] - { y, y, y + 2 * yOf }, 3); + { -1 + res * avCharWidth - avCharHeight / 4, + -1 + res * avCharWidth + avCharHeight / 4, + -1 + res * avCharWidth }, + new int[] + { y, y, y + 2 * yOf }, 3); } } } @@ -566,23 +569,36 @@ public class ScalePanel extends JPanel @Override public void propertyChange(PropertyChangeEvent evt) { - // Respond to viewport change events (e.g. alignment panel was scrolled) - // Both scrolling and resizing change viewport ranges: scrolling changes - // both start and end points, but resize only changes end values. - // Here we only want to fastpaint on a scroll, with resize using a normal - // paint, so scroll events are identified as changes to the horizontal or - // vertical start value. - if (evt.getPropertyName().equals(ViewportRanges.STARTRES) - || evt.getPropertyName().equals(ViewportRanges.STARTRESANDSEQ) - || evt.getPropertyName().equals(ViewportRanges.MOVE_VIEWPORT)) + switch (evt.getPropertyName()) { + case ViewportRanges.STARTRES: + case ViewportRanges.STARTRESANDSEQ: + case ViewportRanges.MOVE_VIEWPORT: // scroll event, repaint panel - - // Call repaint on alignment panel so that repaints from other alignment - // panel components can be aggregated. Otherwise performance of the overview - // window and others may be adversely affected. - av.getAlignPanel().repaint(); + // original comment: + // Call repaint on alignment panel so that repaints from other alignment + // panel components can be aggregated. Otherwise performance of the + // overview + // window and others may be adversely affected. + + // TODO: check this? + // BH: This is actually quite strange. AlignmentPanel is taking care of + // all of this with fast paint, so why indirectly trigger a repaint from + // the ScalePanel? Where do we see this behavior necessary? + // I have set this to check for a trigger from some other ViewportRanges, + // but I don't actually think that is possible. + + if (evt.getSource() != av.getRanges()) + { + av.getAlignPanel().repaint(); + } + break; } } + public boolean isMouseDragging() + { + return mouseDragging; + } + } diff --git a/src/jalview/gui/SeqCanvas.java b/src/jalview/gui/SeqCanvas.java index e962709..123e649 100755 --- a/src/jalview/gui/SeqCanvas.java +++ b/src/jalview/gui/SeqCanvas.java @@ -352,9 +352,6 @@ public class SeqCanvas extends JPanel implements ViewportListenerI gg.copyArea(horizontal * charWidth, vertical * charHeight, img.getWidth(), img.getHeight(), -horizontal * charWidth, -vertical * charHeight); - - /** @j2sNative xxi = this.img */ - gg.translate(transX, transY); drawPanel(gg, startRes, endRes, startSeq, endSeq, 0); gg.translate(-transX, -transY); @@ -375,18 +372,22 @@ public class SeqCanvas extends JPanel implements ViewportListenerI public void paintComponent(Graphics g) { + if (av.getAlignPanel().getHoldRepaint()) + { + return; + } int charHeight = av.getCharHeight(); int charWidth = av.getCharWidth(); - int width = getWidth(); - int height = getHeight(); + int availWidth = getWidth(); + int availHeight = getHeight(); - width -= (width % charWidth); - height -= (height % charHeight); + availWidth -= (availWidth % charWidth); + availHeight -= (availHeight % charHeight); // BH 2019 can't possibly fastPaint if either width or height is 0 - if (width == 0 || height == 0) + if (availWidth == 0 || availHeight == 0) { return; } @@ -436,10 +437,11 @@ public class SeqCanvas extends JPanel implements ViewportListenerI // img is a cached version of the last view we drew. // If we have no img or the size has changed, make a new one. // - if (img == null || width != img.getWidth() - || height != img.getHeight()) + if (img == null || availWidth != img.getWidth() + || availHeight != img.getHeight()) { - img = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB); + img = new BufferedImage(availWidth, availHeight, + BufferedImage.TYPE_INT_RGB); } Graphics2D gg = (Graphics2D) img.getGraphics(); @@ -452,11 +454,11 @@ public class SeqCanvas extends JPanel implements ViewportListenerI } gg.setColor(Color.white); - gg.fillRect(0, 0, img.getWidth(), img.getHeight()); + gg.fillRect(0, 0, availWidth, availHeight); if (av.getWrapAlignment()) { - drawWrappedPanel(gg, width, height, ranges.getStartRes()); + drawWrappedPanel(gg, availWidth, availHeight, ranges.getStartRes()); } else { @@ -524,32 +526,31 @@ public class SeqCanvas extends JPanel implements ViewportListenerI } /** - * Returns the visible width of the canvas in residues, after allowing for - * East or West scales (if shown) + * Using the current font, determine fields labelWidthEast and labelWidthWest, + * and return the number of residues that can fill the remaining width. * - * @param canvasWidth + * @param width * the width in pixels (possibly including scales) * - * @return + * @return the visible width in residues, after allowing for East or West + * scales (if shown) + * */ - public int getWrappedCanvasWidth(int canvasWidth) + public int getWrappedCanvasWidth(int width) { int charWidth = av.getCharWidth(); FontMetrics fm = getFontMetrics(av.getFont()); - int labelWidth = 0; - - if (av.getScaleRightWrapped() || av.getScaleLeftWrapped()) - { - labelWidth = getLabelWidth(fm); - } + int labelWidth = (av.getScaleRightWrapped() || av.getScaleLeftWrapped() + ? getLabelWidth(fm) + : 0); labelWidthEast = av.getScaleRightWrapped() ? labelWidth : 0; labelWidthWest = av.getScaleLeftWrapped() ? labelWidth : 0; - return (canvasWidth - labelWidthEast - labelWidthWest) / charWidth; + return (width - labelWidthEast - labelWidthWest) / charWidth; } /** @@ -575,6 +576,7 @@ public class SeqCanvas extends JPanel implements ViewportListenerI maxWidth = Math.max(maxWidth, alignment.getSequenceAt(i).getEnd()); } + // quick int log10 int length = 0; for (int i = maxWidth; i > 0; i /= 10) { @@ -589,18 +591,18 @@ public class SeqCanvas extends JPanel implements ViewportListenerI * window * * @param g - * @param canvasWidth + * @param availWidth * available width in pixels - * @param canvasHeight + * @param availHeight * available height in pixels * @param startColumn * the first column (0...) of the alignment to draw */ - public void drawWrappedPanel(Graphics g, int canvasWidth, - int canvasHeight, final int startColumn) + public void drawWrappedPanel(Graphics g, int availWidth, int availHeight, + final int startColumn) { - int wrappedWidthInResidues = calculateWrappedGeometry(canvasWidth, - canvasHeight); + int wrappedWidthInResidues = calculateWrappedGeometry(availWidth, + availHeight); av.setWrappedWidth(wrappedWidthInResidues); @@ -610,7 +612,7 @@ public class SeqCanvas extends JPanel implements ViewportListenerI // we need to call this again to make sure the startColumn + // wrappedWidthInResidues values are used to calculate wrappedVisibleWidths // correctly. - calculateWrappedGeometry(canvasWidth, canvasHeight); + calculateWrappedGeometry(availWidth, availHeight); /* * draw one width at a time (excluding any scales shown), @@ -625,7 +627,7 @@ public class SeqCanvas extends JPanel implements ViewportListenerI { int endColumn = Math .min(maxWidth, start + wrappedWidthInResidues - 1); - drawWrappedWidth(g, ypos, start, endColumn, canvasHeight); + drawWrappedWidth(g, ypos, start, endColumn, availHeight); ypos += wrappedRepeatHeightPx; start += wrappedWidthInResidues; currentWidth++; @@ -644,11 +646,11 @@ public class SeqCanvas extends JPanel implements ViewportListenerI *
  • whether scales are shown left, right or above the alignment
  • * * - * @param canvasWidth - * @param canvasHeight + * @param availWidth + * @param availHeight * @return the number of residue columns in each width */ - protected int calculateWrappedGeometry(int canvasWidth, int canvasHeight) + protected int calculateWrappedGeometry(int availWidth, int availHeight) { int charHeight = av.getCharHeight(); @@ -682,8 +684,8 @@ public class SeqCanvas extends JPanel implements ViewportListenerI * ensuring a part height includes at least one sequence */ ViewportRanges ranges = av.getRanges(); - wrappedVisibleWidths = canvasHeight / wrappedRepeatHeightPx; - int remainder = canvasHeight % wrappedRepeatHeightPx; + wrappedVisibleWidths = availHeight / wrappedRepeatHeightPx; + int remainder = availHeight % wrappedRepeatHeightPx; if (remainder >= (wrappedSpaceAboveAlignment + charHeight)) { wrappedVisibleWidths++; @@ -692,7 +694,7 @@ public class SeqCanvas extends JPanel implements ViewportListenerI /* * compute width in residues; this also sets East and West label widths */ - int wrappedWidthInResidues = getWrappedCanvasWidth(canvasWidth); + int wrappedWidthInResidues = getWrappedCanvasWidth(availWidth); /* * limit visibleWidths to not exceed width of alignment @@ -1679,92 +1681,164 @@ public class SeqCanvas extends JPanel implements ViewportListenerI public void propertyChange(PropertyChangeEvent evt) { String eventName = evt.getPropertyName(); - // System.err.println(">>SeqCanvas propertyChange " + eventName); - if (eventName.equals(SequenceGroup.SEQ_GROUP_CHANGED)) - { - fastPaint = true; - repaint(); - return; - } - else if (eventName.equals(ViewportRanges.MOVE_VIEWPORT)) - { - fastPaint = false; - // System.err.println("!!!! fastPaint false from MOVE_VIEWPORT"); - repaint(); - return; - } - int scrollX = 0; - if (eventName.equals(ViewportRanges.STARTRES) - || eventName.equals(ViewportRanges.STARTRESANDSEQ)) - { - // Make sure we're not trying to draw a panel - // larger than the visible window - if (eventName.equals(ViewportRanges.STARTRES)) - { - scrollX = (int) evt.getNewValue() - (int) evt.getOldValue(); - } - else - { - scrollX = ((int[]) evt.getNewValue())[0] - - ((int[]) evt.getOldValue())[0]; - } - ViewportRanges vpRanges = av.getRanges(); + // BH 2019.07.27 removes dead code introduced in aad3650 and simplifies + // logic, emphasizing no check for ENDRES or ENDSEQ - int range = vpRanges.getEndRes() - vpRanges.getStartRes() + 1; - if (scrollX > range) - { - scrollX = range; - } - else if (scrollX < -range) - { - scrollX = -range; - } - } // Both scrolling and resizing change viewport ranges: scrolling changes // both start and end points, but resize only changes end values. // Here we only want to fastpaint on a scroll, with resize using a normal // paint, so scroll events are identified as changes to the horizontal or // vertical start value. - if (eventName.equals(ViewportRanges.STARTRES)) - { - if (av.getWrapAlignment()) - { - fastPaintWrapped(scrollX); - } - else - { - fastPaint(scrollX, 0); - } - } - else if (eventName.equals(ViewportRanges.STARTSEQ)) + + // Make sure we're not trying to draw a panel + // larger than the visible window + int scrollX = 0; + int scrollY = 0; + switch (eventName) { - // scroll + case SequenceGroup.SEQ_GROUP_CHANGED: + fastPaint = true; + repaint(); + return; + case ViewportRanges.MOVE_VIEWPORT: + fastPaint = false; + repaint(); + return; + case ViewportRanges.STARTSEQ: + // meaning STARTOREND + // typically scroll, but possibly just the end changed fastPaint(0, (int) evt.getNewValue() - (int) evt.getOldValue()); - } - else if (eventName.equals(ViewportRanges.STARTRESANDSEQ)) - { - if (av.getWrapAlignment()) - { - fastPaintWrapped(scrollX); - } - else + return; + case ViewportRanges.ENDRES: + case ViewportRanges.ENDSEQ: + // meaning second event along with "START" -- ENDONLY,NOTSTART + // TODO: ignore?? + return; + case ViewportRanges.STARTRES: + // meaning STARTOREND + scrollX = (int) evt.getNewValue() - (int) evt.getOldValue(); + break; + case ViewportRanges.STARTRESANDSEQ: + scrollX = ((int[]) evt.getNewValue())[0] + - ((int[]) evt.getOldValue())[0]; + scrollY = ((int[]) evt.getNewValue())[1] + - ((int[]) evt.getOldValue())[1]; + + // System.out.println("SC dx dy " + scrollX + " " + scrollY); + + if (scrollX != 0 && scrollY != 0) { - fastPaint(scrollX, 0); + // all sorts of problems in JavaScript if this is commented out. + repaint(); + return; + } + break; } - else if (eventName.equals(ViewportRanges.STARTSEQ)) + + ViewportRanges vpRanges = av.getRanges(); + int range = vpRanges.getEndRes() - vpRanges.getStartRes() + 1; + scrollX = Math.max(Math.min(scrollX, range), -range); + // only STARTRES or STARTRESANDSEQ: + if (av.getWrapAlignment()) { - // scroll - fastPaint(0, (int) evt.getNewValue() - (int) evt.getOldValue()); + fastPaintWrapped(scrollX); } - else if (eventName.equals(ViewportRanges.STARTRESANDSEQ)) + else { - if (av.getWrapAlignment()) - { - fastPaintWrapped(scrollX); - } + fastPaint(scrollX, scrollY); } + + // BH 2019.07.27 was: + // if (eventName.equals(SequenceGroup.SEQ_GROUP_CHANGED)) + // { + // fastPaint = true; + // repaint(); + // return; + // } + // else if (eventName.equals(ViewportRanges.MOVE_VIEWPORT)) + // { + // fastPaint = false; + // // System.err.println("!!!! fastPaint false from MOVE_VIEWPORT"); + // repaint(); + // return; + // } + // + // if (eventName.equals(ViewportRanges.STARTRES) + // || eventName.equals(ViewportRanges.STARTRESANDSEQ)) + // { + // // Make sure we're not trying to draw a panel + // // larger than the visible window + // if (eventName.equals(ViewportRanges.STARTRES)) + // { + // scrollX = (int) evt.getNewValue() - (int) evt.getOldValue(); + // } + // else + // { + // scrollX = ((int[]) evt.getNewValue())[0] + // - ((int[]) evt.getOldValue())[0]; + // } + // ViewportRanges vpRanges = av.getRanges(); + // + // int range = vpRanges.getEndRes() - vpRanges.getStartRes() + 1; + // if (scrollX > range) + // { + // scrollX = range; + // } + // else if (scrollX < -range) + // { + // scrollX = -range; + // } + // } + // Both scrolling and resizing change viewport ranges: scrolling changes + // both start and end points, but resize only changes end values. + // Here we only want to fastpaint on a scroll, with resize using a normal + // paint, so scroll events are identified as changes to the horizontal or + // vertical start value. + // BH 2019.07.27 was: + // if (eventName.equals(ViewportRanges.STARTRES)) + // { + // if (av.getWrapAlignment()) + // { + // fastPaintWrapped(scrollX); + // } + // else + // { + // fastPaint(scrollX, 0); + // } + // } + // else if (eventName.equals(ViewportRanges.STARTSEQ)) + // { + // // scroll + // fastPaint(0, (int) evt.getNewValue() - (int) evt.getOldValue()); + // } + // else if (eventName.equals(ViewportRanges.STARTRESANDSEQ)) + // { + // if (av.getWrapAlignment()) + // { + // fastPaintWrapped(scrollX); + // } + // else + // { + // fastPaint(scrollX, 0); + // } + // } + // + // BH oops! + // + // else if (eventName.equals(ViewportRanges.STARTSEQ)) + // { + // // scroll + // fastPaint(0, (int) evt.getNewValue() - (int) evt.getOldValue()); + // } + // else if (eventName.equals(ViewportRanges.STARTRESANDSEQ)) + // { + // if (av.getWrapAlignment()) + // { + // fastPaintWrapped(scrollX); + // } + // } } /** diff --git a/src/jalview/gui/SeqPanel.java b/src/jalview/gui/SeqPanel.java index 2df55ad..134e284 100644 --- a/src/jalview/gui/SeqPanel.java +++ b/src/jalview/gui/SeqPanel.java @@ -74,7 +74,8 @@ import javax.swing.Timer; import javax.swing.ToolTipManager; /** - * DOCUMENT ME! + * The main scrollable region containing the alignment and just to the right of + * the IDPanel. * * @author $author$ * @version $Revision: 1.130 $ @@ -134,7 +135,6 @@ public class SeqPanel extends JPanel MousePos o = (MousePos) obj; boolean b = (column == o.column && seqIndex == o.seqIndex && annotationIndex == o.annotationIndex); - // System.out.println(obj + (b ? "= " : "!= ") + this); return b; } @@ -224,7 +224,7 @@ public class SeqPanel extends JPanel SearchResultsI lastSearchResults; /** - * Creates a new SeqPanel object + * Create a new SeqPanel. * * @param viewport * @param alignPanel @@ -1504,7 +1504,6 @@ public class SeqPanel extends JPanel return; } - // System.out.print(y1+" "+y2+" "+fixedLeft+" "+fixedRight+"~~"); // Selection spans a hidden region if (fixedLeft < y1 && (fixedRight > y2 || fixedRight == -1)) { @@ -1944,12 +1943,21 @@ public class SeqPanel extends JPanel { lastMousePosition = null; ap.alignFrame.setStatus(" "); + if (av.getWrapAlignment()) { return; } - if (mouseDragging && scrollThread == null) + /* + * start scrolling if mouse dragging, whether the drag started + * in the scale panel or this panel + */ + if (ap.getScalePanel().isMouseDragging()) + { + ap.getScalePanel().mouseExited(e); + } + else if (mouseDragging && scrollThread == null) { startScrolling(e.getPoint()); } @@ -2424,29 +2432,22 @@ public class SeqPanel extends JPanel // if (!scrollOnce() {t.stop();}) gives compiler error :-( scrollThread.scrollOnce(); } - } - }); - t.addActionListener(new ActionListener() - { - @Override - public void actionPerformed(ActionEvent e) - { if (scrollThread == null) { // SeqPanel.stopScrolling called - t.stop(); + ((Timer) e.getSource()).stop(); } } }); t.start(); } - } - else - { - /* - * Java - run in a new thread - */ - scrollThread.start(); + else + { + /* + * Java - run in a new thread + */ + scrollThread.start(); + } } } @@ -2770,4 +2771,45 @@ public class SeqPanel extends JPanel { return lastSearchResults; } + + /** + * scroll to the given row/column - or nearest visible location + * + * @param row + * @param column + */ + public void scrollTo(int row, int column) + { + + row = row < 0 ? ap.av.getRanges().getStartSeq() : row; + column = column < 0 ? ap.av.getRanges().getStartRes() : column; + ap.scrollTo(column, column, row, true, true); + } + + /** + * scroll to the given row - or nearest visible location + * + * @param row + */ + public void scrollToRow(int row) + { + + row = row < 0 ? ap.av.getRanges().getStartSeq() : row; + ap.scrollTo(ap.av.getRanges().getStartRes(), + ap.av.getRanges().getStartRes(), row, true, true); + } + + /** + * scroll to the given column - or nearest visible location + * + * @param column + */ + public void scrollToColumn(int column) + { + + column = column < 0 ? ap.av.getRanges().getStartRes() : column; + ap.scrollTo(column, column, ap.av.getRanges().getStartSeq(), true, + true); + } + } diff --git a/src/jalview/gui/SequenceFetcher.java b/src/jalview/gui/SequenceFetcher.java index 646a7f1..b8e3b33 100755 --- a/src/jalview/gui/SequenceFetcher.java +++ b/src/jalview/gui/SequenceFetcher.java @@ -64,9 +64,9 @@ import javax.swing.SwingConstants; * If the selected source is Uniprot or PDB, a free text search panel is opened * instead to perform the search and selection. */ +@SuppressWarnings("serial") public class SequenceFetcher extends JPanel implements Runnable { - private static jalview.ws.SequenceFetcher sfetch = null; JLabel exampleAccession; @@ -97,20 +97,6 @@ public class SequenceFetcher extends JPanel implements Runnable volatile boolean _isConstructing = false; /** - * Returns the shared instance of the SequenceFetcher client - * - * @return - */ - public static jalview.ws.SequenceFetcher getSequenceFetcherSingleton() - { - if (sfetch == null) - { - sfetch = new jalview.ws.SequenceFetcher(); - } - return sfetch; - } - - /** * Constructor given a client to receive any status or progress messages * (currently either the Desktop, or an AlignFrame panel) * @@ -132,7 +118,7 @@ public class SequenceFetcher extends JPanel implements Runnable final String selectedDb, final String queryString) { this.progressIndicator = guiIndic; - getSequenceFetcherSingleton(); + this.guiWindow = progressIndicator; if (progressIndicator instanceof AlignFrame) @@ -164,7 +150,8 @@ public class SequenceFetcher extends JPanel implements Runnable database = new JComboBox<>(); database.setFont(JvSwingUtils.getLabelFont()); database.setPrototypeDisplayValue("ENSEMBLGENOMES "); - String[] sources = new jalview.ws.SequenceFetcher().getSupportedDb(); + String[] sources = jalview.ws.SequenceFetcher.getInstance() + .getSupportedDb(); Arrays.sort(sources, String.CASE_INSENSITIVE_ORDER); database.addItem(MessageManager.getString("action.select_ddbb")); for (String source : sources) @@ -315,7 +302,8 @@ public class SequenceFetcher extends JPanel implements Runnable { StringBuilder sb = new StringBuilder(); HashSet hs = new HashSet<>(); - for (DbSourceProxy dbs : sfetch.getSourceProxy(db)) + for (DbSourceProxy dbs : jalview.ws.SequenceFetcher.getInstance() + .getSourceProxy(db)) { String tq = dbs.getTestQuery(); if (hs.add(tq)) // not a duplicate source @@ -463,7 +451,7 @@ public class SequenceFetcher extends JPanel implements Runnable List presultTitle = new ArrayList<>(); List presult = new ArrayList<>(); List aresult = new ArrayList<>(); - List sources = sfetch + List sources = jalview.ws.SequenceFetcher.getInstance() .getSourceProxy((String) database.getSelectedItem()); Iterator proxies = sources.iterator(); String[] qries = textArea.getText().trim().split(";"); @@ -827,7 +815,7 @@ public class SequenceFetcher extends JPanel implements Runnable { af.getViewport().applyFeaturesStyle(preferredFeatureColours); } - if (Cache.getDefault("HIDE_INTRONS", true)) + if (Cache.getDefault(Preferences.HIDE_INTRONS, true)) { af.hideFeatureColumns(SequenceOntologyI.EXON, false); } @@ -839,7 +827,8 @@ public class SequenceFetcher extends JPanel implements Runnable try { - af.setMaximum(Cache.getDefault("SHOW_FULLSCREEN", false)); + af.setMaximum( + Cache.getDefault(Preferences.SHOW_FULLSCREEN, false)); } catch (Exception ex) { } @@ -860,7 +849,7 @@ public class SequenceFetcher extends JPanel implements Runnable @Override public void run() { - JvOptionPane.showInternalMessageDialog(Desktop.desktop, error, + JvOptionPane.showInternalMessageDialog(Desktop.getDesktopPane(), error, MessageManager.getString("label.error_retrieving_data"), JvOptionPane.WARNING_MESSAGE); } diff --git a/src/jalview/gui/SequenceRenderer.java b/src/jalview/gui/SequenceRenderer.java index fb967ed..81b394b 100755 --- a/src/jalview/gui/SequenceRenderer.java +++ b/src/jalview/gui/SequenceRenderer.java @@ -30,9 +30,6 @@ import java.awt.Color; import java.awt.FontMetrics; import java.awt.Graphics; -import org.jfree.graphics2d.svg.SVGGraphics2D; -import org.jibble.epsgraphics.EpsGraphics2D; - public class SequenceRenderer implements jalview.api.SequenceRenderer { final static int CHAR_TO_UPPER = 'A' - 'a'; @@ -257,19 +254,8 @@ public class SequenceRenderer implements jalview.api.SequenceRenderer } graphics.setColor(av.getTextColour()); - boolean drawAllText = monospacedFont && av.getShowText() && allGroups.length == 0 - && !av.getColourText() && av.getThresholdTextColour() == 0; - - /* - * EPS or SVG misaligns monospaced strings (JAL-3239) - * so always draw these one character at a time - */ - if (graphics instanceof EpsGraphics2D - || graphics instanceof SVGGraphics2D) - { - drawAllText = false; - } - if (drawAllText) + if (monospacedFont && av.getShowText() && allGroups.length == 0 + && !av.getColourText() && av.getThresholdTextColour() == 0) { if (av.isRenderGaps()) { diff --git a/src/jalview/gui/SliderPanel.java b/src/jalview/gui/SliderPanel.java index 46b47a2..31ad083 100755 --- a/src/jalview/gui/SliderPanel.java +++ b/src/jalview/gui/SliderPanel.java @@ -26,7 +26,6 @@ import jalview.jbgui.GSliderPanel; import jalview.renderer.ResidueShaderI; import jalview.util.MessageManager; -import java.awt.event.ActionEvent; import java.awt.event.MouseAdapter; import java.awt.event.MouseEvent; import java.beans.PropertyVetoException; @@ -45,14 +44,11 @@ import javax.swing.event.InternalFrameEvent; * @author $author$ * @version $Revision$ */ +@SuppressWarnings("serial") public class SliderPanel extends GSliderPanel { private static final String BACKGROUND = "Background"; - static JInternalFrame conservationSlider; - - static JInternalFrame PIDSlider; - AlignmentPanel ap; boolean forConservation = true; @@ -66,6 +62,12 @@ public class SliderPanel extends GSliderPanel */ public static SliderPanel getSliderPanel() { + + JInternalFrame conservationSlider = Desktop + .getInstance().conservationSlider; + + JInternalFrame PIDSlider = Desktop.getInstance().PIDSlider; + if (conservationSlider != null && conservationSlider.isVisible()) { return (SliderPanel) conservationSlider.getContentPane(); @@ -153,10 +155,14 @@ public class SliderPanel extends GSliderPanel { SliderPanel sliderPanel = null; + JInternalFrame conservationSlider = Desktop + .getInstance().conservationSlider; + if (conservationSlider == null) { sliderPanel = new SliderPanel(ap, rs.getConservationInc(), true, rs); - conservationSlider = new JInternalFrame(); + conservationSlider = Desktop + .getInstance().conservationSlider = new JInternalFrame(); conservationSlider.setContentPane(sliderPanel); conservationSlider.setLayer(JLayeredPane.PALETTE_LAYER); } @@ -192,12 +198,14 @@ public class SliderPanel extends GSliderPanel */ public static void hidePIDSlider() { + JInternalFrame PIDSlider = Desktop.getInstance().PIDSlider; + if (PIDSlider != null) { try { PIDSlider.setClosed(true); - PIDSlider = null; + Desktop.getInstance().PIDSlider = null; } catch (PropertyVetoException ex) { } @@ -209,12 +217,15 @@ public class SliderPanel extends GSliderPanel */ public static void hideConservationSlider() { + JInternalFrame conservationSlider = Desktop + .getInstance().conservationSlider; + if (conservationSlider != null) { try { conservationSlider.setClosed(true); - conservationSlider = null; + Desktop.getInstance().conservationSlider = null; } catch (PropertyVetoException ex) { } @@ -228,6 +239,9 @@ public class SliderPanel extends GSliderPanel { hidePIDSlider(); + JInternalFrame conservationSlider = Desktop + .getInstance().conservationSlider; + if (!conservationSlider.isVisible()) { Desktop.addInternalFrame(conservationSlider, @@ -238,7 +252,7 @@ public class SliderPanel extends GSliderPanel @Override public void internalFrameClosed(InternalFrameEvent e) { - conservationSlider = null; + Desktop.getInstance().conservationSlider = null; } }); conservationSlider.setLayer(JLayeredPane.PALETTE_LAYER); @@ -264,10 +278,12 @@ public class SliderPanel extends GSliderPanel SliderPanel sliderPanel = null; + JInternalFrame PIDSlider = Desktop.getInstance().PIDSlider; + if (PIDSlider == null) { sliderPanel = new SliderPanel(ap, threshold, false, rs); - PIDSlider = new JInternalFrame(); + PIDSlider = Desktop.getInstance().PIDSlider = new JInternalFrame(); PIDSlider.setContentPane(sliderPanel); PIDSlider.setLayer(JLayeredPane.PALETTE_LAYER); } @@ -305,6 +321,8 @@ public class SliderPanel extends GSliderPanel { hideConservationSlider(); + JInternalFrame PIDSlider = Desktop.getInstance().PIDSlider; + if (!PIDSlider.isVisible()) { Desktop.addInternalFrame(PIDSlider, PIDSlider.getTitle(), true, @@ -315,7 +333,7 @@ public class SliderPanel extends GSliderPanel @Override public void internalFrameClosed(InternalFrameEvent e) { - PIDSlider = null; + Desktop.getInstance().PIDSlider = null; } }); PIDSlider.setLayer(JLayeredPane.PALETTE_LAYER); @@ -451,7 +469,7 @@ public class SliderPanel extends GSliderPanel public static int getConservationValue() { - return getValue(conservationSlider); + return getValue(Desktop.getInstance().conservationSlider); } static int getValue(JInternalFrame slider) @@ -462,7 +480,7 @@ public class SliderPanel extends GSliderPanel public static int getPIDValue() { - return getValue(PIDSlider); + return getValue(Desktop.getInstance().PIDSlider); } /** @@ -485,6 +503,10 @@ public class SliderPanel extends GSliderPanel public String getTitle() { String title = null; + JInternalFrame conservationSlider = Desktop + .getInstance().conservationSlider; + JInternalFrame PIDSlider = Desktop.getInstance().PIDSlider; + if (isForConservation()) { if (conservationSlider != null) diff --git a/src/jalview/gui/SplashScreen.java b/src/jalview/gui/SplashScreen.java index 2b87e10..f5648d2 100755 --- a/src/jalview/gui/SplashScreen.java +++ b/src/jalview/gui/SplashScreen.java @@ -101,7 +101,7 @@ public class SplashScreen extends JPanel */ { authlist = new JTextPane(); - Thread t = new Thread(this); + Thread t = new Thread(this, "SplashScreen"); t.start(); } } @@ -160,7 +160,7 @@ public class SplashScreen extends JPanel System.err.println("Error when loading images!"); } } while (!mt.checkAll()); - Desktop.instance.setIconImage(logo); + Desktop.getInstance().setIconImage(logo); } } catch (Exception ex) { @@ -191,7 +191,7 @@ public class SplashScreen extends JPanel } add(authlist, BorderLayout.CENTER); authlist.addMouseListener(closer); - Desktop.desktop.add(iframe); + Desktop.getDesktopPane().add(iframe); refreshText(); } @@ -203,7 +203,8 @@ public class SplashScreen extends JPanel @SuppressWarnings("unused") protected boolean refreshText() { - String newtext = Desktop.instance.getAboutMessage(true).toString(); + Desktop desktop = Desktop.getInstance(); + String newtext = desktop.getAboutMessage(true).toString(); // System.err.println("Text found: \n"+newtext+"\nEnd of newtext."); if (oldtext != newtext.length()) { @@ -236,8 +237,8 @@ public class SplashScreen extends JPanel authlist.setSize(new Dimension(750, 375)); add(authlist, BorderLayout.CENTER); revalidate(); - iframe.setBounds((Desktop.instance.getWidth() - 750) / 2, - (Desktop.instance.getHeight() - 375) / 2, 750, + iframe.setBounds((desktop.getWidth() - 750) / 2, + (desktop.getHeight() - 375) / 2, 750, authlist.getHeight() + iconimg.getHeight()); iframe.validate(); iframe.setVisible(true); @@ -287,7 +288,7 @@ public class SplashScreen extends JPanel } closeSplash(); - Desktop.instance.startDialogQueue(); + Desktop.getInstance().startDialogQueue(); } /** diff --git a/src/jalview/gui/SplitFrame.java b/src/jalview/gui/SplitFrame.java index 10738e8..253b02c 100644 --- a/src/jalview/gui/SplitFrame.java +++ b/src/jalview/gui/SplitFrame.java @@ -132,7 +132,7 @@ public class SplitFrame extends GSplitFrame implements SplitContainerI // allow about 65 pixels for Desktop decorators on Windows int newHeight = Math.min(height, - Desktop.instance.getHeight() - DESKTOP_DECORATORS_HEIGHT); + Desktop.getInstance().getHeight() - DESKTOP_DECORATORS_HEIGHT); if (newHeight != height) { int oldDividerLocation = getDividerLocation(); @@ -149,8 +149,8 @@ public class SplitFrame extends GSplitFrame implements SplitContainerI { // TODO if CommandListener is only ever 1:1 for complementary views, // may change broadcast pattern to direct messaging (more efficient) - final StructureSelectionManager ssm = StructureSelectionManager - .getStructureSelectionManager(Desktop.instance); + final StructureSelectionManager ssm = Desktop + .getStructureSelectionManager(); ssm.addCommandListener(((AlignFrame) getTopFrame()).getViewport()); ssm.addCommandListener(((AlignFrame) getBottomFrame()).getViewport()); } @@ -282,7 +282,7 @@ public class SplitFrame extends GSplitFrame implements SplitContainerI public void internalFrameClosed(InternalFrameEvent evt) { close(); - }; + } }); } @@ -412,7 +412,7 @@ public class SplitFrame extends GSplitFrame implements SplitContainerI * Ctrl-W / Cmd-W - close view or window */ KeyStroke key_cmdW = KeyStroke.getKeyStroke(KeyEvent.VK_W, - jalview.util.ShortcutKeyMaskExWrapper.getMenuShortcutKeyMaskEx(), false); + Toolkit.getDefaultToolkit().getMenuShortcutKeyMask(), false); action = new AbstractAction() { @Override @@ -433,7 +433,7 @@ public class SplitFrame extends GSplitFrame implements SplitContainerI * Ctrl-T / Cmd-T open new view */ KeyStroke key_cmdT = KeyStroke.getKeyStroke(KeyEvent.VK_T, - jalview.util.ShortcutKeyMaskExWrapper.getMenuShortcutKeyMaskEx(), false); + Toolkit.getDefaultToolkit().getMenuShortcutKeyMask(), false); AbstractAction action = new AbstractAction() { @Override @@ -555,8 +555,8 @@ public class SplitFrame extends GSplitFrame implements SplitContainerI */ adjustLayout(); - final StructureSelectionManager ssm = StructureSelectionManager - .getStructureSelectionManager(Desktop.instance); + final StructureSelectionManager ssm = Desktop + .getStructureSelectionManager(); ssm.addCommandListener(newTopPanel.av); ssm.addCommandListener(newBottomPanel.av); } @@ -683,7 +683,7 @@ public class SplitFrame extends GSplitFrame implements SplitContainerI */ protected void expandViews_actionPerformed() { - Desktop.instance.explodeViews(this); + Desktop.getInstance().explodeViews(this); } /** @@ -692,7 +692,7 @@ public class SplitFrame extends GSplitFrame implements SplitContainerI */ protected void gatherViews_actionPerformed() { - Desktop.instance.gatherViews(this); + Desktop.getInstance().gatherViews(this); } /** @@ -773,7 +773,7 @@ public class SplitFrame extends GSplitFrame implements SplitContainerI * Ctrl-F / Cmd-F open Finder dialog, 'focused' on the right alignment */ KeyStroke key_cmdF = KeyStroke.getKeyStroke(KeyEvent.VK_F, - jalview.util.ShortcutKeyMaskExWrapper.getMenuShortcutKeyMaskEx(), false); + Toolkit.getDefaultToolkit().getMenuShortcutKeyMask(), false); AbstractAction action = new AbstractAction() { @Override diff --git a/src/jalview/gui/StructureChooser.java b/src/jalview/gui/StructureChooser.java index 23b7fcf..9c4f6c8 100644 --- a/src/jalview/gui/StructureChooser.java +++ b/src/jalview/gui/StructureChooser.java @@ -36,11 +36,8 @@ import jalview.fts.core.FTSRestResponse; import jalview.fts.service.pdb.PDBFTSRestClient; import jalview.io.DataSourceType; import jalview.jbgui.GStructureChooser; -import jalview.structure.StructureMapping; import jalview.structure.StructureSelectionManager; import jalview.util.MessageManager; -import jalview.ws.DBRefFetcher; -import jalview.ws.sifts.SiftsSettings; import java.awt.event.ItemEvent; import java.util.ArrayList; @@ -71,27 +68,25 @@ public class StructureChooser extends GStructureChooser { private static final String AUTOSUPERIMPOSE = "AUTOSUPERIMPOSE"; - private static int MAX_QLENGTH = 7820; + private static final int MAX_QLENGTH = 7820; - private SequenceI selectedSequence; + protected SequenceI selectedSequence; - private SequenceI[] selectedSequences; + public SequenceI[] selectedSequences; private IProgressIndicator progressIndicator; - private Collection discoveredStructuresSet; + protected Collection discoveredStructuresSet; - private FTSRestRequest lastPdbRequest; + protected FTSRestRequest lastPdbRequest; - private FTSRestClientI pdbRestClient; + protected FTSRestClientI pdbRestClient; - private String selectedPdbFileName; + protected String selectedPdbFileName; - private boolean isValidPBDEntry; + protected boolean isValidPBDEntry; - private boolean cachedPDBExists; - - private static StructureViewer lastTargetedView = null; + protected boolean cachedPDBExists; public StructureChooser(SequenceI[] selectedSeqs, SequenceI selectedSeq, AlignmentPanel ap) @@ -146,21 +141,24 @@ public class StructureChooser extends GStructureChooser * structures may be added. If this list is empty then it, and the 'Add' * button, are hidden. */ - private void discoverStructureViews() + protected void discoverStructureViews() { - if (Desktop.instance != null) + Desktop desktop = Desktop.getInstance(); + if (desktop != null) { targetView.removeAllItems(); - if (lastTargetedView != null && !lastTargetedView.isVisible()) + if (desktop.lastTargetedView != null + && !desktop.lastTargetedView.isVisible()) { - lastTargetedView = null; + desktop.lastTargetedView = null; } int linkedViewsAt = 0; - for (StructureViewerBase view : Desktop.instance + for (StructureViewerBase view : desktop .getStructureViewers(null, null)) { - StructureViewer viewHandler = (lastTargetedView != null - && lastTargetedView.sview == view) ? lastTargetedView + StructureViewer viewHandler = (desktop.lastTargetedView != null + && desktop.lastTargetedView.sview == view) + ? desktop.lastTargetedView : StructureViewer.reconfigure(view); if (view.isLinkedWith(ap)) @@ -181,9 +179,9 @@ public class StructureChooser extends GStructureChooser if (targetView.getItemCount() > 0) { targetView.setVisible(true); - if (lastTargetedView != null) + if (desktop.lastTargetedView != null) { - targetView.setSelectedItem(lastTargetedView); + targetView.setSelectedItem(desktop.lastTargetedView); } else { @@ -874,13 +872,11 @@ public class StructureChooser extends GStructureChooser /** * structure viewer opened by this dialog, or null */ - private StructureViewer sViewer = null; + protected StructureViewer sViewer = null; public void showStructures(boolean waitUntilFinished) { - final StructureSelectionManager ssm = ap.getStructureSelectionManager(); - final int preferredHeight = pnl_filter.getHeight(); Runnable viewStruc = new Runnable() @@ -929,7 +925,7 @@ public class StructureChooser extends GStructureChooser } SequenceI[] selectedSeqs = selectedSeqsToView .toArray(new SequenceI[selectedSeqsToView.size()]); - sViewer = launchStructureViewer(ssm, pdbEntriesToView, ap, + sViewer = launchStructureViewer(ap, pdbEntriesToView, selectedSeqs); } else if (currentView == VIEWS_LOCAL_PDB) @@ -953,7 +949,7 @@ public class StructureChooser extends GStructureChooser } SequenceI[] selectedSeqs = selectedSeqsToView .toArray(new SequenceI[selectedSeqsToView.size()]); - sViewer = launchStructureViewer(ssm, pdbEntriesToView, ap, + sViewer = launchStructureViewer(ap, pdbEntriesToView, selectedSeqs); } else if (currentView == VIEWS_ENTER_ID) @@ -983,7 +979,7 @@ public class StructureChooser extends GStructureChooser } PDBEntry[] pdbEntriesToView = new PDBEntry[] { pdbEntry }; - sViewer = launchStructureViewer(ssm, pdbEntriesToView, ap, + sViewer = launchStructureViewer(ap, pdbEntriesToView, new SequenceI[] { selectedSequence }); } @@ -995,14 +991,13 @@ public class StructureChooser extends GStructureChooser { selectedSequence = userSelectedSeq; } - PDBEntry fileEntry = new AssociatePdbFileWithSeq() + PDBEntry fileEntry = AssociatePdbFileWithSeq .associatePdbWithSeq(selectedPdbFileName, - DataSourceType.FILE, selectedSequence, true, - Desktop.instance); + DataSourceType.FILE, selectedSequence, true); sViewer = launchStructureViewer( - ssm, new PDBEntry[] - { fileEntry }, ap, + ap, new PDBEntry[] + { fileEntry }, new SequenceI[] { selectedSequence }); } @@ -1036,7 +1031,7 @@ public class StructureChooser extends GStructureChooser } } - private PDBEntry getFindEntry(String id, Vector pdbEntries) + protected PDBEntry getFindEntry(String id, Vector pdbEntries) { Objects.requireNonNull(id); Objects.requireNonNull(pdbEntries); @@ -1055,13 +1050,12 @@ public class StructureChooser extends GStructureChooser * Answers a structure viewer (new or existing) configured to superimpose * added structures or not according to the user's choice * - * @param ssm * @return */ - StructureViewer getTargetedStructureViewer( - StructureSelectionManager ssm) + StructureViewer getTargetedStructureViewer() { - Object sv = targetView.getSelectedItem(); + final StructureSelectionManager ssm = ap.getStructureSelectionManager(); + Object sv = (targetView == null ? null : targetView.getSelectedItem()); return sv == null ? new StructureViewer(ssm) : (StructureViewer) sv; } @@ -1069,93 +1063,24 @@ public class StructureChooser extends GStructureChooser /** * Adds PDB structures to a new or existing structure viewer * - * @param ssm + * @param ap * @param pdbEntriesToView - * @param alignPanel * @param sequences - * @return + * @param superimpose + * @return viewer */ - private StructureViewer launchStructureViewer( - StructureSelectionManager ssm, - final PDBEntry[] pdbEntriesToView, - final AlignmentPanel alignPanel, SequenceI[] sequences) + protected StructureViewer launchStructureViewer( + AlignmentPanel ap, PDBEntry[] pdbEntriesToView, + SequenceI[] selectedSeqs) { - long progressId = sequences.hashCode(); - setProgressBar(MessageManager - .getString("status.launching_3d_structure_viewer"), progressId); - final StructureViewer theViewer = getTargetedStructureViewer(ssm); boolean superimpose = chk_superpose.isSelected(); - theViewer.setSuperpose(superimpose); - /* * remember user's choice of superimpose or not */ Cache.setProperty(AUTOSUPERIMPOSE, Boolean.valueOf(superimpose).toString()); - - setProgressBar(null, progressId); - if (SiftsSettings.isMapWithSifts()) - { - List seqsWithoutSourceDBRef = new ArrayList<>(); - int p = 0; - // TODO: skip PDBEntry:Sequence pairs where PDBEntry doesn't look like a - // real PDB ID. For moment, we can also safely do this if there is already - // a known mapping between the PDBEntry and the sequence. - for (SequenceI seq : sequences) - { - PDBEntry pdbe = pdbEntriesToView[p++]; - if (pdbe != null && pdbe.getFile() != null) - { - StructureMapping[] smm = ssm.getMapping(pdbe.getFile()); - if (smm != null && smm.length > 0) - { - for (StructureMapping sm : smm) - { - if (sm.getSequence() == seq) - { - continue; - } - } - } - } - if (seq.getPrimaryDBRefs().isEmpty()) - { - seqsWithoutSourceDBRef.add(seq); - continue; - } - } - if (!seqsWithoutSourceDBRef.isEmpty()) - { - int y = seqsWithoutSourceDBRef.size(); - setProgressBar(MessageManager.formatMessage( - "status.fetching_dbrefs_for_sequences_without_valid_refs", - y), progressId); - SequenceI[] seqWithoutSrcDBRef = seqsWithoutSourceDBRef - .toArray(new SequenceI[y]); - DBRefFetcher dbRefFetcher = new DBRefFetcher(seqWithoutSrcDBRef); - dbRefFetcher.fetchDBRefs(true); - - setProgressBar("Fetch complete.", progressId); // todo i18n - } - } - if (pdbEntriesToView.length > 1) - { - setProgressBar(MessageManager.getString( - "status.fetching_3d_structures_for_selected_entries"), - progressId); - theViewer.viewStructures(pdbEntriesToView, sequences, alignPanel); - } - else - { - setProgressBar(MessageManager.formatMessage( - "status.fetching_3d_structures_for", - pdbEntriesToView[0].getId()),progressId); - theViewer.viewStructures(pdbEntriesToView[0], sequences, alignPanel); - } - setProgressBar(null, progressId); - // remember the last viewer we used... - lastTargetedView = theViewer; - return theViewer; + return StructureViewer.launchStructureViewer(ap, pdbEntriesToView, selectedSeqs, + superimpose, getTargetedStructureViewer(), progressBar); } /** @@ -1202,7 +1127,8 @@ public class StructureChooser extends GStructureChooser protected void txt_search_ActionPerformed() { String text = txt_search.getText().trim(); - if (text.length() >= PDB_ID_MIN) + if (text.length() >= PDB_ID_MIN) + { new Thread() { @@ -1248,6 +1174,7 @@ public class StructureChooser extends GStructureChooser } }.start(); } + } @Override protected void tabRefresh() @@ -1374,7 +1301,10 @@ public class StructureChooser extends GStructureChooser @Override public void setProgressBar(String message, long id) { - progressBar.setProgressBar(message, id); + if (progressBar != null) + { + progressBar.setProgressBar(message, id); + } } @Override diff --git a/src/jalview/gui/StructureViewer.java b/src/jalview/gui/StructureViewer.java index 0c8354b..dc5d77d 100644 --- a/src/jalview/gui/StructureViewer.java +++ b/src/jalview/gui/StructureViewer.java @@ -25,7 +25,12 @@ import jalview.bin.Cache; import jalview.datamodel.PDBEntry; import jalview.datamodel.SequenceI; import jalview.datamodel.StructureViewerModel; +import jalview.structure.StructureMapping; import jalview.structure.StructureSelectionManager; +import jalview.util.MessageManager; +import jalview.util.Platform; +import jalview.ws.DBRefFetcher; +import jalview.ws.sifts.SiftsSettings; import java.awt.Rectangle; import java.util.ArrayList; @@ -45,6 +50,13 @@ import java.util.Map.Entry; */ public class StructureViewer { + + static + { + Platform.loadStaticResource("core/core_jvjmol.z.js", + "org.jmol.viewer.Viewer"); + } + private static final String UNKNOWN_VIEWER_TYPE = "Unknown structure viewer type "; StructureSelectionManager ssm; @@ -388,4 +400,135 @@ public class StructureViewer superposeAdded = alignAddedStructures; } + /** + * Launch a minimal implementation of a StructureViewer. + * + * @param alignPanel + * @param pdb + * @param seqs + * @return + */ + public static StructureViewer launchStructureViewer( + AlignmentPanel alignPanel, PDBEntry pdb, SequenceI[] seqs) + { + return launchStructureViewer(alignPanel, new PDBEntry[] { pdb }, seqs, + false, null, null); + } + + /** + * Launch a structure viewer with or without an open StructureChooser. + * + * Moved from StructureChooser to enable JalviewJS startup with structure + * display. + * + * @param ap + * @param pdbEntriesToView + * @param sequences + * @param superimpose + * @param theViewer + * @param pb + * @return + */ + protected static StructureViewer launchStructureViewer( + final AlignmentPanel ap, + final PDBEntry[] pdbEntriesToView, SequenceI[] sequences, + boolean superimpose, StructureViewer theViewer, + IProgressIndicator pb) + { + final StructureSelectionManager ssm = ap.getStructureSelectionManager(); + long progressId = sequences.hashCode(); + if (pb != null) + { + pb.setProgressBar(MessageManager + .getString("status.launching_3d_structure_viewer"), progressId); + } + if (theViewer == null) + { + theViewer = new StructureViewer(ssm); + } + theViewer.setSuperpose(superimpose); + + if (pb != null) + { + pb.setProgressBar(null, progressId); + } + if (SiftsSettings.isMapWithSifts()) + { + List seqsWithoutSourceDBRef = new ArrayList<>(); + int p = 0; + // TODO: skip PDBEntry:Sequence pairs where PDBEntry doesn't look like a + // real PDB ID. For moment, we can also safely do this if there is already + // a known mapping between the PDBEntry and the sequence. + for (SequenceI seq : sequences) + { + PDBEntry pdbe = pdbEntriesToView[p++]; + if (pdbe != null && pdbe.getFile() != null) + { + StructureMapping[] smm = ssm.getMapping(pdbe.getFile()); + if (smm != null && smm.length > 0) + { + for (StructureMapping sm : smm) + { + if (sm.getSequence() == seq) + { + continue; + } + } + } + } + if (seq.getPrimaryDBRefs().isEmpty()) + { + seqsWithoutSourceDBRef.add(seq); + continue; + } + } + if (!seqsWithoutSourceDBRef.isEmpty()) + { + int y = seqsWithoutSourceDBRef.size(); + if (pb != null) + { + pb.setProgressBar(MessageManager.formatMessage( + "status.fetching_dbrefs_for_sequences_without_valid_refs", + y), progressId); + } + SequenceI[] seqWithoutSrcDBRef = seqsWithoutSourceDBRef + .toArray(new SequenceI[y]); + DBRefFetcher dbRefFetcher = new DBRefFetcher(seqWithoutSrcDBRef); + dbRefFetcher.fetchDBRefs(true); + + if (pb != null) + { + pb.setProgressBar("Fetch complete.", progressId); // todo i18n + } + } + } + if (pdbEntriesToView.length > 1) + { + if (pb != null) + { + pb.setProgressBar(MessageManager.getString( + "status.fetching_3d_structures_for_selected_entries"), + progressId); + } + theViewer.viewStructures(pdbEntriesToView, sequences, ap); + } + else + { + if (pb != null) + { + pb.setProgressBar(MessageManager.formatMessage( + "status.fetching_3d_structures_for", + pdbEntriesToView[0].getId()),progressId); + } + theViewer.viewStructures(pdbEntriesToView[0], sequences, ap); + } + if (pb != null) + { + pb.setProgressBar(null, progressId); + } + // remember the last viewer we used... + Desktop.getInstance().lastTargetedView = theViewer; + return theViewer; + } + } diff --git a/src/jalview/gui/StructureViewerBase.java b/src/jalview/gui/StructureViewerBase.java index 418a84d..af48093 100644 --- a/src/jalview/gui/StructureViewerBase.java +++ b/src/jalview/gui/StructureViewerBase.java @@ -407,7 +407,7 @@ public abstract class StructureViewerBase extends GStructureViewer */ protected List getViewersFor(AlignmentPanel alp) { - return Desktop.instance.getStructureViewers(alp, this.getClass()); + return Desktop.getInstance().getStructureViewers(alp, this.getClass()); } @Override diff --git a/src/jalview/gui/UserDefinedColours.java b/src/jalview/gui/UserDefinedColours.java index 4846049..6e3a68b 100755 --- a/src/jalview/gui/UserDefinedColours.java +++ b/src/jalview/gui/UserDefinedColours.java @@ -69,8 +69,6 @@ public class UserDefinedColours extends GUserDefinedColours private static final Font VERDANA_BOLD_10 = new Font("Verdana", Font.BOLD, 10); - public static final String USER_DEFINED_COLOURS = "USER_DEFINED_COLOURS"; - private static final String LAST_DIRECTORY = "LAST_DIRECTORY"; private static final int MY_FRAME_HEIGHT = 440; @@ -448,7 +446,7 @@ public class UserDefinedColours extends GUserDefinedColours { if (isNoSelectionMade()) { - JvOptionPane.showMessageDialog(Desktop.desktop, + JvOptionPane.showMessageDialog(Desktop.getDesktopPane(), MessageManager .getString("label.no_colour_selection_in_scheme"), MessageManager.getString("label.no_colour_selection_warn"), @@ -503,7 +501,7 @@ public class UserDefinedColours extends GUserDefinedColours String[] options = new String[] { title, MessageManager.getString("label.dont_save_changes"), }; final String question = JvSwingUtils.wrapTooltip(true, message); - int response = JvOptionPane.showOptionDialog(Desktop.desktop, + int response = JvOptionPane.showOptionDialog(Desktop.getDesktopPane(), question, title, JvOptionPane.DEFAULT_OPTION, JvOptionPane.PLAIN_MESSAGE, null, options, options[0]); @@ -557,7 +555,7 @@ public class UserDefinedColours extends GUserDefinedColours { if (isNoSelectionMade()) { - JvOptionPane.showMessageDialog(Desktop.desktop, + JvOptionPane.showMessageDialog(Desktop.getDesktopPane(), MessageManager .getString("label.no_colour_selection_in_scheme"), MessageManager.getString("label.no_colour_selection_warn"), @@ -694,7 +692,7 @@ public class UserDefinedColours extends GUserDefinedColours /** * Loads the user-defined colour scheme from the first file listed in property - * "USER_DEFINED_COLOURS". If this fails, returns an all-white colour scheme. + * Preferences.USER_DEFINED_COLOURS. If this fails, returns an all-white colour scheme. * * @return */ @@ -702,7 +700,7 @@ public class UserDefinedColours extends GUserDefinedColours { UserColourScheme ret = null; - String colours = Cache.getProperty(USER_DEFINED_COLOURS); + String colours = Cache.getProperty(Preferences.USER_DEFINED_COLOURS); if (colours != null) { if (colours.indexOf("|") > -1) @@ -741,7 +739,7 @@ public class UserDefinedColours extends GUserDefinedColours String name = schemeName.getText().trim(); if (name.length() < 1) { - JvOptionPane.showInternalMessageDialog(Desktop.desktop, + JvOptionPane.showInternalMessageDialog(Desktop.getDesktopPane(), MessageManager .getString("label.user_colour_scheme_must_have_name"), MessageManager.getString("label.no_name_colour_scheme"), @@ -756,7 +754,7 @@ public class UserDefinedColours extends GUserDefinedColours * @j2sIgnore */ { - int reply = JvOptionPane.showInternalConfirmDialog(Desktop.desktop, + int reply = JvOptionPane.showInternalConfirmDialog(Desktop.getDesktopPane(), MessageManager.formatMessage( "label.colour_scheme_exists_overwrite", new Object[] { name, name }), @@ -814,7 +812,8 @@ public class UserDefinedColours extends GUserDefinedColours * update the delimited list of user defined colour files in * Jalview property USER_DEFINED_COLOURS */ - String defaultColours = Cache.getDefault(USER_DEFINED_COLOURS, + String defaultColours = Cache.getDefault( + Preferences.USER_DEFINED_COLOURS, filePath); if (defaultColours.indexOf(filePath) == -1) { @@ -824,7 +823,7 @@ public class UserDefinedColours extends GUserDefinedColours } defaultColours = defaultColours.concat(filePath); } - Cache.setProperty(USER_DEFINED_COLOURS, defaultColours); + Cache.setProperty(Preferences.USER_DEFINED_COLOURS, defaultColours); /* * construct and register the colour scheme diff --git a/src/jalview/gui/UserQuestionnaireCheck.java b/src/jalview/gui/UserQuestionnaireCheck.java index ef86756..df64db0 100644 --- a/src/jalview/gui/UserQuestionnaireCheck.java +++ b/src/jalview/gui/UserQuestionnaireCheck.java @@ -21,13 +21,12 @@ package jalview.gui; import jalview.util.MessageManager; +import jalview.util.Platform; import java.io.BufferedReader; import java.io.InputStreamReader; import java.net.URL; -import javax.swing.JOptionPane; - public class UserQuestionnaireCheck implements Runnable { /** @@ -91,6 +90,7 @@ public class UserQuestionnaireCheck implements Runnable return prompt; } + @Override public void run() { if (url == null) @@ -101,7 +101,7 @@ public class UserQuestionnaireCheck implements Runnable try { // First - check to see if wee have an old questionnaire/response id pair. - String lastq = jalview.bin.Cache.getProperty("QUESTIONNAIRE"); + String lastq = jalview.bin.Cache.getProperty(Preferences.QUESTIONNAIRE); if (lastq == null) { prompt = checkresponse(new URL(url @@ -133,7 +133,7 @@ public class UserQuestionnaireCheck implements Runnable if (qid != null && rid != null) { // Update our local property cache with latest qid and rid - jalview.bin.Cache.setProperty("QUESTIONNAIRE", qid + ":" + rid); + jalview.bin.Cache.setProperty(Preferences.QUESTIONNAIRE, qid + ":" + rid); } if (prompt) { @@ -141,7 +141,7 @@ public class UserQuestionnaireCheck implements Runnable + qid + "&rid=" + rid; jalview.bin.Cache.log .info("Prompting user for questionnaire at " + qurl); - int reply = JvOptionPane.showInternalConfirmDialog(Desktop.desktop, + int reply = JvOptionPane.showInternalConfirmDialog(Desktop.getDesktopPane(), MessageManager.getString("label.jalview_new_questionnaire"), MessageManager.getString("label.jalview_user_survey"), JvOptionPane.YES_NO_OPTION, JvOptionPane.QUESTION_MESSAGE); @@ -149,7 +149,7 @@ public class UserQuestionnaireCheck implements Runnable if (reply == JvOptionPane.YES_OPTION) { jalview.bin.Cache.log.debug("Opening " + qurl); - jalview.util.BrowserLauncher.openURL(qurl); + Platform.openURL(qurl); } } } catch (Exception e) diff --git a/src/jalview/gui/VamsasApplication.java b/src/jalview/gui/VamsasApplication.java index c094b1c..ef814d3 100644 --- a/src/jalview/gui/VamsasApplication.java +++ b/src/jalview/gui/VamsasApplication.java @@ -173,7 +173,7 @@ public class VamsasApplication implements SelectionSource, VamsasSource } } catch (InvalidSessionDocumentException e) { - JvOptionPane.showInternalMessageDialog(Desktop.desktop, + JvOptionPane.showInternalMessageDialog(Desktop.getDesktopPane(), MessageManager.getString( "label.vamsas_doc_couldnt_be_opened_as_new_session"), @@ -455,7 +455,7 @@ public class VamsasApplication implements SelectionSource, VamsasSource VamsasAppDatastore vds = new VamsasAppDatastore(doc, vobj2jv, jv2vobj, baseProvEntry(), alRedoState); // wander through frames - JInternalFrame[] frames = Desktop.desktop.getAllFrames(); + JInternalFrame[] frames = Desktop.getDesktopPane().getAllFrames(); if (frames == null) { @@ -660,7 +660,7 @@ public class VamsasApplication implements SelectionSource, VamsasSource Cache.log.debug( "Asking user if the vamsas session should be stored."); int reply = JvOptionPane.showInternalConfirmDialog( - Desktop.desktop, + Desktop.getDesktopPane(), "The current VAMSAS session has unsaved data - do you want to save it ?", "VAMSAS Session Shutdown", JvOptionPane.YES_NO_OPTION, @@ -669,7 +669,7 @@ public class VamsasApplication implements SelectionSource, VamsasSource if (reply == JvOptionPane.YES_OPTION) { Cache.log.debug("Prompting for vamsas store filename."); - Desktop.instance.vamsasSave_actionPerformed(null); + Desktop.getInstance().vamsasSave_actionPerformed(null); Cache.log .debug("Finished attempt at storing document."); } @@ -688,7 +688,7 @@ public class VamsasApplication implements SelectionSource, VamsasSource public void disableGui(boolean b) { - Desktop.instance.setVamsasUpdate(b); + Desktop.getInstance().setVamsasUpdate(b); } Hashtable _backup_vobj2jv; @@ -761,10 +761,10 @@ public class VamsasApplication implements SelectionSource, VamsasSource } try { - final IPickManager pm = vclient.getPickManager(); - final StructureSelectionManager ssm = StructureSelectionManager - .getStructureSelectionManager(Desktop.instance); - final VamsasApplication me = this; + IPickManager pm = vclient.getPickManager(); + StructureSelectionManager ssm = Desktop + .getStructureSelectionManager(); + VamsasApplication me = this; pm.registerMessageHandler(new IMessageHandler() { String last = null; @@ -830,7 +830,6 @@ public class VamsasApplication implements SelectionSource, VamsasSource { type = jvobjs[o].getClass(); } - ; if (type != jvobjs[o].getClass()) { send = false; @@ -954,7 +953,6 @@ public class VamsasApplication implements SelectionSource, VamsasSource { jvobjs[c] = null; } - ; jvobjs = null; return; } diff --git a/src/jalview/gui/WebserviceInfo.java b/src/jalview/gui/WebserviceInfo.java index c6137cc..ae013ec 100644 --- a/src/jalview/gui/WebserviceInfo.java +++ b/src/jalview/gui/WebserviceInfo.java @@ -711,7 +711,7 @@ public class WebserviceInfo extends GWebserviceInfo @Override public void run() { - JvOptionPane.showInternalMessageDialog(Desktop.desktop, message, + JvOptionPane.showInternalMessageDialog(Desktop.getDesktopPane(), message, title, JvOptionPane.WARNING_MESSAGE); } diff --git a/src/jalview/gui/WsJobParameters.java b/src/jalview/gui/WsJobParameters.java index 976e551..45822a3 100644 --- a/src/jalview/gui/WsJobParameters.java +++ b/src/jalview/gui/WsJobParameters.java @@ -215,12 +215,12 @@ public class WsJobParameters extends JPanel implements ItemListener, public boolean showRunDialog() { - frame = new JDialog(Desktop.instance, true); + frame = new JDialog(Desktop.getInstance(), true); frame.setTitle(MessageManager.formatMessage("label.edit_params_for", new String[] { service.getActionText() })); - Rectangle deskr = Desktop.instance.getBounds(); + Rectangle deskr = Desktop.getInstance().getBounds(); Dimension pref = this.getPreferredSize(); frame.setBounds( new Rectangle((int) (deskr.getCenterX() - pref.width / 2), @@ -436,8 +436,8 @@ public class WsJobParameters extends JPanel implements ItemListener, dialogpanel.add(canceljob); // JAL-1580: setMaximumSize() doesn't work, so just size for the worst case: // check for null is for JUnit usage - final int windowHeight = Desktop.instance == null ? 540 - : Desktop.instance.getHeight(); + final int windowHeight = Desktop.getInstance() == null ? 540 + : Desktop.getInstance().getHeight(); setPreferredSize(new Dimension(540, windowHeight)); add(dialogpanel, BorderLayout.SOUTH); validate(); @@ -963,13 +963,13 @@ public class WsJobParameters extends JPanel implements ItemListener, public static void main(String[] args) { jalview.ws.jws2.Jws2Discoverer disc = jalview.ws.jws2.Jws2Discoverer - .getDiscoverer(); + .getInstance(); int p = 0; if (args.length > 0) { Vector services = new Vector<>(); services.addElement(args[p++]); - Jws2Discoverer.getDiscoverer().setServiceUrls(services); + Jws2Discoverer.getInstance().setServiceUrls(services); } try { diff --git a/src/jalview/gui/WsParamSetManager.java b/src/jalview/gui/WsParamSetManager.java index bb5d996..0bfbb43 100644 --- a/src/jalview/gui/WsParamSetManager.java +++ b/src/jalview/gui/WsParamSetManager.java @@ -203,7 +203,7 @@ public class WsParamSetManager implements ParamManager chooser.setDialogTitle(MessageManager .getString("label.choose_filename_for_param_file")); chooser.setToolTipText(MessageManager.getString("action.save")); - int value = chooser.showSaveDialog(Desktop.instance); + int value = chooser.showSaveDialog(Desktop.getInstance()); if (value == JalviewFileChooser.APPROVE_OPTION) { outfile = chooser.getSelectedFile(); @@ -274,7 +274,7 @@ public class WsParamSetManager implements ParamManager * if (value == JalviewFileChooser.APPROVE_OPTION) { File choice = * chooser.getSelectedFile(); jalview.bin.Cache.setProperty("LAST_DIRECTORY", * choice.getParent()); String defaultColours = jalview.bin.Cache.getDefault( - * "USER_DEFINED_COLOURS", choice.getPath()); if + * Preferences.USER_DEFINED_COLOURS, choice.getPath()); if * (defaultColours.indexOf(choice.getPath()) == -1) { defaultColours = * defaultColours.concat("|") .concat(choice.getPath()); } (non-Javadoc) * @@ -311,7 +311,7 @@ public class WsParamSetManager implements ParamManager File pfile = new File(filename); if (pfile.exists() && pfile.canWrite()) { - if (JvOptionPane.showConfirmDialog(Desktop.instance, + if (JvOptionPane.showConfirmDialog(Desktop.getInstance(), "Delete the preset's file, too ?", "Delete User Preset ?", JvOptionPane.OK_CANCEL_OPTION) == JvOptionPane.OK_OPTION) { diff --git a/src/jalview/gui/WsPreferences.java b/src/jalview/gui/WsPreferences.java index 5186a26..01a62e9 100644 --- a/src/jalview/gui/WsPreferences.java +++ b/src/jalview/gui/WsPreferences.java @@ -65,7 +65,7 @@ public class WsPreferences extends GWsPreferences private void initFromPreferences() { - wsUrls = Jws2Discoverer.getDiscoverer().getServiceUrls(); + wsUrls = Jws2Discoverer.getInstance().getServiceUrls(); if (!wsUrls.isEmpty()) { oldUrls = new Vector(wsUrls); @@ -122,8 +122,8 @@ public class WsPreferences extends GWsPreferences int r = 0; for (String url : wsUrls) { - int status = Jws2Discoverer.getDiscoverer().getServerStatusFor(url); - tdat[r][1] = Integer.valueOf(status); + int status = Jws2Discoverer.getInstance().getServerStatusFor(url); + tdat[r][1] = new Integer(status); tdat[r++][0] = url; } @@ -241,7 +241,7 @@ public class WsPreferences extends GWsPreferences private void updateServiceList() { - Jws2Discoverer.getDiscoverer().setServiceUrls(wsUrls); + Jws2Discoverer.getInstance().setServiceUrls(wsUrls); } private void updateRsbsServiceList() @@ -454,7 +454,7 @@ public class WsPreferences extends GWsPreferences boolean valid = false; int resp = JvOptionPane.CANCEL_OPTION; while (!valid && (resp = JvOptionPane.showInternalConfirmDialog( - Desktop.desktop, panel, title, + Desktop.getDesktopPane(), panel, title, JvOptionPane.OK_CANCEL_OPTION)) == JvOptionPane.OK_OPTION) { try @@ -472,13 +472,13 @@ public class WsPreferences extends GWsPreferences } catch (Exception e) { valid = false; - JvOptionPane.showInternalMessageDialog(Desktop.desktop, + JvOptionPane.showInternalMessageDialog(Desktop.getDesktopPane(), MessageManager.getString("label.invalid_url")); } } if (valid && resp == JvOptionPane.OK_OPTION) { - int validate = JvOptionPane.showInternalConfirmDialog(Desktop.desktop, + int validate = JvOptionPane.showInternalConfirmDialog(Desktop.getDesktopPane(), MessageManager.getString("info.validate_jabaws_server"), MessageManager.getString("label.test_server"), JvOptionPane.YES_NO_OPTION); @@ -491,7 +491,7 @@ public class WsPreferences extends GWsPreferences } else { - int opt = JvOptionPane.showInternalOptionDialog(Desktop.desktop, + int opt = JvOptionPane.showInternalOptionDialog(Desktop.getDesktopPane(), "The Server '" + foo.toString() + "' failed validation,\ndo you want to add it anyway? ", "Server Validation Failed", JvOptionPane.YES_NO_OPTION, @@ -502,7 +502,7 @@ public class WsPreferences extends GWsPreferences } else { - JvOptionPane.showInternalMessageDialog(Desktop.desktop, + JvOptionPane.showInternalMessageDialog(Desktop.getDesktopPane(), MessageManager.getString( "warn.server_didnt_pass_validation")); } @@ -595,7 +595,7 @@ public class WsPreferences extends GWsPreferences if (lastrefresh != update) { lastrefresh = update; - Desktop.instance.startServiceDiscovery(true); // wait around for all + Desktop.getInstance().startServiceDiscovery(true); // wait around for all // threads to complete updateList(); @@ -616,15 +616,15 @@ public class WsPreferences extends GWsPreferences public void run() { long ct = System.currentTimeMillis(); - Desktop.instance.setProgressBar(MessageManager + Desktop.getInstance().setProgressBar(MessageManager .getString("status.refreshing_web_service_menus"), ct); if (lastrefresh != update) { lastrefresh = update; - Desktop.instance.startServiceDiscovery(true); + Desktop.getInstance().startServiceDiscovery(true); updateList(); } - Desktop.instance.setProgressBar(null, ct); + Desktop.getInstance().setProgressBar(null, ct); } }).start(); @@ -646,8 +646,8 @@ public class WsPreferences extends GWsPreferences @Override protected void resetWs_actionPerformed(ActionEvent e) { - Jws2Discoverer.getDiscoverer().setServiceUrls(null); - List nwsUrls = Jws2Discoverer.getDiscoverer().getServiceUrls(); + Jws2Discoverer.getInstance().setServiceUrls(null); + List nwsUrls = Jws2Discoverer.getInstance().getServiceUrls(); if (!wsUrls.equals(nwsUrls)) { update++; diff --git a/src/jalview/httpserver/HttpServer.java b/src/jalview/httpserver/HttpServer.java index a18d38d..f2daf2b 100644 --- a/src/jalview/httpserver/HttpServer.java +++ b/src/jalview/httpserver/HttpServer.java @@ -20,6 +20,8 @@ */ package jalview.httpserver; +import jalview.bin.ApplicationSingletonProvider; +import jalview.bin.ApplicationSingletonProvider.ApplicationSingletonI; import jalview.rest.RestHandler; import java.net.BindException; @@ -49,7 +51,7 @@ import org.eclipse.jetty.util.thread.QueuedThreadPool; * @author gmcarstairs * @see http://eclipse.org/jetty/documentation/current/embedding-jetty.html */ -public class HttpServer +public class HttpServer implements ApplicationSingletonI { /* * 'context root' - actually just prefixed to the path for each handler for @@ -58,11 +60,6 @@ public class HttpServer private static final String JALVIEW_PATH = "jalview"; /* - * Singleton instance of this server - */ - private static HttpServer instance; - - /* * The Http server */ private Server server; @@ -75,7 +72,7 @@ public class HttpServer /* * Lookup of ContextHandler by its wrapped handler */ - Map myHandlers = new HashMap(); + Map myHandlers = new HashMap<>(); /* * The context root for the server @@ -92,22 +89,20 @@ public class HttpServer { synchronized (HttpServer.class) { - if (instance == null) - { - instance = new HttpServer(); - } - return instance; + return (HttpServer) ApplicationSingletonProvider.getInstance(HttpServer.class); } } /** - * Private constructor to enforce use of singleton + * Private constructor to enforce use of singleton; use getInstance(). * * @throws BindException * if no free port can be assigned */ private HttpServer() throws BindException { + // use getInstance() + startServer(); /* diff --git a/src/jalview/io/AlignFile.java b/src/jalview/io/AlignFile.java index cea2870..c2cf667 100755 --- a/src/jalview/io/AlignFile.java +++ b/src/jalview/io/AlignFile.java @@ -323,14 +323,15 @@ public abstract class AlignFile extends FileParse */ protected void initData() { - seqs = new Vector(); - annotations = new Vector(); - seqGroups = new ArrayList(); + seqs = new Vector<>(); + annotations = new Vector<>(); + seqGroups = new ArrayList<>(); parseCalled = false; } /** - * DOCUMENT ME! + * Create the seqs Vector from a set of parsed sequences in an AlignFile, + * FeaturesFile, RnamlFile, or StockholmFile. * * @param s * DOCUMENT ME! @@ -338,7 +339,7 @@ public abstract class AlignFile extends FileParse @Override public void setSeqs(SequenceI[] s) { - seqs = new Vector(); + seqs = new Vector<>(); for (int i = 0; i < s.length; i++) { @@ -409,7 +410,7 @@ public abstract class AlignFile extends FileParse { if (newickStrings == null) { - newickStrings = new Vector(); + newickStrings = new Vector<>(); } newickStrings.addElement(new String[] { treeName, newickString }); } diff --git a/src/jalview/io/AnnotationFile.java b/src/jalview/io/AnnotationFile.java index f0f1ca3..02667c5 100755 --- a/src/jalview/io/AnnotationFile.java +++ b/src/jalview/io/AnnotationFile.java @@ -274,7 +274,7 @@ public class AnnotationFile if (row.graphGroup > -1) { graphGroupSeen.set(row.graphGroup); - Integer key = Integer.valueOf(row.graphGroup); + Integer key = new Integer(row.graphGroup); if (graphGroup.containsKey(key)) { graphGroup.put(key, graphGroup.get(key) + "\t" + row.label); @@ -762,7 +762,7 @@ public class AnnotationFile autoAnnotsKey(aa[aai], aa[aai].sequenceRef, (aa[aai].groupRef == null ? null : aa[aai].groupRef.getName())), - Integer.valueOf(1)); + new Integer(1)); } } } @@ -1271,7 +1271,7 @@ public class AnnotationFile { displayChar = token; // foo - value = Float.valueOf(token).floatValue(); + value = new Float(token).floatValue(); parsedValue = true; continue; } catch (NumberFormatException ex) diff --git a/src/jalview/io/BackupFilenameParts.java b/src/jalview/io/BackupFilenameParts.java index 1504404..4f93ece 100644 --- a/src/jalview/io/BackupFilenameParts.java +++ b/src/jalview/io/BackupFilenameParts.java @@ -1,5 +1,7 @@ package jalview.io; +import jalview.bin.Cache; + import java.io.File; public class BackupFilenameParts @@ -111,9 +113,7 @@ public class BackupFilenameParts String filename, String base, boolean extensionMatch) { BackupFilenameParts bfp = new BackupFilenameParts(); - BackupFilesPresetEntry bfpe = BackupFilesPresetEntry - .getSavedBackupEntry(); - String template = bfpe.suffix; + String template = Cache.getDefault(BackupFiles.SUFFIX, null); if (template == null) { return bfp; @@ -121,7 +121,8 @@ public class BackupFilenameParts int digits; try { - digits = bfpe.digits; + digits = Integer + .parseInt(Cache.getDefault(BackupFiles.SUFFIX_DIGITS, null)); } catch (Exception e) { return bfp; diff --git a/src/jalview/io/BackupFiles.java b/src/jalview/io/BackupFiles.java index 06c2fc9..c697a99 100644 --- a/src/jalview/io/BackupFiles.java +++ b/src/jalview/io/BackupFiles.java @@ -18,8 +18,12 @@ import java.util.TreeMap; * BackupFiles used for manipulating (naming rolling/deleting) backup/version files when an alignment or project file is saved. * User configurable options are: * BACKUPFILES_ENABLED - boolean flag as to whether to use this mechanism or act as before, including overwriting files as saved. - * The rest of the options are now saved as BACKUPFILES_PRESET, BACKUPFILES_SAVED and BACKUPFILES_CUSTOM - * (see BackupFilesPresetEntry) + * BACKUPFILES_SUFFIX - a template to insert after the file extension. Use '%n' to be replaced by a 0-led SUFFIX_DIGITS long integer. + * BACKUPFILES_NO_MAX - flag to turn off setting a maximum number of backup files to keep. + * BACKUPFILES_ROLL_MAX - the maximum number of backupfiles to keep for any one alignment or project file. + * BACKUPFILES_SUFFIX_DIGITS - the number of digits to insert replace %n with (e.g. BACKUPFILES_SUFFIX_DIGITS = 3 would make "001", "002", etc) + * BACKUPFILES_REVERSE_ORDER - if true then "logfile" style numbering and file rolling will occur. If false then ever-increasing version numbering will occur, but old files will still be deleted if there are more than ROLL_MAX backup files. + * BACKUPFILES_CONFIRM_DELETE_OLD - if true then prompt/confirm with the user when deleting older backup/version files. */ public class BackupFiles @@ -30,8 +34,21 @@ public class BackupFiles public static final String ENABLED = NS + "_ENABLED"; + public static final String SUFFIX = NS + "_SUFFIX"; + + public static final String NO_MAX = NS + "_NO_MAX"; + + public static final String ROLL_MAX = NS + "_ROLL_MAX"; + + public static final String SUFFIX_DIGITS = NS + "_SUFFIX_DIGITS"; + public static final String NUM_PLACEHOLDER = "%n"; + public static final String REVERSE_ORDER = NS + "_REVERSE_ORDER"; + + public static final String CONFIRM_DELETE_OLD = NS + + "_CONFIRM_DELETE_OLD"; + private static final String DEFAULT_TEMP_FILE = "jalview_temp_file_" + NS; private static final String TEMP_FILE_EXT = ".tmp"; @@ -85,14 +102,20 @@ public class BackupFiles // REVERSE_ORDER public BackupFiles(File file) { + this(file, ".bak" + NUM_PLACEHOLDER, false, 3, 3, false); + } + + public BackupFiles(File file, String defaultSuffix, boolean defaultNoMax, + int defaultMax, int defaultDigits, boolean defaultReverseOrder) + { classInit(); this.file = file; - BackupFilesPresetEntry bfpe = BackupFilesPresetEntry.getSavedBackupEntry(); - this.suffix = bfpe.suffix; - this.noMax = bfpe.keepAll; - this.max = bfpe.rollMax; - this.digits = bfpe.digits; - this.reverseOrder = bfpe.reverse; + this.suffix = Cache.getDefault(SUFFIX, defaultSuffix); + this.noMax = Cache.getDefault(NO_MAX, defaultNoMax); + this.max = Cache.getDefault(ROLL_MAX, defaultMax); + this.digits = Cache.getDefault(SUFFIX_DIGITS, defaultDigits); + this.reverseOrder = Cache.getDefault(REVERSE_ORDER, + defaultReverseOrder); // create a temp file to save new data in File temp = null; @@ -123,9 +146,7 @@ public class BackupFiles public static void classInit() { setEnabled(Cache.getDefault(ENABLED, !Platform.isJS())); - BackupFilesPresetEntry bfpe = BackupFilesPresetEntry - .getSavedBackupEntry(); - setConfirmDelete(bfpe.confirmDelete); + setConfirmDelete(Cache.getDefault(CONFIRM_DELETE_OLD, true)); } public static void setEnabled(boolean flag) @@ -518,7 +539,7 @@ public class BackupFiles MessageManager.getString("label.delete"), MessageManager.getString("label.rename") }; - confirmButton = JvOptionPane.showOptionDialog(Desktop.desktop, + confirmButton = JvOptionPane.showOptionDialog(Desktop.getDesktopPane(), messageSB.toString(), MessageManager.getString("label.backupfiles_confirm_delete"), JvOptionPane.YES_NO_OPTION, JvOptionPane.WARNING_MESSAGE, @@ -538,7 +559,7 @@ public class BackupFiles MessageManager.getString("label.delete"), MessageManager.getString("label.keep") }; - confirmButton = JvOptionPane.showOptionDialog(Desktop.desktop, + confirmButton = JvOptionPane.showOptionDialog(Desktop.getDesktopPane(), messageSB.toString(), MessageManager.getString("label.backupfiles_confirm_delete"), JvOptionPane.YES_NO_OPTION, JvOptionPane.WARNING_MESSAGE, @@ -573,7 +594,7 @@ public class BackupFiles Long.toString(df.length()) })); } - int confirmButton = JvOptionPane.showConfirmDialog(Desktop.desktop, + int confirmButton = JvOptionPane.showConfirmDialog(Desktop.getDesktopPane(), messageSB.toString(), MessageManager .getString("label.backupfiles_confirm_delete"), @@ -662,7 +683,7 @@ public class BackupFiles "label.backupfiles_confirm_save_new_saved_file_not_ok")); } - int confirmButton = JvOptionPane.showConfirmDialog(Desktop.desktop, + int confirmButton = JvOptionPane.showConfirmDialog(Desktop.getDesktopPane(), messageSB.toString(), MessageManager .getString("label.backupfiles_confirm_save_file"), diff --git a/src/jalview/io/BackupFilesPresetEntry.java b/src/jalview/io/BackupFilesPresetEntry.java deleted file mode 100644 index 4face29..0000000 --- a/src/jalview/io/BackupFilesPresetEntry.java +++ /dev/null @@ -1,173 +0,0 @@ -package jalview.io; - -import jalview.bin.Cache; -import jalview.util.MessageManager; - -import java.util.HashMap; -import java.util.Map; -import java.util.StringTokenizer; - -public class BackupFilesPresetEntry -{ - - public String suffix; - - public static final int DIGITSMIN = 1; - - public static final int DIGITSMAX = 6; - - public int digits; - - public boolean reverse; - - public boolean keepAll; - - public static final int ROLLMAXMIN = 1; - - public static final int ROLLMAXMAX = 999; - - public int rollMax; - - public boolean confirmDelete; - - public static final String SAVEDCONFIG = BackupFiles.NS + "_SAVED"; - - public static final String CUSTOMCONFIG = BackupFiles.NS + "_CUSTOM"; - - private static final String stringDelim = "\t"; - - public static final int BACKUPFILESSCHEMECUSTOM = 0; - - public static final int BACKUPFILESSCHEMEDEFAULT = 1; - - public BackupFilesPresetEntry(String suffix, int digits, boolean reverse, - boolean keepAll, int rollMax, boolean confirmDelete) - { - this.suffix = suffix == null ? "" : suffix; - this.digits = digits < DIGITSMIN ? DIGITSMIN - : (digits > DIGITSMAX ? DIGITSMAX : digits); - this.reverse = reverse; - this.keepAll = keepAll; - this.rollMax = rollMax < ROLLMAXMIN ? ROLLMAXMIN - : (rollMax > ROLLMAXMAX ? ROLLMAXMAX : rollMax); - this.confirmDelete = confirmDelete; - } - - public boolean equals(BackupFilesPresetEntry compare) - { - return suffix.equals(compare.suffix) && digits == compare.digits - && reverse == compare.reverse && keepAll == compare.keepAll - && rollMax == compare.rollMax - && confirmDelete == compare.confirmDelete; - } - - @Override - public String toString() - { - StringBuilder sb = new StringBuilder(); - sb.append(suffix); - sb.append(stringDelim); - sb.append(digits); - sb.append(stringDelim); - sb.append(reverse); - sb.append(stringDelim); - sb.append(keepAll); - sb.append(stringDelim); - sb.append(rollMax); - sb.append(stringDelim); - sb.append(confirmDelete); - return sb.toString(); - } - - public static BackupFilesPresetEntry createBackupFilesPresetEntry( - String line) - { - if (line == null) - { - return null; - } - StringTokenizer st = new StringTokenizer(line, stringDelim); - String suffix = null; - int digits = 0; - boolean reverse = false; - boolean keepAll = false; - int rollMax = 0; - boolean confirmDelete = false; - - try - { - suffix = st.nextToken(); - digits = Integer.valueOf(st.nextToken()); - reverse = Boolean.valueOf(st.nextToken()); - keepAll = Boolean.valueOf(st.nextToken()); - rollMax = Integer.valueOf(st.nextToken()); - confirmDelete = Boolean.valueOf(st.nextToken()); - } catch (Exception e) - { - Cache.log.error("Error parsing backupfiles scheme '" + line + "'"); - } - - return new BackupFilesPresetEntry(suffix, digits, reverse, keepAll, - rollMax, confirmDelete); - } - - public static BackupFilesPresetEntry getSavedBackupEntry() - { - String savedPresetString = Cache - .getDefault(BackupFilesPresetEntry.SAVEDCONFIG, null); - BackupFilesPresetEntry savedPreset = BackupFilesPresetEntry - .createBackupFilesPresetEntry(savedPresetString); - if (savedPreset == null) - { - savedPreset = backupfilesPresetEntriesValues - .get(BACKUPFILESSCHEMEDEFAULT); - } - return savedPreset; - } - - public static final IntKeyStringValueEntry[] backupfilesPresetEntries = { - new IntKeyStringValueEntry(BACKUPFILESSCHEMEDEFAULT, - MessageManager.getString("label.default")), - new IntKeyStringValueEntry(2, - MessageManager.getString("label.single_file")), - new IntKeyStringValueEntry(3, - MessageManager.getString("label.keep_all_versions")), - new IntKeyStringValueEntry(4, - MessageManager.getString("label.rolled_backups")), - // ... - // IMPORTANT, keep "Custom" entry with key 0 (even though it appears last) - new IntKeyStringValueEntry(BACKUPFILESSCHEMECUSTOM, - MessageManager.getString("label.custom")) }; - - public static final String[] backupfilesPresetEntryDescriptions = { - MessageManager.getString("label.default_description"), - MessageManager.getString("label.single_file_description"), - MessageManager.getString("label.keep_all_versions_description"), - MessageManager.getString("label.rolled_backups_description"), - MessageManager.getString("label.custom_description") }; - - public static final Map backupfilesPresetEntriesValues = new HashMap() - { - /** - * - */ - private static final long serialVersionUID = 125L; - - { - put(1, new BackupFilesPresetEntry( - ".bak" + BackupFiles.NUM_PLACEHOLDER, 3, false, false, 3, - false)); - put(2, new BackupFilesPresetEntry("~", 1, false, false, 1, false)); - put(3, new BackupFilesPresetEntry(".v" + BackupFiles.NUM_PLACEHOLDER, - 3, false, true, 10, true)); - put(4, new BackupFilesPresetEntry( - "_bak." + BackupFiles.NUM_PLACEHOLDER, 1, true, false, 9, - false)); - - // This gets replaced by GPreferences - put(BACKUPFILESSCHEMECUSTOM, - new BackupFilesPresetEntry("", 0, false, false, 0, false)); - } - }; - -} diff --git a/src/jalview/io/FeaturesFile.java b/src/jalview/io/FeaturesFile.java index 5f68099..aa21b0f 100755 --- a/src/jalview/io/FeaturesFile.java +++ b/src/jalview/io/FeaturesFile.java @@ -441,7 +441,7 @@ public class FeaturesFile extends AlignFile implements FeaturesSourceI float score = Float.NaN; try { - score = Float.valueOf(gffColumns[6]).floatValue(); + score = new Float(gffColumns[6]).floatValue(); } catch (NumberFormatException ex) { sf = new SequenceFeature(ft, desc, startPos, endPos, featureGroup); @@ -829,14 +829,15 @@ public class FeaturesFile extends AlignFile implements FeaturesSourceI AlignViewportI av = getViewport(); if (av != null) { - if (av.getAlignment() != null) + AlignmentI a = av.getAlignment(); + if (a != null) { - dataset = av.getAlignment().getDataset(); + dataset = a.getDataset(); } if (dataset == null) { // working in the applet context ? - dataset = av.getAlignment(); + dataset = a; } } else @@ -890,7 +891,8 @@ public class FeaturesFile extends AlignFile implements FeaturesSourceI StringBuilder out = new StringBuilder(256); - out.append(String.format("%s %d\n", GFF_VERSION, gffVersion == 0 ? 2 : gffVersion)); + out.append(String.format("%s %d" + newline, GFF_VERSION, + gffVersion == 0 ? 2 : gffVersion)); if (!includeNonPositionalFeatures && (visibleColours == null || visibleColours.isEmpty())) diff --git a/src/jalview/io/FileFormats.java b/src/jalview/io/FileFormats.java index aadcdb9..e83b87c 100644 --- a/src/jalview/io/FileFormats.java +++ b/src/jalview/io/FileFormats.java @@ -20,6 +20,9 @@ */ package jalview.io; +import jalview.bin.ApplicationSingletonProvider; +import jalview.bin.ApplicationSingletonProvider.ApplicationSingletonI; + import java.util.ArrayList; import java.util.HashSet; import java.util.LinkedHashMap; @@ -36,23 +39,11 @@ import java.util.Set; * @author gmcarstairs * */ -public class FileFormats +public class FileFormats implements ApplicationSingletonI { - private static FileFormats instance = new FileFormats(); - - /* - * A lookup map of file formats by upper-cased name - */ - private static Map formats; - - /* - * Formats in this set are capable of being identified by IdentifyFile - */ - private static Set identifiable; - public static FileFormats getInstance() { - return instance; + return (FileFormats) ApplicationSingletonProvider.getInstance(FileFormats.class); } /** @@ -63,6 +54,16 @@ public class FileFormats reset(); } + /* + * A lookup map of file formats by upper-cased name + */ + private Map formats; + + /* + * Formats in this set are capable of being identified by IdentifyFile + */ + private Set identifiable; + /** * Reset to just the built-in file formats packaged with Jalview. These are * added (and will be shown in menus) in the order of their declaration in the @@ -70,8 +71,8 @@ public class FileFormats */ public synchronized void reset() { - formats = new LinkedHashMap(); - identifiable = new HashSet(); + formats = new LinkedHashMap<>(); + identifiable = new HashSet<>(); for (FileFormat format : FileFormat.values()) { registerFileFormat(format, format.isIdentifiable()); @@ -135,7 +136,7 @@ public class FileFormats */ public List getWritableFormats(boolean textOnly) { - List l = new ArrayList(); + List l = new ArrayList<>(); for (FileFormatI ff : formats.values()) { if (ff.isWritable() && (!textOnly || ff.isTextFormat())) @@ -154,7 +155,7 @@ public class FileFormats */ public List getReadableFormats() { - List l = new ArrayList(); + List l = new ArrayList<>(); for (FileFormatI ff : formats.values()) { if (ff.isReadable()) diff --git a/src/jalview/io/FileLoader.java b/src/jalview/io/FileLoader.java index 95f85e6..3585c93 100755 --- a/src/jalview/io/FileLoader.java +++ b/src/jalview/io/FileLoader.java @@ -37,7 +37,6 @@ import jalview.gui.JvOptionPane; import jalview.json.binding.biojson.v1.ColourSchemeMapper; import jalview.project.Jalview2XML; import jalview.schemes.ColourSchemeI; -import jalview.structure.StructureSelectionManager; import jalview.util.MessageManager; import jalview.util.Platform; import jalview.ws.utils.UrlDownloadClient; @@ -56,16 +55,35 @@ import javax.swing.SwingUtilities; public class FileLoader implements Runnable { + private File selectedFile; + String file; DataSourceType protocol; FileFormatI format; - AlignmentFileReaderI source = null; // alternative specification of where data - // comes + AlignmentFileReaderI source; // alternative specification of where data + // comes from - // from + /** + * It is critical that all these fields are set, as this instance is reused. + * + * @param source + * @param file + * @param inFile + * @param dataSourceType + * @param format + */ + private void setFileFields(AlignmentFileReaderI source, File file, + String inFile, DataSourceType dataSourceType, FileFormatI format) + { + this.source = source; + this.file = inFile; + this.selectedFile = file; + this.protocol = dataSourceType; + this.format = format; + } AlignViewport viewport; @@ -77,8 +95,6 @@ public class FileLoader implements Runnable boolean raiseGUI = true; - private File selectedFile; - /** * default constructor always raised errors in GUI dialog boxes */ @@ -98,7 +114,7 @@ public class FileLoader implements Runnable this.raiseGUI = raiseGUI; } - public void LoadFile(AlignViewport viewport, Object file, + public void loadFile(AlignViewport viewport, Object file, DataSourceType protocol, FileFormatI format) { this.viewport = viewport; @@ -106,10 +122,10 @@ public class FileLoader implements Runnable this.selectedFile = (File) file; file = selectedFile.getPath(); } - LoadFile(file.toString(), protocol, format); + loadFile(file.toString(), protocol, format); } - public void LoadFile(String file, DataSourceType protocol, + public void loadFile(String file, DataSourceType protocol, FileFormatI format) { this.file = file; @@ -136,7 +152,7 @@ public class FileLoader implements Runnable */ public void LoadFile(String file, DataSourceType protocol) { - LoadFile(file, protocol, null); + loadFile(file, protocol, null); } /** @@ -149,7 +165,7 @@ public class FileLoader implements Runnable public AlignFrame LoadFileWaitTillLoaded(String file, DataSourceType sourceType) { - return LoadFileWaitTillLoaded(file, sourceType, null); + return loadFileWaitTillLoaded(file, sourceType, null); } /** @@ -160,13 +176,11 @@ public class FileLoader implements Runnable * @param format * @return alignFrame constructed from file contents */ - public AlignFrame LoadFileWaitTillLoaded(String file, + public AlignFrame loadFileWaitTillLoaded(String file, DataSourceType sourceType, FileFormatI format) { - this.file = file; - this.protocol = sourceType; - this.format = format; - return _LoadFileWaitTillLoaded(); + setFileFields(null, null, file, sourceType, format); + return _loadFileWaitTillLoaded(); } /** @@ -177,14 +191,11 @@ public class FileLoader implements Runnable * @param format * @return alignFrame constructed from file contents */ - public AlignFrame LoadFileWaitTillLoaded(File file, + public AlignFrame loadFileWaitTillLoaded(File file, DataSourceType sourceType, FileFormatI format) { - this.selectedFile = file; - this.file = file.getPath(); - this.protocol = sourceType; - this.format = format; - return _LoadFileWaitTillLoaded(); + setFileFields(null, file, null, sourceType, format); + return _loadFileWaitTillLoaded(); } /** @@ -194,15 +205,12 @@ public class FileLoader implements Runnable * @param format * @return alignFrame constructed from file contents */ - public AlignFrame LoadFileWaitTillLoaded(AlignmentFileReaderI source, + public AlignFrame loadFileWaitTillLoaded(AlignmentFileReaderI source, FileFormatI format) { - this.source = source; - - file = source.getInFile(); - protocol = source.getDataSourceType(); - this.format = format; - return _LoadFileWaitTillLoaded(); + setFileFields(source, null, source.getInFile(), + source.getDataSourceType(), format); + return _loadFileWaitTillLoaded(); } /** @@ -211,7 +219,7 @@ public class FileLoader implements Runnable * * @return */ - protected AlignFrame _LoadFileWaitTillLoaded() + private AlignFrame _loadFileWaitTillLoaded() { this.run(); return alignFrame; @@ -278,9 +286,9 @@ public class FileLoader implements Runnable Runtime rt = Runtime.getRuntime(); try { - if (Desktop.instance != null) + if (Desktop.getInstance() != null) { - Desktop.instance.startLoading(file); + Desktop.getInstance().startLoading(file); } if (format == null) { @@ -302,12 +310,12 @@ public class FileLoader implements Runnable if (format == null) { - Desktop.instance.stopLoading(); + Desktop.getInstance().stopLoading(); System.err.println("The input file \"" + file + "\" has null or unidentifiable data content!"); if (!Jalview.isHeadlessMode()) { - JvOptionPane.showInternalMessageDialog(Desktop.desktop, + JvOptionPane.showInternalMessageDialog(Desktop.getDesktopPane(), MessageManager.getString("label.couldnt_read_data") + " in " + file + "\n" + AppletFormatAdapter.getSupportedFormats(), @@ -318,7 +326,7 @@ public class FileLoader implements Runnable } // TODO: cache any stream datasources as a temporary file (eg. PDBs // retrieved via URL) - if (Desktop.desktop != null && Desktop.desktop.isShowMemoryUsage()) + if (Desktop.getDesktopPane() != null && Desktop.getDesktopPane().isShowMemoryUsage()) { System.gc(); memused = (rt.maxMemory() - rt.totalMemory() + rt.freeMemory()); // free @@ -339,7 +347,10 @@ public class FileLoader implements Runnable // We read the data anyway - it might make sense. } // BH 2018 switch to File object here instead of filename + Platform.timeCheck(null, Platform.TIME_MARK); alignFrame = new Jalview2XML(raiseGUI).loadJalviewAlign(selectedFile == null ? file : selectedFile); + Platform.timeCheck("JVP loaded", Platform.TIME_MARK); + } else { @@ -361,15 +372,15 @@ public class FileLoader implements Runnable if (downloadStructureFile) { String structExt = format.getExtensions().split(",")[0]; - String urlLeafName = file.substring( - file.lastIndexOf( - System.getProperty("file.separator")), + int pt = file.lastIndexOf(file.indexOf('/') >= 0 ? "/" + : System.getProperty("file.separator")); + String urlLeafName = file.substring(pt, file.lastIndexOf(".")); String tempStructureFileStr = createNamedJvTempFile( urlLeafName, structExt); // BH - switching to File object here so as to hold - // ._bytes array directly + // .秘bytes array directly File tempFile = new File(tempStructureFileStr); UrlDownloadClient.download(file, tempFile); @@ -410,8 +421,7 @@ public class FileLoader implements Runnable { // register PDB entries with desktop's structure selection // manager - StructureSelectionManager - .getStructureSelectionManager(Desktop.instance) + Desktop.getStructureSelectionManager() .registerPDBEntry(pdbe); } } @@ -500,23 +510,23 @@ public class FileLoader implements Runnable } else { - if (Desktop.instance != null) + if (Desktop.getInstance() != null) { - Desktop.instance.stopLoading(); + Desktop.getInstance().stopLoading(); } final String errorMessage = MessageManager.getString( "label.couldnt_load_file") + " " + title + "\n" + error; // TODO: refactor FileLoader to be independent of Desktop / Applet GUI // bits ? - if (raiseGUI && Desktop.desktop != null) + if (raiseGUI && Desktop.getDesktopPane() != null) { javax.swing.SwingUtilities.invokeLater(new Runnable() { @Override public void run() { - JvOptionPane.showInternalMessageDialog(Desktop.desktop, + JvOptionPane.showInternalMessageDialog(Desktop.getDesktopPane(), errorMessage, MessageManager .getString("label.error_loading_file"), @@ -544,7 +554,7 @@ public class FileLoader implements Runnable @Override public void run() { - JvOptionPane.showInternalMessageDialog(Desktop.desktop, + JvOptionPane.showInternalMessageDialog(Desktop.getDesktopPane(), MessageManager.formatMessage( "label.problems_opening_file", new String[] { file }), @@ -566,7 +576,7 @@ public class FileLoader implements Runnable @Override public void run() { - JvOptionPane.showInternalMessageDialog(Desktop.desktop, + JvOptionPane.showInternalMessageDialog(Desktop.getDesktopPane(), MessageManager.formatMessage( "warn.out_of_memory_loading_file", new String[] { file }), @@ -588,7 +598,7 @@ public class FileLoader implements Runnable // memory // after // load - if (Desktop.desktop != null && Desktop.desktop.isShowMemoryUsage()) + if (Desktop.getDesktopPane() != null && Desktop.getDesktopPane().isShowMemoryUsage()) { if (alignFrame != null) { @@ -610,9 +620,9 @@ public class FileLoader implements Runnable } } // remove the visual delay indicator - if (Desktop.instance != null) + if (Desktop.getInstance() != null) { - Desktop.instance.stopLoading(); + Desktop.getInstance().stopLoading(); } } diff --git a/src/jalview/io/FormatAdapter.java b/src/jalview/io/FormatAdapter.java index 85cf48a..b0414af 100755 --- a/src/jalview/io/FormatAdapter.java +++ b/src/jalview/io/FormatAdapter.java @@ -30,6 +30,7 @@ import jalview.datamodel.HiddenColumns; import jalview.datamodel.Sequence; import jalview.datamodel.SequenceGroup; import jalview.datamodel.SequenceI; +import jalview.gui.Preferences; import jalview.util.Comparison; import java.io.File; @@ -63,13 +64,16 @@ public class FormatAdapter extends AppletFormatAdapter private void init() { - if (jalview.bin.Cache.getDefault("STRUCT_FROM_PDB", true)) + if (jalview.bin.Cache.getDefault(Preferences.STRUCT_FROM_PDB, true)) { - annotFromStructure = jalview.bin.Cache.getDefault("ADD_TEMPFACT_ANN", + annotFromStructure = jalview.bin.Cache.getDefault( + Preferences.ADD_TEMPFACT_ANN, true); - localSecondaryStruct = jalview.bin.Cache.getDefault("ADD_SS_ANN", + localSecondaryStruct = jalview.bin.Cache.getDefault( + Preferences.ADD_SS_ANN, true); - serviceSecondaryStruct = jalview.bin.Cache.getDefault("USE_RNAVIEW", + serviceSecondaryStruct = jalview.bin.Cache + .getDefault(Preferences.USE_RNAVIEW, true); } else diff --git a/src/jalview/io/HTMLOutput.java b/src/jalview/io/HTMLOutput.java index 54e7e4b..e7054c7 100644 --- a/src/jalview/io/HTMLOutput.java +++ b/src/jalview/io/HTMLOutput.java @@ -22,11 +22,13 @@ package jalview.io; import jalview.api.AlignExportSettingsI; import jalview.bin.Cache; +import jalview.bin.Jalview; import jalview.datamodel.AlignExportSettingsAdapter; import jalview.datamodel.AlignmentExportData; import jalview.gui.AlignmentPanel; import jalview.gui.IProgressIndicator; import jalview.util.MessageManager; +import jalview.util.Platform; import java.io.BufferedReader; import java.io.File; @@ -231,7 +233,7 @@ public abstract class HTMLOutput implements Runnable protected void setProgressMessage(String message) { - if (pIndicator != null && !isHeadless()) + if (pIndicator != null && !Jalview.isHeadlessMode()) { pIndicator.setProgressBar(message, pSessionId); } @@ -242,29 +244,17 @@ public abstract class HTMLOutput implements Runnable } /** - * Answers true if HTML export is invoke in headless mode or false otherwise - * - * @return - */ - protected boolean isHeadless() - { - return System.getProperty("java.awt.headless") != null - && System.getProperty("java.awt.headless").equals("true"); - } - - /** * This method provides implementation of consistent behaviour which should * occur after a HTML file export. It MUST be called at the end of the * exportHTML() method implementation. */ protected void exportCompleted() { - if (isLaunchInBrowserAfterExport() && !isHeadless()) + if (isLaunchInBrowserAfterExport() && !Jalview.isHeadlessMode()) { try { - jalview.util.BrowserLauncher - .openURL("file:///" + getExportedFile()); + Platform.openURL("file:///" + getExportedFile()); } catch (IOException e) { e.printStackTrace(); diff --git a/src/jalview/io/HtmlSvgOutput.java b/src/jalview/io/HtmlSvgOutput.java index b8241c8..d4a4651 100644 --- a/src/jalview/io/HtmlSvgOutput.java +++ b/src/jalview/io/HtmlSvgOutput.java @@ -21,6 +21,7 @@ package jalview.io; import jalview.bin.Cache; +import jalview.bin.Jalview; import jalview.gui.AlignmentPanel; import jalview.gui.LineartOptions; import jalview.gui.OOMWarning; @@ -223,7 +224,8 @@ public class HtmlSvgOutput extends HTMLOutput /* * Prompt for character rendering style if preference is not set */ - if (renderStyle.equalsIgnoreCase("Prompt each time") && !isHeadless()) + if (renderStyle.equalsIgnoreCase("Prompt each time") + && !Jalview.isHeadlessMode()) { LineartOptions svgOption = new LineartOptions("HTML", textOption); svgOption.setResponseAction(1, new Runnable() diff --git a/src/jalview/io/IdentifyFile.java b/src/jalview/io/IdentifyFile.java index b312474..621cfac 100755 --- a/src/jalview/io/IdentifyFile.java +++ b/src/jalview/io/IdentifyFile.java @@ -151,7 +151,7 @@ public class IdentifyFile { for (int i = 0; !isBinary && i < data.length(); i++) { - char c = data.charAt(i); + int c = data.charAt(i); isBinary = (c < 32 && c != '\t' && c != '\n' && c != '\r' && c != 5 && c != 27); // nominal binary character filter // excluding CR, LF, tab,DEL and ^E @@ -165,11 +165,12 @@ public class IdentifyFile if (source.inFile != null) { String fileStr = source.inFile.getName(); - if (fileStr.contains(".jar") - || fileStr.contains(".zip") || fileStr.contains(".jvp")) + if (fileStr.contains(".jar") || fileStr.contains(".zip") + || fileStr.contains(".jvp")) { // possibly a Jalview archive (but check further) reply = FileFormat.Jalview; + break; } } if (!lineswereskipped && data.startsWith("PK")) diff --git a/src/jalview/io/IntKeyStringValueEntry.java b/src/jalview/io/IntKeyStringValueEntry.java deleted file mode 100644 index 084dbc5..0000000 --- a/src/jalview/io/IntKeyStringValueEntry.java +++ /dev/null @@ -1,21 +0,0 @@ -package jalview.io; - -public class IntKeyStringValueEntry -{ - public final int k; - - public final String v; - - public IntKeyStringValueEntry(int k, String v) - { - this.k = k; - this.v = v; - } - - @Override - public String toString() - { - return v; - } - -} diff --git a/src/jalview/io/JPredFile.java b/src/jalview/io/JPredFile.java index 6af92b7..e375df7 100755 --- a/src/jalview/io/JPredFile.java +++ b/src/jalview/io/JPredFile.java @@ -209,7 +209,7 @@ public class JPredFile extends AlignFile { ascore = symbols.nextToken(); - Float score = Float.valueOf(ascore); + Float score = new Float(ascore); scores.addElement(score); } @@ -285,7 +285,7 @@ public class JPredFile extends AlignFile seq_entries.addElement(newseq.toString()); ids.addElement(id); - Symscores.put(id, Integer.valueOf(ids.size() - 1)); + Symscores.put(id, new Integer(ids.size() - 1)); } } } diff --git a/src/jalview/io/JalviewFileFilter.java b/src/jalview/io/JalviewFileFilter.java index bc20342..cc63a22 100755 --- a/src/jalview/io/JalviewFileFilter.java +++ b/src/jalview/io/JalviewFileFilter.java @@ -21,7 +21,6 @@ package jalview.io; import java.io.File; -import java.util.Hashtable; import java.util.Iterator; import java.util.LinkedHashMap; import java.util.Map; @@ -31,8 +30,6 @@ import javax.swing.filechooser.FileFilter; public class JalviewFileFilter extends FileFilter { - public static Hashtable suffixHash = new Hashtable(); - private Map filters = null; private String description = "no description"; @@ -136,8 +133,6 @@ public class JalviewFileFilter extends FileFilter { return filename.substring(i + 1).toLowerCase(); } - - ; } return ""; diff --git a/src/jalview/io/JnetAnnotationMaker.java b/src/jalview/io/JnetAnnotationMaker.java index 6828202..c9f1fcf 100755 --- a/src/jalview/io/JnetAnnotationMaker.java +++ b/src/jalview/io/JnetAnnotationMaker.java @@ -148,7 +148,7 @@ public class JnetAnnotationMaker { for (int j = 0; j < width; j++) { - float value = Float.valueOf(preds[i].getCharAt(j) + "") + float value = new Float(preds[i].getCharAt(j) + "") .floatValue(); annotations[gapmap[j]] = new Annotation( preds[i].getCharAt(j) + "", "", @@ -159,7 +159,7 @@ public class JnetAnnotationMaker { for (int j = 0; j < width; j++) { - float value = Float.valueOf(preds[i].getCharAt(j) + "") + float value = new Float(preds[i].getCharAt(j) + "") .floatValue(); annotations[gapmap[delMap[j]]] = new Annotation( preds[i].getCharAt(j) + "", "", diff --git a/src/jalview/io/ModellerDescription.java b/src/jalview/io/ModellerDescription.java index a56f2af..4a12387 100755 --- a/src/jalview/io/ModellerDescription.java +++ b/src/jalview/io/ModellerDescription.java @@ -22,6 +22,7 @@ package jalview.io; import jalview.datamodel.DBRefEntry; import jalview.datamodel.SequenceI; +import jalview.util.Platform; import java.util.List; @@ -90,17 +91,25 @@ public class ModellerDescription resCode(int v) { - val = Integer.valueOf(v); + val = new Integer(v); field = val.toString(); } }; + private static Regex VALIDATION_REGEX; + + private static Regex getRegex() + { + return (VALIDATION_REGEX == null + ? VALIDATION_REGEX = Platform + .newRegex("\\s*((([-0-9]+).?)|FIRST|LAST|@)", null) + : VALIDATION_REGEX); + } + private resCode validResidueCode(String field) { Integer val = null; - Regex r = new Regex( - "\\s*((([-0-9]+).?)|FIRST|LAST|@)"); - + Regex r = getRegex(); if (!r.search(field)) { return null; // invalid diff --git a/src/jalview/io/NewickFile.java b/src/jalview/io/NewickFile.java index f3eaa45..7596db4 100755 --- a/src/jalview/io/NewickFile.java +++ b/src/jalview/io/NewickFile.java @@ -28,6 +28,7 @@ package jalview.io; import jalview.datamodel.SequenceNode; import jalview.util.MessageManager; +import jalview.util.Platform; import java.io.BufferedReader; import java.io.File; @@ -37,6 +38,8 @@ import java.util.StringTokenizer; import com.stevesoft.pat.Regex; +// TODO This class does not conform to Java standards for field name capitalization. + /** * Parse a new hanpshire style tree Caveats: NHX files are NOT supported and the * tree distances and topology are unreliable when they are parsed. TODO: on @@ -76,7 +79,7 @@ import com.stevesoft.pat.Regex; */ public class NewickFile extends FileParse { - SequenceNode root; + private SequenceNode root; private boolean HasBootstrap = false; @@ -85,21 +88,90 @@ public class NewickFile extends FileParse private boolean RootHasDistance = false; // File IO Flags - boolean ReplaceUnderscores = false; + private boolean ReplaceUnderscores = false; + + private boolean printRootInfo = true; + + private static final int REGEX_PERL_NODE_REQUIRE_QUOTE = 0; + + private static final int REGEX_PERL_NODE_ESCAPE_QUOTE = 1; + + private static final int REGEX_PERL_NODE_UNQUOTED_WHITESPACE = 2; + + private static final int REGEX_MAJOR_SYMS = 3; + + private static final int REGEX_QNODE_NAME = 4; + + private static final int REGEX_COMMENT = 5; + + private static final int REGEX_UQNODE_NAME = 6; - boolean printRootInfo = true; + private static final int REGEX_NBOOTSTRAP = 7; + + private static final int REGEX_NDIST = 8; + + private static final int REGEX_NO_LINES = 9; + + private static final int REGEX_PERL_EXPAND_QUOTES = 10; + + private static final int REGEX_MAX = 11; + + private static final Regex[] REGEX = new Regex[REGEX_MAX]; + + private static Regex getRegex(int id) + { + if (REGEX[id] == null) + { + String code = null; + String code2 = null; + String codePerl = null; + switch (id) + { + case REGEX_PERL_NODE_REQUIRE_QUOTE: + codePerl = "m/[\\[,:'()]/"; + break; + case REGEX_PERL_NODE_ESCAPE_QUOTE: + codePerl = "s/'/''/"; + break; + case REGEX_PERL_NODE_UNQUOTED_WHITESPACE: + codePerl = "s/\\/w/_/"; + break; + case REGEX_PERL_EXPAND_QUOTES: + codePerl = "s/''/'/"; + break; + case REGEX_MAJOR_SYMS: + code = "[(\\['),;]"; + break; + case REGEX_QNODE_NAME: + code = "'([^']|'')+'"; + break; + case REGEX_COMMENT: + code = "]"; + break; + case REGEX_UQNODE_NAME: + code = "\\b([^' :;\\](),]+)"; + break; + case REGEX_NBOOTSTRAP: + code = "\\s*([0-9+]+)\\s*:"; + break; + case REGEX_NDIST: + code = ":([-0-9Ee.+]+)"; + break; + case REGEX_NO_LINES: + code = "\n+"; + code2 = ""; + break; + default: + return null; + } + return codePerl == null ? Platform.newRegex(code, code2) + : Platform.newRegexPerl(codePerl); + } + return REGEX[id]; + } - private Regex[] NodeSafeName = new Regex[] { - new Regex().perlCode("m/[\\[,:'()]/"), // test for - // requiring - // quotes - new Regex().perlCode("s/'/''/"), // escaping quote - // characters - new Regex().perlCode("s/\\/w/_/") // unqoted whitespace - // transformation - }; - char QuoteChar = '\''; + private char quoteChar = '\''; /** * Creates a new NewickFile object. @@ -257,6 +329,7 @@ public class NewickFile extends FileParse */ public void parse() throws IOException { + Platform.ensureRegex(); String nf; { // fill nf with complete tree file @@ -294,8 +367,7 @@ public class NewickFile extends FileParse boolean ascending = false; // flag indicating that we are leaving the // current node - Regex majorsyms = new Regex( - "[(\\['),;]"); + Regex majorsyms = getRegex(REGEX_MAJOR_SYMS); // "[(\\['),;]" int nextcp = 0; int ncp = cp; @@ -354,8 +426,7 @@ public class NewickFile extends FileParse // Deal with quoted fields case '\'': - Regex qnodename = new Regex( - "'([^']|'')+'"); + Regex qnodename = getRegex(REGEX_QNODE_NAME);// "'([^']|'')+'"); if (qnodename.searchFrom(nf, fcp)) { @@ -363,8 +434,7 @@ public class NewickFile extends FileParse nodename = new String( qnodename.stringMatched().substring(1, nl - 1)); // unpack any escaped colons - Regex xpandquotes = Regex - .perlCode("s/''/'/"); + Regex xpandquotes = getRegex(REGEX_PERL_EXPAND_QUOTES); String widernodename = xpandquotes.replaceAll(nodename); nodename = widernodename; // jump to after end of quoted nodename @@ -398,8 +468,7 @@ public class NewickFile extends FileParse * '"+nf.substring(cp,fcp)+"'"); } */ // verify termination. - Regex comment = new Regex( - "]"); + Regex comment = getRegex(REGEX_COMMENT); // "]" if (comment.searchFrom(nf, fcp)) { // Skip the comment field @@ -430,12 +499,9 @@ public class NewickFile extends FileParse + fstring.substring(cend + 1); } - Regex uqnodename = new Regex( - "\\b([^' :;\\](),]+)"); - Regex nbootstrap = new Regex( - "\\s*([0-9+]+)\\s*:"); - Regex ndist = new Regex( - ":([-0-9Ee.+]+)"); + Regex uqnodename = getRegex(REGEX_UQNODE_NAME);// "\\b([^' :;\\](),]+)" + Regex nbootstrap = getRegex(REGEX_NBOOTSTRAP);// "\\s*([0-9+]+)\\s*:"); + Regex ndist = getRegex(REGEX_NDIST);// ":([-0-9Ee.+]+)"); if (!parsednodename && uqnodename.search(fstring) && ((uqnodename.matchedFrom(1) == 0) || (fstring @@ -475,7 +541,7 @@ public class NewickFile extends FileParse { try { - bootstrap = (Integer.valueOf(nbootstrap.stringMatched(1))) + bootstrap = (new Integer(nbootstrap.stringMatched(1))) .intValue(); HasBootstrap = true; } catch (Exception e) @@ -492,7 +558,7 @@ public class NewickFile extends FileParse { try { - distance = (Float.valueOf(ndist.stringMatched(1))).floatValue(); + distance = (new Float(ndist.stringMatched(1))).floatValue(); HasDistances = true; nodehasdistance = true; } catch (Exception e) @@ -659,7 +725,7 @@ public class NewickFile extends FileParse if (code.toLowerCase().equals("b")) { int v = -1; - Float iv = Float.valueOf(value); + Float iv = new Float(value); v = iv.intValue(); // jalview only does integer bootstraps // currently c.setBootstrap(v); @@ -790,7 +856,7 @@ public class NewickFile extends FileParse */ char getQuoteChar() { - return QuoteChar; + return quoteChar; } /** @@ -803,8 +869,8 @@ public class NewickFile extends FileParse */ char setQuoteChar(char c) { - char old = QuoteChar; - QuoteChar = c; + char old = quoteChar; + quoteChar = c; return old; } @@ -819,13 +885,15 @@ public class NewickFile extends FileParse */ private String nodeName(String name) { - if (NodeSafeName[0].search(name)) + if (getRegex(REGEX_PERL_NODE_REQUIRE_QUOTE).search(name)) { - return QuoteChar + NodeSafeName[1].replaceAll(name) + QuoteChar; + return quoteChar + + getRegex(REGEX_PERL_NODE_ESCAPE_QUOTE).replaceAll(name) + + quoteChar; } else { - return NodeSafeName[2].replaceAll(name); + return getRegex(REGEX_PERL_NODE_UNQUOTED_WHITESPACE).replaceAll(name); } } @@ -972,7 +1040,7 @@ public class NewickFile extends FileParse trf.parse(); System.out.println("Original file :\n"); - Regex nonl = new Regex("\n+", ""); + Regex nonl = getRegex(REGEX_NO_LINES);// "\n+", ""); System.out.println(nonl.replaceAll(newickfile.toString()) + "\n"); System.out.println("Parsed file.\n"); diff --git a/src/jalview/io/PIRFile.java b/src/jalview/io/PIRFile.java index d9ed516..3f0fea0 100755 --- a/src/jalview/io/PIRFile.java +++ b/src/jalview/io/PIRFile.java @@ -20,18 +20,16 @@ */ package jalview.io; +import jalview.bin.Cache; import jalview.datamodel.Sequence; import jalview.datamodel.SequenceI; import jalview.util.Comparison; import java.io.IOException; -import java.util.Vector; public class PIRFile extends AlignFile { - public static boolean useModellerOutput = false; - - Vector words = new Vector(); // Stores the words in a line after splitting + // Vector words = new Vector(); // Stores the words in a line after splitting public PIRFile() { @@ -111,7 +109,7 @@ public class PIRFile extends AlignFile StringBuffer out = new StringBuffer(); int i = 0; ModellerDescription md; - + boolean useModellerOutput = Cache.getDefault("PIR_MODELLER", false); while ((i < s.length) && (s[i] != null)) { String seq = s[i].getSequenceAsString(); @@ -147,7 +145,6 @@ public class PIRFile extends AlignFile } else { - if (useModellerOutput) { out.append(">P1;" + s[i].getName()); diff --git a/src/jalview/io/RnamlFile.java b/src/jalview/io/RnamlFile.java index 4d3ddc1..d5a8d81 100644 --- a/src/jalview/io/RnamlFile.java +++ b/src/jalview/io/RnamlFile.java @@ -26,6 +26,7 @@ import jalview.datamodel.Annotation; import jalview.datamodel.Sequence; import jalview.datamodel.SequenceI; import jalview.util.MessageManager; +import jalview.util.Platform; import java.io.BufferedReader; import java.io.FileNotFoundException; @@ -227,7 +228,7 @@ public class RnamlFile extends AlignFile dataName = dataName.substring(0, b - 1); } b = 0; - Regex m = new Regex("[\\/]?([-A-Za-z0-9]+)\\.?"); + Regex m = getSafeRegex(); String mm = dataName; while (m.searchFrom(dataName, b)) { @@ -236,4 +237,13 @@ public class RnamlFile extends AlignFile } return mm; } + + private static Regex SAFE_REGEX; + + private static Regex getSafeRegex() + { + return (SAFE_REGEX == null + ? SAFE_REGEX = Platform.newRegex("[\\/]?([-A-Za-z0-9]+)\\.?", null) + : SAFE_REGEX); + } } diff --git a/src/jalview/io/StockholmFile.java b/src/jalview/io/StockholmFile.java index 84e629e..92f73f4 100644 --- a/src/jalview/io/StockholmFile.java +++ b/src/jalview/io/StockholmFile.java @@ -36,6 +36,7 @@ import jalview.schemes.ResidueProperties; import jalview.util.Comparison; import jalview.util.Format; import jalview.util.MessageManager; +import jalview.util.Platform; import java.io.BufferedReader; import java.io.FileReader; @@ -76,20 +77,105 @@ public class StockholmFile extends AlignFile { private static final String ANNOTATION = "annotation"; -// private static final Regex OPEN_PAREN = new Regex("(<|\\[)", "("); -// -// private static final Regex CLOSE_PAREN = new Regex("(>|\\])", ")"); + // WUSS extended symbols. Avoid ambiguity with protein SS annotations by using + // NOT_RNASS first. - public static final Regex DETECT_BRACKETS = new Regex( - "(<|>|\\[|\\]|\\(|\\)|\\{|\\})"); - - // WUSS extended symbols. Avoid ambiguity with protein SS annotations by using NOT_RNASS first. public static final String RNASS_BRACKETS = "<>[](){}AaBbCcDdEeFfGgHhIiJjKkLlMmNnOoPpQqRrSsTtUuVvWwXxYyZz"; + public static final int REGEX_STOCKHOLM = 0; + + public static final int REGEX_BRACKETS = 1; + // use the following regex to decide an annotations (whole) line is NOT an RNA // SS (it contains only E,H,e,h and other non-brace/non-alpha chars) - private static final Regex NOT_RNASS = new Regex( - "^[^<>[\\](){}A-DF-Za-df-z]*$"); + public static final int REGEX_NOT_RNASS = 2; + + private static final int REGEX_ANNOTATION = 3; + + private static final int REGEX_PFAM = 4; + + private static final int REGEX_RFAM = 5; + + private static final int REGEX_ALIGN_END = 6; + + private static final int REGEX_SPLIT_ID = 7; + + private static final int REGEX_SUBTYPE = 8; + + private static final int REGEX_ANNOTATION_LINE = 9; + + private static final int REGEX_REMOVE_ID = 10; + + private static final int REGEX_OPEN_PAREN = 11; + + private static final int REGEX_CLOSE_PAREN = 12; + + public static final int REGEX_MAX = 13; + + private static Regex REGEX[] = new Regex[REGEX_MAX]; + + /** + * Centralize all actual Regex instantialization in Platform. + * + * @param id + * @return + */ + private static Regex getRegex(int id) + { + if (REGEX[id] == null) + { + String pat = null, pat2 = null; + switch (id) + { + case REGEX_STOCKHOLM: + pat = "# STOCKHOLM ([\\d\\.]+)"; + break; + case REGEX_BRACKETS: + // for reference; not used + pat = "(<|>|\\[|\\]|\\(|\\)|\\{|\\})"; + break; + case REGEX_NOT_RNASS: + pat = "^[^<>[\\](){}A-DF-Za-df-z]*$"; + break; + case REGEX_ANNOTATION: + pat = "(\\w+)\\s*(.*)"; + break; + case REGEX_PFAM: + pat = "PF[0-9]{5}(.*)"; + break; + case REGEX_RFAM: + pat = "RF[0-9]{5}(.*)"; + break; + case REGEX_ALIGN_END: + pat = "^\\s*\\/\\/"; + break; + case REGEX_SPLIT_ID: + pat = "(\\S+)\\/(\\d+)\\-(\\d+)"; + break; + case REGEX_SUBTYPE: + pat = "(\\S+)\\s+(\\S*)\\s+(.*)"; + break; + case REGEX_ANNOTATION_LINE: + pat = "#=(G[FSRC]?)\\s+(.*)"; + break; + case REGEX_REMOVE_ID: + pat = "(\\S+)\\s+(\\S+)"; + break; + case REGEX_OPEN_PAREN: + pat = "(<|\\[)"; + pat2 = "("; + break; + case REGEX_CLOSE_PAREN: + pat = "(>|\\])"; + pat2 = ")"; + break; + default: + return null; + } + REGEX[id] = Platform.newRegex(pat, pat2); + } + return REGEX[id]; + } StringBuffer out; // output buffer @@ -214,7 +300,7 @@ public class StockholmFile extends AlignFile // First, we have to check that this file has STOCKHOLM format, i.e. the // first line must match - r = new Regex("# STOCKHOLM ([\\d\\.]+)"); + r = getRegex(REGEX_STOCKHOLM); if (!r.search(nextLine())) { throw new IOException(MessageManager @@ -228,19 +314,22 @@ public class StockholmFile extends AlignFile } // We define some Regexes here that will be used regularily later - rend = new Regex("^\\s*\\/\\/"); // Find the end of an alignment - p = new Regex("(\\S+)\\/(\\d+)\\-(\\d+)"); // split sequence id in + rend = getRegex(REGEX_ALIGN_END);//"^\\s*\\/\\/"); // Find the end of an alignment + p = getRegex(REGEX_SPLIT_ID);//"(\\S+)\\/(\\d+)\\-(\\d+)"); // split sequence id in // id/from/to - s = new Regex("(\\S+)\\s+(\\S*)\\s+(.*)"); // Parses annotation subtype - r = new Regex("#=(G[FSRC]?)\\s+(.*)"); // Finds any annotation line - x = new Regex("(\\S+)\\s+(\\S+)"); // split id from sequence + s = getRegex(REGEX_SUBTYPE);// "(\\S+)\\s+(\\S*)\\s+(.*)"); // Parses + // annotation subtype + r = getRegex(REGEX_ANNOTATION_LINE);// "#=(G[FSRC]?)\\s+(.*)"); // Finds any + // annotation line + x = getRegex(REGEX_REMOVE_ID);// "(\\S+)\\s+(\\S+)"); // split id from + // sequence // Convert all bracket types to parentheses (necessary for passing to VARNA) - Regex openparen = new Regex("(<|\\[)", "("); - Regex closeparen = new Regex("(>|\\])", ")"); + Regex openparen = getRegex(REGEX_OPEN_PAREN);//"(<|\\[)", "("); + Regex closeparen = getRegex(REGEX_CLOSE_PAREN);//"(>|\\])", ")"); // // Detect if file is RNA by looking for bracket types -// Regex detectbrackets = new Regex("(<|>|\\[|\\]|\\(|\\))"); + // Regex detectbrackets = getRegex("(<|>|\\[|\\]|\\(|\\))"); rend.optimize(); p.optimize(); @@ -262,8 +351,8 @@ public class StockholmFile extends AlignFile this.noSeqs = seqs.size(); String dbsource = null; - Regex pf = new Regex("PF[0-9]{5}(.*)"); // Finds AC for Pfam - Regex rf = new Regex("RF[0-9]{5}(.*)"); // Finds AC for Rfam + Regex pf = getRegex(REGEX_PFAM); // Finds AC for Pfam + Regex rf = getRegex(REGEX_RFAM); // Finds AC for Rfam if (getAlignmentProperty("AC") != null) { String dbType = getAlignmentProperty("AC").toString(); @@ -507,7 +596,7 @@ public class StockholmFile extends AlignFile */ // Let's save the annotations, maybe we'll be able to do something // with them later... - Regex an = new Regex("(\\w+)\\s*(.*)"); + Regex an = getRegex(REGEX_ANNOTATION); if (an.search(annContent)) { if (an.stringMatched(1).equals("NH")) @@ -837,7 +926,8 @@ public class StockholmFile extends AlignFile if (type.equalsIgnoreCase("secondary structure")) { ss = true; - isrnass = !NOT_RNASS.search(annots); // sorry about the double negative + isrnass = !getRegex(REGEX_NOT_RNASS).search(annots); // sorry about the double + // negative // here (it's easier for dealing with // other non-alpha-non-brace chars) } @@ -998,7 +1088,7 @@ public class StockholmFile extends AlignFile while (en.hasMoreElements()) { Object idd = en.nextElement(); - String type = (String) dataRef.remove(idd); + String type = dataRef.remove(idd); out.append(new Format("%-" + (maxid - 2) + "s") .form("#=GS " + idd.toString() + " ")); if (type.contains("PFAM") || type.contains("RFAM")) diff --git a/src/jalview/io/TCoffeeScoreFile.java b/src/jalview/io/TCoffeeScoreFile.java index 7e963d5..d069e5e 100644 --- a/src/jalview/io/TCoffeeScoreFile.java +++ b/src/jalview/io/TCoffeeScoreFile.java @@ -109,7 +109,7 @@ public class TCoffeeScoreFile extends AlignFile public final static String TCOFFEE_SCORE = "TCoffeeScore"; - static Pattern SCORES_WITH_RESIDUE_NUMS = Pattern + private final static Pattern SCORES_WITH_RESIDUE_NUMS = Pattern .compile("^\\d+\\s([^\\s]+)\\s+\\d+$"); /** The {@link Header} structure holder */ @@ -198,7 +198,7 @@ public class TCoffeeScoreFile extends AlignFile { return null; } - List result = new ArrayList(scores.size()); + List result = new ArrayList<>(scores.size()); for (Map.Entry it : scores.entrySet()) { result.add(it.getValue().toString()); @@ -250,7 +250,7 @@ public class TCoffeeScoreFile extends AlignFile error = true; return; } - scores = new LinkedHashMap(); + scores = new LinkedHashMap<>(); /* * initilize the structure @@ -503,7 +503,7 @@ public class TCoffeeScoreFile extends AlignFile int score; - LinkedHashMap scores = new LinkedHashMap(); + LinkedHashMap scores = new LinkedHashMap<>(); public int getScoreAvg() { @@ -530,7 +530,7 @@ public class TCoffeeScoreFile extends AlignFile public Block(int size) { this.size = size; - this.items = new HashMap(size); + this.items = new HashMap<>(size); } String getScoresFor(String id) diff --git a/src/jalview/io/VamsasAppDatastore.java b/src/jalview/io/VamsasAppDatastore.java index 387dbfa..84d31f0 100644 --- a/src/jalview/io/VamsasAppDatastore.java +++ b/src/jalview/io/VamsasAppDatastore.java @@ -389,7 +389,6 @@ public class VamsasAppDatastore { dssmods.addElement(sequence); } - ; } if (dssmods.size() > 0) { @@ -585,7 +584,6 @@ public class VamsasAppDatastore (AlignmentSequence) alsref, aa[i]); break; } - ; } } } @@ -720,9 +718,9 @@ public class VamsasAppDatastore // /SAVE THE TREES // ///////////////////////////////// // FIND ANY ASSOCIATED TREES - if (Desktop.desktop != null) + if (Desktop.getDesktopPane() != null) { - javax.swing.JInternalFrame[] frames = Desktop.instance + javax.swing.JInternalFrame[] frames = Desktop.getInstance() .getAllFrames(); for (int t = 0; t < frames.length; t++) @@ -1478,8 +1476,7 @@ public class VamsasAppDatastore // active if (mappings != null) { - jalview.structure.StructureSelectionManager - .getStructureSelectionManager(Desktop.instance) + Desktop.getStructureSelectionManager() .registerMappings(mappings); } } @@ -2020,17 +2017,17 @@ public class VamsasAppDatastore } // bitfields - should be a template in j1.5 - private static int HASSECSTR = 0; + private static final int HASSECSTR = 0; - private static int HASVALS = 1; + private static final int HASVALS = 1; - private static int HASHPHOB = 2; + private static final int HASHPHOB = 2; - private static int HASDC = 3; + private static final int HASDC = 3; - private static int HASDESCSTR = 4; + private static final int HASDESCSTR = 4; - private static int HASTWOSTATE = 5; // not used yet. + private static final int HASTWOSTATE = 5; // not used yet. /** * parses the AnnotationElements - if they exist - into @@ -2248,7 +2245,7 @@ public class VamsasAppDatastore Float val = null; try { - val = Float.valueOf(props[p].getContent()); + val = new Float(props[p].getContent()); } catch (Exception e) { Cache.log.warn("Failed to parse threshold property"); @@ -2537,7 +2534,7 @@ public class VamsasAppDatastore int se_end = se[1 - se[2]] + (se[2] == 0 ? 1 : -1); for (int p = se[se[2]]; p != se_end; p += se[2] == 0 ? 1 : -1) { - posList.add(Integer.valueOf(p)); + posList.add(new Integer(p)); } } } @@ -2548,7 +2545,7 @@ public class VamsasAppDatastore for (int p = 0, pSize = dseta.getPosCount(); p < pSize; p++) { pos = dseta.getPos(p).getI(); - posList.add(Integer.valueOf(pos)); + posList.add(new Integer(pos)); } } } diff --git a/src/jalview/io/WSWUBlastClient.java b/src/jalview/io/WSWUBlastClient.java index 63b78b2..e24c2f3 100755 --- a/src/jalview/io/WSWUBlastClient.java +++ b/src/jalview/io/WSWUBlastClient.java @@ -150,7 +150,7 @@ public class WSWUBlastClient { // This must be outside the run() body as java 1.5 // will not return any value from the OptionPane to the expired thread. - int reply = JvOptionPane.showConfirmDialog(Desktop.desktop, + int reply = JvOptionPane.showConfirmDialog(Desktop.getDesktopPane(), "Automatically update suggested ids?", "Auto replace sequence ids", JvOptionPane.YES_NO_OPTION); diff --git a/src/jalview/io/cache/AppCache.java b/src/jalview/io/cache/AppCache.java index eaf6ecd..2a254cc 100644 --- a/src/jalview/io/cache/AppCache.java +++ b/src/jalview/io/cache/AppCache.java @@ -21,6 +21,8 @@ package jalview.io.cache; import jalview.bin.Cache; +import jalview.bin.ApplicationSingletonProvider; +import jalview.bin.ApplicationSingletonProvider.ApplicationSingletonI; import java.util.Hashtable; import java.util.LinkedHashSet; @@ -28,26 +30,31 @@ import java.util.LinkedHashSet; /** * A singleton class used for querying and persisting cache items. * + * * @author tcnofoegbu * */ -public class AppCache +public class AppCache implements ApplicationSingletonI { + + public static AppCache getInstance() + { + return (AppCache) ApplicationSingletonProvider.getInstance(AppCache.class); + } + + private AppCache() + { + cacheItems = new Hashtable<>(); + } + public static final String DEFAULT_LIMIT = "99"; public static final String CACHE_DELIMITER = ";"; - private static AppCache instance = null; - private static final String DEFAULT_LIMIT_KEY = ".DEFAULT_LIMIT"; private Hashtable> cacheItems; - private AppCache() - { - cacheItems = new Hashtable>(); - } - /** * Method to obtain all the cache items for a given cache key * @@ -59,27 +66,13 @@ public class AppCache LinkedHashSet foundCache = cacheItems.get(cacheKey); if (foundCache == null) { - foundCache = new LinkedHashSet(); + foundCache = new LinkedHashSet<>(); cacheItems.put(cacheKey, foundCache); } return foundCache; } /** - * Returns a singleton instance of AppCache - * - * @return - */ - public static AppCache getInstance() - { - if (instance == null) - { - instance = new AppCache(); - } - return instance; - } - - /** * Method for persisting cache items for a given cache key * * @param cacheKey diff --git a/src/jalview/io/cache/JvCacheableInputBox.java b/src/jalview/io/cache/JvCacheableInputBox.java index 9ec3a9f..e02a396 100644 --- a/src/jalview/io/cache/JvCacheableInputBox.java +++ b/src/jalview/io/cache/JvCacheableInputBox.java @@ -237,65 +237,76 @@ public class JvCacheableInputBox @Override public void run() { - int cacheLimit = Integer.parseInt(appCache.getCacheLimit(cacheKey)); - String userInput = getUserInput(); - if (userInput != null && !userInput.isEmpty()) - { - LinkedHashSet foundCache = appCache - .getAllCachedItemsFor(cacheKey); - // remove old cache item so as to place current input at the top of - // the result - foundCache.remove(userInput); - foundCache.add(userInput); - appCache.putCache(cacheKey, foundCache); - } + updateCacheNow(); + } + }); + } - String lastSearch = userInput; - if (comboBox.getItemCount() > 0) - { - comboBox.removeAllItems(); - } - Set cacheItems = appCache.getAllCachedItemsFor(cacheKey); - List reversedCacheItems = new ArrayList<>(); - reversedCacheItems.addAll(cacheItems); - cacheItems = null; - Collections.reverse(reversedCacheItems); - if (lastSearch.isEmpty()) - { - comboBox.addItem(""); - } + /** + * For TestNG + * + * @author Bob Hanson 2019.08.28 + */ + public void updateCacheNow() + { + int cacheLimit = Integer.parseInt(appCache.getCacheLimit(cacheKey)); + String userInput = getUserInput(); + if (userInput != null && !userInput.isEmpty()) + { + LinkedHashSet foundCache = appCache + .getAllCachedItemsFor(cacheKey); + // remove old cache item so as to place current input at the top of + // the result + foundCache.remove(userInput); + foundCache.add(userInput); + appCache.putCache(cacheKey, foundCache); + } - if (reversedCacheItems != null && !reversedCacheItems.isEmpty()) + String lastSearch = userInput; + if (comboBox.getItemCount() > 0) + { + comboBox.removeAllItems(); + } + Set cacheItems = appCache.getAllCachedItemsFor(cacheKey); + List reversedCacheItems = new ArrayList<>(); + reversedCacheItems.addAll(cacheItems); + cacheItems = null; + Collections.reverse(reversedCacheItems); + if (lastSearch.isEmpty()) + { + comboBox.addItem(""); + } + + if (reversedCacheItems != null && !reversedCacheItems.isEmpty()) + { + LinkedHashSet foundCache = appCache + .getAllCachedItemsFor(cacheKey); + boolean prune = reversedCacheItems.size() > cacheLimit; + int count = 1; + boolean limitExceeded = false; + for (String cacheItem : reversedCacheItems) + { + limitExceeded = (count++ > cacheLimit); + if (prune) { - LinkedHashSet foundCache = appCache - .getAllCachedItemsFor(cacheKey); - boolean prune = reversedCacheItems.size() > cacheLimit; - int count = 1; - boolean limitExceeded = false; - for (String cacheItem : reversedCacheItems) + if (limitExceeded) { - limitExceeded = (count++ > cacheLimit); - if (prune) - { - if (limitExceeded) - { - foundCache.remove(cacheItem); - } - else - { - comboBox.addItem(cacheItem); - } - } - else - { - comboBox.addItem(cacheItem); - } + foundCache.remove(cacheItem); } - appCache.putCache(cacheKey, foundCache); + else + { + comboBox.addItem(cacheItem); + } + } + else + { + comboBox.addItem(cacheItem); } - setSelectedItem(lastSearch.isEmpty() ? "" : lastSearch); } - }); + appCache.putCache(cacheKey, foundCache); + } + setSelectedItem(lastSearch.isEmpty() ? "" : lastSearch); + } /** diff --git a/src/jalview/io/gff/Gff3Helper.java b/src/jalview/io/gff/Gff3Helper.java index a25a014..28bcf44 100644 --- a/src/jalview/io/gff/Gff3Helper.java +++ b/src/jalview/io/gff/Gff3Helper.java @@ -91,7 +91,7 @@ public class Gff3Helper extends GffHelperBase String atts = gff[ATTRIBUTES_COL]; Map> attributes = parseNameValuePairs(atts); - SequenceOntologyI so = SequenceOntologyFactory.getInstance(); + SequenceOntologyI so = SequenceOntologyFactory.getSequenceOntology(); if (so.isA(soTerm, SequenceOntologyI.PROTEIN_MATCH)) { sf = processProteinMatch(attributes, seq, gff, align, newseqs, @@ -394,7 +394,7 @@ public class Gff3Helper extends GffHelperBase desc = target.split(" ")[0]; } - SequenceOntologyI so = SequenceOntologyFactory.getInstance(); + SequenceOntologyI so = SequenceOntologyFactory.getSequenceOntology(); String type = sf.getType(); if (so.isA(type, SequenceOntologyI.SEQUENCE_VARIANT)) { diff --git a/src/jalview/io/gff/InterProScanHelper.java b/src/jalview/io/gff/InterProScanHelper.java index 948cdd2..141b677 100644 --- a/src/jalview/io/gff/InterProScanHelper.java +++ b/src/jalview/io/gff/InterProScanHelper.java @@ -108,7 +108,7 @@ public class InterProScanHelper extends Gff3Helper */ public static boolean recognises(String[] columns) { - SequenceOntologyI so = SequenceOntologyFactory.getInstance(); + SequenceOntologyI so = SequenceOntologyFactory.getSequenceOntology(); String type = columns[TYPE_COL]; if (so.isA(type, SequenceOntologyI.PROTEIN_MATCH) || (".".equals(columns[SOURCE_COL]) diff --git a/src/jalview/io/gff/SequenceOntologyFactory.java b/src/jalview/io/gff/SequenceOntologyFactory.java index 90cae7a..2ba41da 100644 --- a/src/jalview/io/gff/SequenceOntologyFactory.java +++ b/src/jalview/io/gff/SequenceOntologyFactory.java @@ -20,29 +20,62 @@ */ package jalview.io.gff; +import jalview.bin.ApplicationSingletonProvider; +import jalview.bin.ApplicationSingletonProvider.ApplicationSingletonI; + /** * A factory class that returns a model of the Sequence Ontology. By default a - * hard-coded subset is used (for the applet, or testing), or setInstance() can - * be used to set full Ontology data. + * hard-coded subset is used (for the applet, or testing), or + * setSequenceOntology() can be used to set full Ontology data. * * @author gmcarstairs * */ -public class SequenceOntologyFactory +public class SequenceOntologyFactory implements ApplicationSingletonI { - private static SequenceOntologyI instance; + /** + * Answers an instance of this class for the current application context. Note + * that this supports running two JS 'applets' on the same page, one with the + * full Sequence Ontology (USE_FULL_SO = true) and one with a hard-coded + * subset (USE_FULL_SO = false). If this is overkill, could change this method + * to just return a common static instance. + * + * @return + */ + private static synchronized SequenceOntologyFactory getInstance() + { + return (SequenceOntologyFactory) ApplicationSingletonProvider + .getInstance(SequenceOntologyFactory.class); + } + + /** + * Answers the configured model of the Sequence Ontology. + * + * @return + */ + public static synchronized SequenceOntologyI getSequenceOntology() + { + SequenceOntologyFactory f = getInstance(); + return (f.sequenceOntology == null + ? f.sequenceOntology = new SequenceOntologyLite() + : f.sequenceOntology); + } - public static synchronized SequenceOntologyI getInstance() + /** + * For testng only + * + * @param so + */ + public static void setSequenceOntology(SequenceOntologyI so) { - if (instance == null) - { - instance = new SequenceOntologyLite(); - } - return instance; + getInstance().sequenceOntology = so; } - public static void setInstance(SequenceOntologyI so) + private SequenceOntologyI sequenceOntology; + + private SequenceOntologyFactory() { - instance = so; + // private singleton } + } diff --git a/src/jalview/io/vamsas/DatastoreRegistry.java b/src/jalview/io/vamsas/DatastoreRegistry.java index b53de08..ff7a764 100644 --- a/src/jalview/io/vamsas/DatastoreRegistry.java +++ b/src/jalview/io/vamsas/DatastoreRegistry.java @@ -24,7 +24,7 @@ import java.util.IdentityHashMap; import java.util.Iterator; import java.util.Map; -public class DatastoreRegistry implements AutoCloseable +public class DatastoreRegistry { protected static org.apache.log4j.Logger log = org.apache.log4j.Logger .getLogger(DatastoreRegistry.class); @@ -153,7 +153,7 @@ public class DatastoreRegistry implements AutoCloseable } @Override - public void close() + protected void finalize() throws Throwable { if (dsObjReg != null) { @@ -172,6 +172,6 @@ public class DatastoreRegistry implements AutoCloseable { dsItemReg.clear(); } - // super.finalize(); + super.finalize(); } } diff --git a/src/jalview/io/vamsas/Rangetype.java b/src/jalview/io/vamsas/Rangetype.java index b4580f0..ee4fa83 100644 --- a/src/jalview/io/vamsas/Rangetype.java +++ b/src/jalview/io/vamsas/Rangetype.java @@ -148,7 +148,7 @@ public abstract class Rangetype extends DatastoreItem int se_end = se[1 - se[2]] + (se[2] == 0 ? 1 : -1); for (int p = se[se[2]]; p != se_end; p += se[2] == 0 ? 1 : -1) { - posList.add(Integer.valueOf(p)); + posList.add(new Integer(p)); } } } @@ -159,7 +159,7 @@ public abstract class Rangetype extends DatastoreItem for (int p = 0, pSize = dseta.getPosCount(); p < pSize; p++) { pos = dseta.getPos(p).getI(); - posList.add(Integer.valueOf(pos)); + posList.add(new Integer(pos)); } } } @@ -193,8 +193,8 @@ public abstract class Rangetype extends DatastoreItem for (int s = 0, sSize = range.getSegCount(); s < sSize; s++) { se = getSegRange(range.getSeg(s), false); - posList.addElement(Integer.valueOf(se[0])); - posList.addElement(Integer.valueOf(se[1])); + posList.addElement(new Integer(se[0])); + posList.addElement(new Integer(se[1])); } } else if (range.getPosCount() > 0) @@ -204,8 +204,8 @@ public abstract class Rangetype extends DatastoreItem for (int p = 0, pSize = range.getPosCount(); p < pSize; p++) { pos = range.getPos(p).getI(); - posList.add(Integer.valueOf(pos)); - posList.add(Integer.valueOf(pos)); + posList.add(new Integer(pos)); + posList.add(new Integer(pos)); } } } diff --git a/src/jalview/io/vamsas/Sequencefeature.java b/src/jalview/io/vamsas/Sequencefeature.java index f8d86d5..dab840e 100644 --- a/src/jalview/io/vamsas/Sequencefeature.java +++ b/src/jalview/io/vamsas/Sequencefeature.java @@ -232,7 +232,7 @@ public class Sequencefeature extends Rangetype if (feature.otherDetails != null) { Iterator iter = feature.otherDetails.keySet().iterator(); - Vector props = dsa.getPropertyAsReference(); + Vector props = dsa.getPropertyAsReference(); while (iter.hasNext()) { String key = iter.next(); @@ -290,10 +290,11 @@ public class Sequencefeature extends Rangetype String featureType = dseta.getType(); if (dseta.getScoreCount() > 0) { - Enumeration scr = dseta.enumerateScore(); + @SuppressWarnings("unchecked") + Enumeration scr = dseta.enumerateScore(); while (scr.hasMoreElements()) { - Score score = (Score) scr.nextElement(); + Score score = scr.nextElement(); if (score.getName().equals(featureType)) { theScore = score.getContent(); @@ -325,10 +326,11 @@ public class Sequencefeature extends Rangetype } if (dseta.getScoreCount() > 0) { - Enumeration scr = dseta.enumerateScore(); + @SuppressWarnings("unchecked") + Enumeration scr = dseta.enumerateScore(); while (scr.hasMoreElements()) { - Score score = (Score) scr.nextElement(); + Score score = scr.nextElement(); if (!score.getName().equals(sf.getType())) { sf.setValue(score.getName(), "" + score.getContent()); @@ -336,10 +338,11 @@ public class Sequencefeature extends Rangetype } } // other details - Enumeration props = dseta.enumerateProperty(); + @SuppressWarnings("unchecked") + Enumeration props = dseta.enumerateProperty(); while (props.hasMoreElements()) { - Property p = (Property) props.nextElement(); + Property p = props.nextElement(); Object val = null; if (Properties.isValid(p)) { @@ -351,7 +354,7 @@ public class Sequencefeature extends Rangetype { try { - val = Boolean.valueOf(p.getContent()); + val = new Boolean(p.getContent()); } catch (Exception e) { } @@ -360,7 +363,7 @@ public class Sequencefeature extends Rangetype { try { - val = Float.valueOf(p.getContent()); + val = new Float(p.getContent()); } catch (Exception e) { @@ -370,7 +373,7 @@ public class Sequencefeature extends Rangetype { try { - val = Integer.valueOf(p.getContent()); + val = new Integer(p.getContent()); } catch (Exception e) { } diff --git a/src/jalview/io/vamsas/Sequencemapping.java b/src/jalview/io/vamsas/Sequencemapping.java index 0a582e5..542bd3f 100644 --- a/src/jalview/io/vamsas/Sequencemapping.java +++ b/src/jalview/io/vamsas/Sequencemapping.java @@ -110,27 +110,32 @@ public class Sequencemapping extends Rangetype } } + @Override public void addToDocument() { add(mjvmapping, from, ds); } + @Override public void addFromDocument() { add((SequenceMapping) vobj); } + @Override public void conflict() { conflict(mjvmapping, (SequenceMapping) vobj); } + @Override public void updateToDoc() { update(mjvmapping, (SequenceMapping) vobj); } + @Override public void updateFromDoc() { update((SequenceMapping) vobj, (jalview.datamodel.Mapping) jvobj); @@ -364,8 +369,7 @@ public class Sequencemapping extends Rangetype acf.addMap(from, to, mapping); } bindjvvobj(mapping, sequenceMapping); - jalview.structure.StructureSelectionManager - .getStructureSelectionManager(Desktop.instance) + Desktop.getStructureSelectionManager() .registerMapping(acf); // Try to link up any conjugate database references in the two sequences // matchConjugateDBRefs(from, to, mapping); @@ -402,7 +406,7 @@ public class Sequencemapping extends Rangetype + from.getName() + " and " + to.getName()); } List fdb = from.getDBRefs(); - List tdb = new ArrayList(to.getDBRefs()); + List tdb = new ArrayList<>(to.getDBRefs()); int tdblen = to.getDBRefs().size(); // // diff --git a/src/jalview/io/vamsas/Tree.java b/src/jalview/io/vamsas/Tree.java index 00e4fbc..e4e0b6c 100644 --- a/src/jalview/io/vamsas/Tree.java +++ b/src/jalview/io/vamsas/Tree.java @@ -443,7 +443,7 @@ public class Tree extends DatastoreItem Integer nindx = (Integer) nodespecs.get(nname); if (nindx == null) { - nindx = Integer.valueOf(1); + nindx = new Integer(1); } nname = nindx.toString() + " " + nname; return nname; @@ -465,7 +465,7 @@ public class Tree extends DatastoreItem String oval = nodespec.substring(0, nodespec.indexOf(' ')); try { - occurence = Integer.valueOf(oval).intValue(); + occurence = new Integer(oval).intValue(); } catch (Exception e) { System.err.println("Invalid nodespec '" + nodespec + "'"); @@ -517,7 +517,7 @@ public class Tree extends DatastoreItem * referenced in input data has already been associated with jalview objects. * * @param tp - * @param alignFrame + * @param loaderFrame * @return Object[] { AlignmentView, AlignmentI - reference alignment for * input } */ diff --git a/src/jalview/io/vcf/VCFLoader.java b/src/jalview/io/vcf/VCFLoader.java index 8d316fb..bf988da 100644 --- a/src/jalview/io/vcf/VCFLoader.java +++ b/src/jalview/io/vcf/VCFLoader.java @@ -51,8 +51,6 @@ import htsjdk.variant.vcf.VCFInfoHeaderLine; */ public class VCFLoader { - private static final String DEFAULT_SPECIES = "homo_sapiens"; - /** * A class to model the mapping from sequence to VCF coordinates. Cases include *
      @@ -84,7 +82,7 @@ public class VCFLoader /* * Lookup keys, and default values, for Preference entries that describe - * patterns for VCF and VEP fields to capture + * patterns for VCF and VEP fields to capture */ private static final String VEP_FIELDS_PREF = "VEP_FIELDS"; @@ -95,16 +93,6 @@ public class VCFLoader private static final String DEFAULT_VEP_FIELDS = ".*";// "Allele,Consequence,IMPACT,SWISSPROT,SIFT,PolyPhen,CLIN_SIG"; /* - * Lookup keys, and default values, for Preference entries that give - * mappings from tokens in the 'reference' header to species or assembly - */ - private static final String VCF_ASSEMBLY = "VCF_ASSEMBLY"; - - private static final String DEFAULT_VCF_ASSEMBLY = "assembly19=GRCh38,hs37=GRCh37,grch37=GRCh37,grch38=GRCh38"; - - private static final String VCF_SPECIES = "VCF_SPECIES"; // default is human - - /* * keys to fields of VEP CSQ consequence data * see https://www.ensembl.org/info/docs/tools/vep/vep_formats.html */ @@ -126,6 +114,12 @@ public class VCFLoader private static final String PIPE_REGEX = "\\|"; /* + * key for Allele Frequency output by VEP + * see http://www.ensembl.org/info/docs/tools/vep/vep_formats.html + */ + private static final String ALLELE_FREQUENCY_KEY = "AF"; + + /* * delimiter that separates multiple consequence data blocks */ private static final String COMMA = ","; @@ -161,16 +155,6 @@ public class VCFLoader private VCFHeader header; /* - * species (as a valid Ensembl term) the VCF is for - */ - private String vcfSpecies; - - /* - * genome assembly version (as a valid Ensembl identifier) the VCF is for - */ - private String vcfAssembly; - - /* * a Dictionary of contigs (if present) referenced in the VCF file */ private SAMSequenceDictionary dictionary; @@ -262,13 +246,12 @@ public class VCFLoader */ public SequenceI loadVCFContig(String contig) { - VCFHeaderLine headerLine = header.getOtherHeaderLine(VCFHeader.REFERENCE_KEY); - String ref = headerLine == null ? null : headerLine.getValue(); + String ref = header.getOtherHeaderLine(VCFHeader.REFERENCE_KEY) + .getValue(); if (ref.startsWith("file://")) { ref = ref.substring(7); } - setSpeciesAndAssembly(ref); SequenceI seq = null; File dbFile = new File(ref); @@ -277,7 +260,7 @@ public class VCFLoader { HtsContigDb db = new HtsContigDb("", dbFile); seq = db.getSequenceProxy(contig); - loadSequenceVCF(seq); + loadSequenceVCF(seq, ref); db.close(); } else @@ -301,9 +284,7 @@ public class VCFLoader { VCFHeaderLine ref = header .getOtherHeaderLine(VCFHeader.REFERENCE_KEY); - String reference = ref.getValue(); - - setSpeciesAndAssembly(reference); + String vcfAssembly = ref.getValue(); int varCount = 0; int seqCount = 0; @@ -313,7 +294,7 @@ public class VCFLoader */ for (SequenceI seq : seqs) { - int added = loadSequenceVCF(seq); + int added = loadSequenceVCF(seq, vcfAssembly); if (added > 0) { seqCount++; @@ -357,65 +338,6 @@ public class VCFLoader } /** - * Attempts to determine and save the species and genome assembly version to - * which the VCF data applies. This may be done by parsing the {@code reference} - * header line, configured in a property file, or (potentially) confirmed - * interactively by the user. - *

      - * The saved values should be identifiers valid for Ensembl's REST service - * {@code map} endpoint, so they can be used (if necessary) to retrieve the - * mapping between VCF coordinates and sequence coordinates. - * - * @param reference - * @see https://rest.ensembl.org/documentation/info/assembly_map - * @see https://rest.ensembl.org/info/assembly/human?content-type=text/xml - * @see https://rest.ensembl.org/info/species?content-type=text/xml - */ - protected void setSpeciesAndAssembly(String reference) - { - reference = reference.toLowerCase(); - vcfSpecies = DEFAULT_SPECIES; - - /* - * for a non-human species, or other assembly identifier, - * specify as a Jalview property file entry e.g. - * VCF_ASSEMBLY = hs37=GRCh37,assembly19=GRCh37 - * VCF_SPECIES = c_elegans=celegans - * to map a token in the reference header to a value - */ - String prop = Cache.getDefault(VCF_ASSEMBLY, DEFAULT_VCF_ASSEMBLY); - for (String token : prop.split(",")) - { - String[] tokens = token.split("="); - if (tokens.length == 2) - { - if (reference.contains(tokens[0].trim().toLowerCase())) - { - vcfAssembly = tokens[1].trim(); - break; - } - } - } - - prop = Cache.getProperty(VCF_SPECIES); - if (prop != null) - { - for (String token : prop.split(",")) - { - String[] tokens = token.split("="); - if (tokens.length == 2) - { - if (reference.contains(tokens[0].trim().toLowerCase())) - { - vcfSpecies = tokens[1].trim(); - break; - } - } - } - } - } - - /** * Opens the VCF file and parses header data * * @param filePath @@ -666,11 +588,12 @@ public class VCFLoader * and returns the number of variant features added * * @param seq + * @param vcfAssembly * @return */ - protected int loadSequenceVCF(SequenceI seq) + protected int loadSequenceVCF(SequenceI seq, String vcfAssembly) { - VCFMap vcfMap = getVcfMap(seq); + VCFMap vcfMap = getVcfMap(seq, vcfAssembly); if (vcfMap == null) { return 0; @@ -691,9 +614,10 @@ public class VCFLoader * Answers a map from sequence coordinates to VCF chromosome ranges * * @param seq + * @param vcfAssembly * @return */ - private VCFMap getVcfMap(SequenceI seq) + private VCFMap getVcfMap(SequenceI seq, String vcfAssembly) { /* * simplest case: sequence has id and length matching a VCF contig @@ -726,26 +650,32 @@ public class VCFLoader String seqRef = seqCoords.getAssemblyId(); MapList map = seqCoords.getMap(); - // note this requires the configured species to match that - // returned with the Ensembl sequence; todo: support aliases? - if (!vcfSpecies.equalsIgnoreCase(species)) + if (!vcfSpeciesMatchesSequence(vcfAssembly, species)) { - Cache.log.warn("No VCF loaded to " + seq.getName() - + " as species not matched"); return null; } - if (seqRef.equalsIgnoreCase(vcfAssembly)) + if (vcfAssemblyMatchesSequence(vcfAssembly, seqRef)) { return new VCFMap(chromosome, map); } + if (!"GRCh38".equalsIgnoreCase(seqRef) // Ensembl + || !vcfAssembly.contains("Homo_sapiens_assembly19")) // gnomAD + { + return null; + } + /* - * VCF data has a different reference assembly to the sequence: - * query Ensembl to map chromosomal coordinates from sequence to VCF + * map chromosomal coordinates from sequence to VCF if the VCF + * data has a different reference assembly to the sequence */ + // TODO generalise for cases other than GRCh38 -> GRCh37 ! + // - or get the user to choose in a dialog + List toVcfRanges = new ArrayList<>(); List fromSequenceRanges = new ArrayList<>(); + String toRef = "GRCh37"; for (int[] range : map.getToRanges()) { @@ -757,13 +687,12 @@ public class VCFLoader } int[] newRange = mapReferenceRange(range, chromosome, "human", seqRef, - vcfAssembly); + toRef); if (newRange == null) { Cache.log.error( String.format("Failed to map %s:%s:%s:%d:%d to %s", species, - chromosome, seqRef, range[0], range[1], - vcfAssembly)); + chromosome, seqRef, range[0], range[1], toRef)); continue; } else @@ -804,6 +733,62 @@ public class VCFLoader } /** + * Answers true if we determine that the VCF data uses the same reference + * assembly as the sequence, else false + * + * @param vcfAssembly + * @param seqRef + * @return + */ + private boolean vcfAssemblyMatchesSequence(String vcfAssembly, + String seqRef) + { + // TODO improve on this stub, which handles gnomAD and + // hopes for the best for other cases + + if ("GRCh38".equalsIgnoreCase(seqRef) // Ensembl + && vcfAssembly.contains("Homo_sapiens_assembly19")) // gnomAD + { + return false; + } + return true; + } + + /** + * Answers true if the species inferred from the VCF reference identifier + * matches that for the sequence + * + * @param vcfAssembly + * @param speciesId + * @return + */ + boolean vcfSpeciesMatchesSequence(String vcfAssembly, String speciesId) + { + // PROBLEM 1 + // there are many aliases for species - how to equate one with another? + // PROBLEM 2 + // VCF ##reference header is an unstructured URI - how to extract species? + // perhaps check if ref includes any (Ensembl) alias of speciesId?? + // TODO ask the user to confirm this?? + + if (vcfAssembly.contains("Homo_sapiens") // gnomAD exome data example + && "HOMO_SAPIENS".equals(speciesId)) // Ensembl species id + { + return true; + } + + if (vcfAssembly.contains("c_elegans") // VEP VCF response example + && "CAENORHABDITIS_ELEGANS".equals(speciesId)) // Ensembl + { + return true; + } + + // this is not a sustainable solution... + + return false; + } + + /** * Queries the VCF reader for any variants that overlap the mapped chromosome * ranges of the sequence, and adds as variant features. Returns the number of * overlapping variants found. diff --git a/src/jalview/javascript/JSFunctionExec.java b/src/jalview/javascript/JSFunctionExec.java index 29f3fa9..ad7a379 100644 --- a/src/jalview/javascript/JSFunctionExec.java +++ b/src/jalview/javascript/JSFunctionExec.java @@ -20,26 +20,28 @@ */ package jalview.javascript; -import jalview.bin.JalviewLite; +import jalview.api.JalviewApp; import java.net.URL; +import java.util.Hashtable; import java.util.Vector; import netscape.javascript.JSObject; public class JSFunctionExec implements Runnable { - public JalviewLite jvlite; + public JalviewApp jvlite; - public JSFunctionExec(JalviewLite applet) + protected boolean debug; + + public JSFunctionExec(JalviewApp applet, boolean debug) { jvlite = applet; - - jsExecQueue = jvlite.getJsExecQueue(); - jvlite.setExecutor(this); + this.debug = debug; + jsExecQueue = jvlite.getJsExecQueue(this); } - private Vector jsExecQueue; + private Vector jsExecQueue; private Thread executor = null; @@ -47,7 +49,7 @@ public class JSFunctionExec implements Runnable { if (jsExecQueue != null) { - Vector q = null; + Vector q = null; synchronized (jsExecQueue) { q = jsExecQueue; @@ -55,9 +57,9 @@ public class JSFunctionExec implements Runnable } if (q != null) { - for (JSFunctionExec jx : q) + for (Runnable jx : q) { - jx.jvlite = null; + ((JSFunctionExec) jx).jvlite = null; } q.removeAllElements(); @@ -78,7 +80,7 @@ public class JSFunctionExec implements Runnable { if (jsExecQueue.size() > 0) { - Runnable r = (Runnable) jsExecQueue.elementAt(0); + Runnable r = jsExecQueue.elementAt(0); jsExecQueue.removeElementAt(0); try { @@ -162,14 +164,14 @@ public class JSFunctionExec implements Runnable JSObject scriptObject = null; try { - scriptObject = JSObject.getWindow(jvlite); + scriptObject = jvlite.getJSObject(); } catch (Exception ex) { } ; if (scriptObject != null) { - if (jvlite.debug && dbgMsg != null) + if (debug && dbgMsg != null) { System.err.println(dbgMsg); } @@ -180,15 +182,15 @@ public class JSFunctionExec implements Runnable // squash any malformedURLExceptions thrown by windows/safari if (!(jex instanceof java.net.MalformedURLException)) { - if (jvlite.debug) + if (debug) { System.err.println(jex); } if (jex instanceof netscape.javascript.JSException - && jvlite.jsfallbackEnabled) + && jvlite.isJsfallbackEnabled()) { jsex[0] = jex; - if (jvlite.debug) + if (debug) { System.err.println("Falling back to javascript: url call"); } @@ -211,7 +213,7 @@ public class JSFunctionExec implements Runnable sb.append("\""); } sb.append(")"); - if (jvlite.debug) + if (debug) { System.err.println(sb.toString()); } @@ -248,7 +250,7 @@ public class JSFunctionExec implements Runnable { if (executor == null) { - executor = new Thread(new JSFunctionExec(jvlite)); + executor = new Thread(new JSFunctionExec(jvlite, debug)); executor.start(); } synchronized (jsExecQueue) @@ -268,4 +270,80 @@ public class JSFunctionExec implements Runnable } } + public static void setJsMessageSet(String messageclass, String viewId, + String[] colcommands, JalviewApp app) + { + Hashtable> jsmessages = app + .getJSMessages(); + Hashtable jshashes = app.getJSHashes(); + + Hashtable msgset = jsmessages.get(messageclass); + if (msgset == null) + { + msgset = new Hashtable<>(); + jsmessages.put(messageclass, msgset); + } + msgset.put(viewId, colcommands); + int[] l = new int[colcommands.length]; + for (int i = 0; i < colcommands.length; i++) + { + l[i] = colcommands[i].hashCode(); + } + jshashes.put(messageclass + "|" + viewId, l); + } + + /* + * (non-Javadoc) + * + * @see jalview.bin.JalviewLiteJsApi#getJsMessage(java.lang.String, + * java.lang.String) + */ + public static String getJsMessage(String messageclass, String viewId, + JalviewApp app) + { + Hashtable msgset = app.getJSMessages() + .get(messageclass); + if (msgset != null) + { + String[] msgs = msgset.get(viewId); + if (msgs != null) + { + for (int i = 0; i < msgs.length; i++) + { + if (msgs[i] != null) + { + String m = msgs[i]; + msgs[i] = null; + return m; + } + } + } + } + return ""; + } + + public static boolean isJsMessageSetChanged(String string, String string2, + String[] colcommands, JalviewApp app) + { + int[] l = app.getJSHashes().get(string + "|" + string2); + if (l == null && colcommands != null) + { + return true; + } + for (int i = 0; i < colcommands.length; i++) + { + if (l[i] != colcommands[i].hashCode()) + { + return true; + } + } + return false; + } + + public void tidyUp() + { + stopQueue(); + jvlite = null; + } + } diff --git a/src/jalview/javascript/JalviewLiteJsApi.java b/src/jalview/javascript/JalviewLiteJsApi.java index b5811aa..3ce2c9f 100644 --- a/src/jalview/javascript/JalviewLiteJsApi.java +++ b/src/jalview/javascript/JalviewLiteJsApi.java @@ -1,13 +1,13 @@ /* - * Jalview - A Sequence Alignment Editor and Viewer ($$Version-Rel$$) - * Copyright (C) $$Year-Rel$$ The Jalview Authors + * Jalview - A Sequence Alignment Editor and Viewer ($$Version-Rel$$); + * Copyright (C); $$Year-Rel$$ The Jalview Authors * * This file is part of Jalview. * * Jalview is free software: you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation, either version 3 - * of the License, or (at your option) any later version. + * of the License, or (at your option); any later version. * * Jalview is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty @@ -20,13 +20,13 @@ */ package jalview.javascript; -import jalview.appletgui.AlignFrame; +import jalview.api.AlignFrameI; /** * The following public methods may be called * externally, eg via javascript in an HTML page. * - *
      TODO: introduce abstract interface for jalview.appletgui.AlignFrame
      + *
      TODO: introduce abstract interface for jalview.appletgui.AlignFrameI
      * * Most function arguments are strings, which contain serialised versions of lists. * Lists of things are separated by a separator character - either the default or a user supplied one. @@ -42,7 +42,7 @@ public interface JalviewLiteJsApi /** * @return String list of selected sequence IDs, each terminated by the - * 'boolean not' character (""+0x00AC) or (¬) + * 'boolean not' character (""+0x00AC); or (¬); */ public abstract String getSelectedSequences(); @@ -56,12 +56,12 @@ public interface JalviewLiteJsApi /** * @param alf - * alignframe containing selection + * AlignFrameI containing selection * @return String list of selected sequence IDs, each terminated by current * default separator sequence * */ - public abstract String getSelectedSequencesFrom(AlignFrame alf); + public abstract String getSelectedSequencesFrom(AlignFrameI alf); /** * get list of selected sequence IDs separated by given separator @@ -73,7 +73,7 @@ public interface JalviewLiteJsApi * @return String list of selected sequence IDs, each terminated by the given * separator */ - public abstract String getSelectedSequencesFrom(AlignFrame alf, + public abstract String getSelectedSequencesFrom(AlignFrameI alf, String sep); /** @@ -99,7 +99,7 @@ public interface JalviewLiteJsApi * false, blank or something else - indicate if position is an * alignment column or unaligned sequence position */ - public abstract void highlightIn(AlignFrame alf, String sequenceId, + public abstract void highlightIn(AlignFrameI alf, String sequenceId, String position, String alignedPosition); /** @@ -133,7 +133,7 @@ public interface JalviewLiteJsApi * @param sep * separator between toselect fields */ - public abstract void selectIn(AlignFrame alf, String sequenceIds, + public abstract void selectIn(AlignFrameI alf, String sequenceIds, String columns); /** @@ -145,11 +145,11 @@ public interface JalviewLiteJsApi * @param sep * separator between toselect fields */ - public abstract void selectIn(AlignFrame alf, String sequenceIds, + public abstract void selectIn(AlignFrameI alf, String sequenceIds, String columns, String sep); /** - * get sequences selected in current alignFrame and return their alignment in + * get sequences selected in current AlignFrameI and return their alignment in * format 'format' either with or without suffix * * @param alf @@ -177,7 +177,8 @@ public interface JalviewLiteJsApi * @return selected sequences as flat file or empty string if there was no * current selection */ - public abstract String getSelectedSequencesAsAlignmentFrom(AlignFrame alf, + public abstract String getSelectedSequencesAsAlignmentFrom( + AlignFrameI alf, String format, String suffix); /** @@ -195,7 +196,7 @@ public interface JalviewLiteJsApi * @param alf * @return */ - public abstract String getAlignmentOrderFrom(AlignFrame alf); + public abstract String getAlignmentOrderFrom(AlignFrameI alf); /** * get a sep separated list of sequence IDs reflecting the order of the @@ -206,7 +207,8 @@ public interface JalviewLiteJsApi * - separator to use * @return */ - public abstract String getAlignmentOrderFrom(AlignFrame alf, String sep); + public abstract String getAlignmentOrderFrom(AlignFrameI alf, + String sep); /** * re-order the current alignment using the given list of sequence IDs @@ -232,7 +234,8 @@ public interface JalviewLiteJsApi * @return 'true' if alignment was actually reordered. empty string if * alignment did not contain sequences. */ - public abstract String orderBy(String order, String undoName, String sep); + public abstract String orderBy(String order, String undoName, + String sep); /** * re-order the given alignment using the given list of sequence IDs separated @@ -247,12 +250,12 @@ public interface JalviewLiteJsApi * @return 'true' if alignment was actually reordered. empty string if * alignment did not contain sequences. */ - public abstract String orderAlignmentBy(AlignFrame alf, String order, + public abstract String orderAlignmentBy(AlignFrameI alf, String order, String undoName, String sep); /** * get alignment as format (format names FASTA, BLC, CLUSTAL, MSF, PILEUP, - * PFAM - see jalview.io.AppletFormatAdapter for full list) + * PFAM - see jalview.io.AppletFormatAdapter for full list); * * @param format * @return @@ -266,7 +269,7 @@ public interface JalviewLiteJsApi * @param format * @return */ - public abstract String getAlignmentFrom(AlignFrame alf, String format); + public abstract String getAlignmentFrom(AlignFrameI alf, String format); /** * get alignment as format with jalview start-end sequence suffix appended @@ -286,7 +289,7 @@ public interface JalviewLiteJsApi * @param suffix * @return */ - public abstract String getAlignmentFrom(AlignFrame alf, String format, + public abstract String getAlignmentFrom(AlignFrameI alf, String format, String suffix); /** @@ -302,12 +305,12 @@ public interface JalviewLiteJsApi * @param alf * @param annotation */ - public abstract void loadAnnotationFrom(AlignFrame alf, + public abstract void loadAnnotationFrom(AlignFrameI alf, String annotation); /** * parse the given string as a jalview feature or GFF annotation file and - * optionally enable feature display on the current alignFrame + * optionally enable feature display on the current AlignFrameI * * @param features * - gff or features file @@ -320,7 +323,7 @@ public interface JalviewLiteJsApi /** * parse the given string as a jalview feature or GFF annotation file and - * optionally enable feature display on the given alignFrame. + * optionally enable feature display on the given AlignFrameI. * * @param alf * @param features @@ -330,11 +333,11 @@ public interface JalviewLiteJsApi * be parsed from the string. * @return true if data parsed as features */ - public abstract boolean loadFeaturesFrom(AlignFrame alf, String features, + public abstract boolean loadFeaturesFrom(AlignFrameI alf, String features, boolean autoenabledisplay); /** - * get the sequence features in the given format (Jalview or GFF) + * get the sequence features in the given format (Jalview or GFF); * * @param format * @return @@ -342,13 +345,13 @@ public interface JalviewLiteJsApi public abstract String getFeatures(String format); /** - * get the sequence features in alf in the given format (Jalview or GFF) + * get the sequence features in alf in the given format (Jalview or GFF); * * @param alf * @param format * @return */ - public abstract String getFeaturesFrom(AlignFrame alf, String format); + public abstract String getFeaturesFrom(AlignFrameI alf, String format); /** * get current alignment's annotation as an annotation file @@ -363,30 +366,30 @@ public interface JalviewLiteJsApi * @param alf * @return */ - public abstract String getAnnotationFrom(AlignFrame alf); + public abstract String getAnnotationFrom(AlignFrameI alf); /** - * create a new view and return the alignFrame instance + * create a new view and return the AlignFrameI instance * * @return */ - public abstract AlignFrame newView(); + public abstract AlignFrameI newView(); /** - * create a new view named name and return the alignFrame instance + * create a new view named name and return the AlignFrameI instance * * @param name * @return */ - public abstract AlignFrame newView(String name); + public abstract AlignFrameI newView(String name); /** - * create a new view on alf and return the alignFrame instance + * create a new view on alf and return the AlignFrameI instance * * @param alf * @return */ - public abstract AlignFrame newViewFrom(AlignFrame alf); + public abstract AlignFrameI newViewFrom(AlignFrameI alf); /** * create a new view named name on alf @@ -395,7 +398,7 @@ public interface JalviewLiteJsApi * @param name * @return */ - public abstract AlignFrame newViewFrom(AlignFrame alf, String name); + public abstract AlignFrameI newViewFrom(AlignFrameI alf, String name); /** * @@ -405,15 +408,15 @@ public interface JalviewLiteJsApi * window title * @return null or new alignment frame */ - public abstract AlignFrame loadAlignment(String text, String title); + public abstract AlignFrameI loadAlignment(String text, String title); /** * register a javascript function to handle any alignment mouseover events * * @param listener * name of javascript function (called with arguments - * [jalview.appletgui.AlignFrame,String(sequence id),String(column in - * alignment), String(position in sequence)] + * [jalview.appletgui.AlignFrameI,String(sequence id);,String(column + * in alignment);, String(position in sequence);] */ public abstract void setMouseoverListener(String listener); @@ -421,12 +424,13 @@ public interface JalviewLiteJsApi * register a javascript function to handle mouseover events * * @param af - * (null or specific alignframe for which events are to be listened - * for) + * (null or specific AlignFrameI for which events are to be listened + * for); * @param listener * name of javascript function */ - public abstract void setMouseoverListener(AlignFrame af, String listener); + public abstract void setMouseoverListener(AlignFrameI af, + String listener); /** * register a javascript function to handle any alignment selection events. @@ -435,14 +439,15 @@ public interface JalviewLiteJsApi * * @param listener * name of javascript function (called with arguments - * [jalview.appletgui.AlignFrame, String(sequence set id), - * String(separator separated list of sequences which were selected), - * String(separator separated list of column ranges (i.e. single - * number or hyphenated range) that were selected)] + * [jalview.appletgui.AlignFrameI, String(sequence set id);, + * String(separator separated list of sequences which were + * selected);, String(separator separated list of column ranges (i.e. + * single number or hyphenated range); that were selected);] */ public abstract void setSelectionListener(String listener); - public abstract void setSelectionListener(AlignFrame af, String listener); + public abstract void setSelectionListener(AlignFrameI af, + String listener); /** * register a javascript function to handle events normally routed to a Jmol @@ -450,11 +455,11 @@ public interface JalviewLiteJsApi * * @param listener * - javascript function (arguments are variable, see - * jalview.javascript.MouseOverStructureListener for full details) + * jalview.javascript.MouseOverStructureListener for full details); * @param modelSet * - separator separated list of PDB file URIs that this viewer is * handling. These files must be in the same order they appear in - * Jmol (e.g. first one is frame 1, second is frame 2, etc). + * Jmol (e.g. first one is frame 1, second is frame 2, etc);. * @see jalview.javascript.MouseOverStructureListener */ public abstract void setStructureListener(String listener, @@ -462,14 +467,14 @@ public interface JalviewLiteJsApi /** * remove any callback using the given listener function and associated with - * the given alignFrame (or null for all callbacks) + * the given AlignFrameI (or null for all callbacks); * * @param af - * (may be null) + * (may be null); * @param listener - * (may be null) + * (may be null); */ - public abstract void removeJavascriptListener(AlignFrame af, + public abstract void removeJavascriptListener(AlignFrameI af, String listener); /** @@ -484,10 +489,10 @@ public interface JalviewLiteJsApi String pdbfile); /** - * bind a pdb file to a sequence in the given alignFrame. + * bind a pdb file to a sequence in the given AlignFrameI. * * @param alFrame - * - null or specific alignFrame. This specifies the dataset that + * - null or specific AlignFrameI. This specifies the dataset that * will be searched for a seuqence called sequenceId * @param sequenceId * - sequenceId within the dataset. @@ -499,7 +504,7 @@ public interface JalviewLiteJsApi * structure for indicating when PDB parsing or sequenceId location * fails. */ - public abstract boolean addPdbFile(AlignFrame alFrame, String sequenceId, + public abstract boolean addPdbFile(AlignFrameI alFrame, String sequenceId, String pdbEntryString, String pdbFile); /** @@ -510,7 +515,7 @@ public interface JalviewLiteJsApi * @param topRow * @param leftHandColumn */ - public abstract void scrollViewToIn(AlignFrame alf, String topRow, + public abstract void scrollViewToIn(AlignFrameI alf, String topRow, String leftHandColumn); /** @@ -519,7 +524,7 @@ public interface JalviewLiteJsApi * @param alf * @param topRow */ - public abstract void scrollViewToRowIn(AlignFrame alf, String topRow); + public abstract void scrollViewToRowIn(AlignFrameI alf, String topRow); /** * adjust horizontal scroll to make the given column the left one in the given @@ -528,28 +533,28 @@ public interface JalviewLiteJsApi * @param alf * @param leftHandColumn */ - public abstract void scrollViewToColumnIn(AlignFrame alf, + public abstract void scrollViewToColumnIn(AlignFrameI alf, String leftHandColumn); /** * * @return - * @see jalview.appletgui.AlignFrame#getFeatureGroups() + * @see jalview.appletgui.AlignFrameI#getFeatureGroups(); */ public abstract String getFeatureGroups(); /** * @param alf - * alignframe to get feature groups on + * AlignFrameI to get feature groups on * @return - * @see jalview.appletgui.AlignFrame#getFeatureGroups() + * @see jalview.appletgui.AlignFrameI#getFeatureGroups(); */ - public abstract String getFeatureGroupsOn(AlignFrame alf); + public abstract String getFeatureGroupsOn(AlignFrameI alf); /** * @param visible * @return - * @see jalview.appletgui.AlignFrame#getFeatureGroupsOfState(boolean) + * @see jalview.appletgui.AlignFrameI#getFeatureGroupsOfState(boolean); */ public abstract String getFeatureGroupsOfState(boolean visible); @@ -558,9 +563,9 @@ public interface JalviewLiteJsApi * align frame to get groups of state visible * @param visible * @return - * @see jalview.appletgui.AlignFrame#getFeatureGroupsOfState(boolean) + * @see jalview.appletgui.AlignFrameI#getFeatureGroupsOfState(boolean); */ - public abstract String getFeatureGroupsOfStateOn(AlignFrame alf, + public abstract String getFeatureGroupsOfStateOn(AlignFrameI alf, boolean visible); /** @@ -568,10 +573,11 @@ public interface JalviewLiteJsApi * tab separated list of group names * @param state * true or false - * @see jalview.appletgui.AlignFrame#setFeatureGroupState(java.lang.String[], - * boolean) + * @see jalview.appletgui.AlignFrameI#setFeatureGroupState(java.lang.String[], + * boolean); */ - public abstract void setFeatureGroupStateOn(AlignFrame alf, String groups, + public abstract void setFeatureGroupStateOn(AlignFrameI alf, + String groups, boolean state); public abstract void setFeatureGroupState(String groups, boolean state); @@ -600,4 +606,24 @@ public interface JalviewLiteJsApi */ public abstract String getJsMessage(String messageclass, String viewId); + /// in http://www.jalview.org/examples/jalviewLiteJs.html but missing here + + // get selected sequences as alignment as format with or without start-end + // suffix + public String getSelectedSequencesAsAlignment(String format, + boolean suffix); + + // get selected sequences as alignment from given view as format with or + // without start-end suffix + public String getSelectedSequencesAsAlignmentFrom(AlignFrameI alf, + String format, boolean suffix); + + public String arrayToSeparatorList(String[] array); + + // get a string array from a list + public String[] separatorListToArray(String list); + + // debug flag - controls output to standard out + public static boolean debug = false; + } diff --git a/src/jalview/javascript/JsSelectionSender.java b/src/jalview/javascript/JsSelectionSender.java index c2a963e..56efe70 100644 --- a/src/jalview/javascript/JsSelectionSender.java +++ b/src/jalview/javascript/JsSelectionSender.java @@ -20,8 +20,8 @@ */ package jalview.javascript; +import jalview.api.JalviewApp; import jalview.appletgui.AlignFrame; -import jalview.bin.JalviewLite; import jalview.datamodel.ColumnSelection; import jalview.datamodel.HiddenColumns; import jalview.datamodel.SequenceGroup; @@ -35,10 +35,10 @@ public class JsSelectionSender extends JSFunctionExec String _listener; - public JsSelectionSender(JalviewLite jvlite, AlignFrame af, - String listener) + public JsSelectionSender(JalviewApp jvlite, AlignFrame af, + String listener, boolean debug) { - super(jvlite); + super(jvlite, debug); _af = af; _listener = listener; } @@ -47,70 +47,13 @@ public class JsSelectionSender extends JSFunctionExec public void selection(SequenceGroup seqsel, ColumnSelection colsel, HiddenColumns hidden, SelectionSource source) { - // System.err.println("Testing selection event relay to - // jsfunction:"+_listener); + Object[] info = jvlite.getSelectionForListener(seqsel, colsel, hidden, source, _af); try { - String setid = ""; - AlignFrame src = _af; - if (source != null) - { - if (source instanceof jalview.appletgui.AlignViewport - && ((jalview.appletgui.AlignViewport) source).applet.currentAlignFrame.viewport == source) - { - // should be valid if it just generated an event! - src = ((jalview.appletgui.AlignViewport) source).applet.currentAlignFrame; - } - } - String[] seqs = new String[] {}; - String[] cols = new String[] {}; - int strt = 0, end = (src == null) ? -1 - : src.alignPanel.av.getAlignment().getWidth(); - if (seqsel != null && seqsel.getSize() > 0) - { - seqs = new String[seqsel.getSize()]; - for (int i = 0; i < seqs.length; i++) - { - seqs[i] = seqsel.getSequenceAt(i).getName(); - } - if (strt < seqsel.getStartRes()) - { - strt = seqsel.getStartRes(); - } - if (end == -1 || end > seqsel.getEndRes()) - { - end = seqsel.getEndRes(); - } - } - if (colsel != null && !colsel.isEmpty()) - { - if (end == -1) - { - end = colsel.getMax() + 1; - } - cols = new String[colsel.getSelected().size()]; - for (int i = 0; i < cols.length; i++) - { - cols[i] = "" + (1 + colsel.getSelected().get(i).intValue()); - } - } - else - { - if (seqsel != null && seqsel.getSize() > 0) - { - // send a valid range, otherwise we send the empty selection - cols = new String[2]; - cols[0] = "" + (1 + strt) + "-" + (1 + end); - } - ; - - } System.err.println("Relaying selection to jsfunction:" + _listener); - executeJavascriptFunction(_listener, - new Object[] - { src, setid, jvlite.arrayToSeparatorList(seqs), - jvlite.arrayToSeparatorList(cols) }); + executeJavascriptFunction(_listener, info); + } catch (Exception ex) { System.err.println( @@ -125,6 +68,7 @@ public class JsSelectionSender extends JSFunctionExec } } + } @Override diff --git a/src/jalview/javascript/MouseOverListener.java b/src/jalview/javascript/MouseOverListener.java index 6a4d0f8..7c74965 100644 --- a/src/jalview/javascript/MouseOverListener.java +++ b/src/jalview/javascript/MouseOverListener.java @@ -20,8 +20,8 @@ */ package jalview.javascript; +import jalview.api.JalviewApp; import jalview.appletgui.AlignFrame; -import jalview.bin.JalviewLite; import jalview.datamodel.SequenceI; import jalview.structure.VamsasListener; import jalview.structure.VamsasSource; @@ -48,25 +48,12 @@ public class MouseOverListener extends JSFunctionExec // + seq + " at " + index); last = seq; i = index; - AlignFrame src = null; + Object alignFrame = jvlite.getFrameForSource(source); try { - if (source != null) - { - if (source instanceof jalview.appletgui.AlignViewport - && ((jalview.appletgui.AlignViewport) source).applet.currentAlignFrame.viewport == source) - { - // should be valid if it just generated an event! - src = ((jalview.appletgui.AlignViewport) source).applet.currentAlignFrame; - - } - // TODO: ensure that if '_af' is specified along with a handler - // function, then only events from that alignFrame are sent to that - // function - } executeJavascriptFunction(_listener, new Object[] - { src, seq.getDisplayId(false), "" + (1 + i), + { alignFrame, seq.getDisplayId(false), "" + (1 + i), "" + seq.findPosition(i) }); } catch (Exception ex) { @@ -84,10 +71,10 @@ public class MouseOverListener extends JSFunctionExec } } - public MouseOverListener(JalviewLite applet, AlignFrame af, - String listener) + public MouseOverListener(JalviewApp applet, AlignFrame af, + String listener, boolean debug) { - super(applet); + super(applet, debug); _af = af; _listener = listener; } diff --git a/src/jalview/javascript/MouseOverStructureListener.java b/src/jalview/javascript/MouseOverStructureListener.java index 6071933..28e2ced 100644 --- a/src/jalview/javascript/MouseOverStructureListener.java +++ b/src/jalview/javascript/MouseOverStructureListener.java @@ -20,11 +20,11 @@ */ package jalview.javascript; +import jalview.api.AlignViewportI; import jalview.api.AlignmentViewPanel; -import jalview.api.FeatureRenderer; +import jalview.api.JalviewApp; import jalview.api.SequenceRenderer; import jalview.appletgui.AlignFrame; -import jalview.bin.JalviewLite; import jalview.datamodel.SequenceI; import jalview.ext.jmol.JmolCommands; import jalview.structure.AtomSpec; @@ -76,12 +76,12 @@ public class MouseOverStructureListener extends JSFunctionExec String _listenerfn; - String[] modelSet; + public String[] modelSet; - public MouseOverStructureListener(JalviewLite jalviewLite, - String listener, String[] modelList) + public MouseOverStructureListener(JalviewApp app, String listener, + String[] modelList, boolean debug) { - super(jalviewLite); + super(app, debug); _listenerfn = listener; modelSet = modelList; if (modelSet != null) @@ -165,21 +165,22 @@ public class MouseOverStructureListener extends JSFunctionExec } @Override - public synchronized void updateColours(Object srce) + public synchronized void updateColours(Object source) { - final Object source = srce; StructureSelectionManager ssm = StructureSelectionManager - .getStructureSelectionManager(jvlite); + .getStructureSelectionManager( + jvlite.getStructureSelectionManagerProvider()); - if (JalviewLite.debug) + if (debug) { System.err.println( this.getClass().getName() + " modelSet[0]: " + modelSet[0]); ssm.reportMapping(); } - if (source instanceof jalview.api.AlignmentViewPanel) + if (source instanceof AlignmentViewPanel) { + AlignmentViewPanel panel = (AlignmentViewPanel) source; SequenceI[][] sequence = new SequenceI[modelSet.length][]; for (int m = 0; m < modelSet.length; m++) { @@ -203,25 +204,20 @@ public class MouseOverStructureListener extends JSFunctionExec // } } - SequenceRenderer sr = ((jalview.appletgui.AlignmentPanel) source) - .getSequenceRenderer(); - FeatureRenderer fr = ((jalview.appletgui.AlignmentPanel) source).av - .isShowSequenceFeatures() - ? new jalview.appletgui.FeatureRenderer( - ((jalview.appletgui.AlignmentPanel) source).av) - : null; + SequenceRenderer sr = panel.getSequenceRenderer(); + AlignViewportI vp = panel.getAlignViewport(); + jalview.renderer.seqfeatures.FeatureRenderer fr = vp + .isShowSequenceFeatures() ? jvlite.getNewFeatureRenderer(vp) + : null; if (fr != null) { - ((jalview.appletgui.FeatureRenderer) fr).transferSettings( - ((jalview.appletgui.AlignmentPanel) source) - .getFeatureRenderer()); + fr.transferSettings(panel.getFeatureRenderer()); } - ; // Form a colour command from the given alignment panel for each distinct // structure - ArrayList ccomands = new ArrayList(); - ArrayList pdbfn = new ArrayList(); + ArrayList ccomands = new ArrayList<>(); + ArrayList pdbfn = new ArrayList<>(); StructureMappingcommandSet[] colcommands = JmolCommands .getColourBySequenceCommand(ssm, modelSet, sequence, sr, (AlignmentViewPanel) source); @@ -237,7 +233,6 @@ public class MouseOverStructureListener extends JSFunctionExec pdbfn.add(ccset.mapping); } - String mclass, mhandle; String ccomandset[] = new String[sz]; sz = 0; for (String[] ccset : ccomands) @@ -245,28 +240,16 @@ public class MouseOverStructureListener extends JSFunctionExec System.arraycopy(ccset, 0, ccomandset, sz, ccset.length); sz += ccset.length; } - if (jvlite.isJsMessageSetChanged(mclass = "colourstruct", - mhandle = ((jalview.appletgui.AlignmentPanel) source).av - .getViewId(), - ccomandset)) + String mclass = "colourstruct"; + String mhandle = vp.getViewId(); + if (isJsMessageSetChanged(mclass, mhandle, ccomandset, jvlite)) { - jvlite.setJsMessageSet(mclass, mhandle, ccomandset); + setJsMessageSet(mclass, mhandle, ccomandset, jvlite); // and notify javascript handler - String st[] = new String[] { "colourstruct", - "" + ((jalview.appletgui.AlignmentPanel) source).av.getViewId(), + String st[] = new String[] { mclass, mhandle, "" + ccomandset.length, jvlite.arrayToSeparatorList( pdbfn.toArray(new String[pdbfn.size()])) }; - try - { - executeJavascriptFunction(true, _listenerfn, st); - } catch (Exception ex) - { - System.err.println("Couldn't execute callback with " + _listenerfn - + " using args { " + st[0] + ", " + st[1] + ", " + st[2] - + "," + st[3] + "}"); // + ","+st[4]+"\n"); - ex.printStackTrace(); - - } + executeJavascriptFunction(true, st); } /* * new Thread(new Runnable() { public void run() { // and send to @@ -283,6 +266,7 @@ public class MouseOverStructureListener extends JSFunctionExec */ } + jvlite.updateColoursFromMouseOver(source, this); } @Override @@ -312,4 +296,19 @@ public class MouseOverStructureListener extends JSFunctionExec return true; } + public void executeJavascriptFunction(boolean b, String[] st) + { + try + { + executeJavascriptFunction(true, _listenerfn, st); + } catch (Exception ex) + { + System.err.println("Couldn't execute callback with " + _listenerfn + + " using args { " + st[0] + ", " + st[1] + ", " + st[2] + "," + + st[3] + "}"); // + ","+st[4]+"\n"); + ex.printStackTrace(); + + } + } + } diff --git a/src/jalview/javascript/json/JSON.java b/src/jalview/javascript/json/JSON.java index 4e9d1dd..72d8982 100644 --- a/src/jalview/javascript/json/JSON.java +++ b/src/jalview/javascript/json/JSON.java @@ -16,7 +16,7 @@ import java.net.URL; * methods for extracting data. [get(), contains(), probably should add keySet, * valueSet, and entrySet]. * - * @author hansonr Bob Hanson St. Olaf College 1/24/2019 + * @author hansonr Bob Hanson St. Olaf College 1/24/2019+ * */ public class JSON { diff --git a/src/jalview/jbgui/GAlignFrame.java b/src/jalview/jbgui/GAlignFrame.java index 6685c67..9de31ab 100755 --- a/src/jalview/jbgui/GAlignFrame.java +++ b/src/jalview/jbgui/GAlignFrame.java @@ -25,6 +25,7 @@ import jalview.analysis.GeneticCodeI; import jalview.analysis.GeneticCodes; import jalview.api.SplitContainerI; import jalview.bin.Cache; +import jalview.bin.Jalview; import jalview.gui.JvSwingUtils; import jalview.gui.Preferences; import jalview.io.FileFormats; @@ -35,6 +36,7 @@ import jalview.util.Platform; import java.awt.BorderLayout; import java.awt.Color; import java.awt.GridLayout; +import java.awt.Toolkit; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.awt.event.FocusAdapter; @@ -220,7 +222,7 @@ public class GAlignFrame extends JInternalFrame { // for Web-page embedding using id=align-frame-div - setName("jalview-alignment"); + setName(Jalview.getAppID("alignment")); jbInit(); setJMenuBar(alignFrameMenuBar); @@ -276,14 +278,14 @@ public class GAlignFrame extends JInternalFrame // FIXME getDefaultToolkit throws an exception in Headless mode KeyStroke keyStroke = KeyStroke.getKeyStroke(KeyEvent.VK_S, - jalview.util.ShortcutKeyMaskExWrapper.getMenuShortcutKeyMaskEx() - | jalview.util.ShortcutKeyMaskExWrapper.SHIFT_DOWN_MASK, + Toolkit.getDefaultToolkit().getMenuShortcutKeyMask() + | KeyEvent.SHIFT_MASK, false); addMenuActionAndAccelerator(keyStroke, saveAs, al); closeMenuItem.setText(MessageManager.getString("action.close")); keyStroke = KeyStroke.getKeyStroke(KeyEvent.VK_W, - jalview.util.ShortcutKeyMaskExWrapper.getMenuShortcutKeyMaskEx(), false); + Toolkit.getDefaultToolkit().getMenuShortcutKeyMask(), false); al = new ActionListener() { @Override @@ -306,7 +308,7 @@ public class GAlignFrame extends JInternalFrame JMenuItem selectAllSequenceMenuItem = new JMenuItem( MessageManager.getString("action.select_all")); keyStroke = KeyStroke.getKeyStroke(KeyEvent.VK_A, - jalview.util.ShortcutKeyMaskExWrapper.getMenuShortcutKeyMaskEx(), false); + Toolkit.getDefaultToolkit().getMenuShortcutKeyMask(), false); al = new ActionListener() { @Override @@ -333,7 +335,7 @@ public class GAlignFrame extends JInternalFrame JMenuItem invertSequenceMenuItem = new JMenuItem( MessageManager.getString("action.invert_sequence_selection")); keyStroke = KeyStroke.getKeyStroke(KeyEvent.VK_I, - jalview.util.ShortcutKeyMaskExWrapper.getMenuShortcutKeyMaskEx(), false); + Toolkit.getDefaultToolkit().getMenuShortcutKeyMask(), false); al = new ActionListener() { @Override @@ -369,7 +371,7 @@ public class GAlignFrame extends JInternalFrame JMenuItem remove2LeftMenuItem = new JMenuItem( MessageManager.getString("action.remove_left")); keyStroke = KeyStroke.getKeyStroke(KeyEvent.VK_L, - jalview.util.ShortcutKeyMaskExWrapper.getMenuShortcutKeyMaskEx(), false); + Toolkit.getDefaultToolkit().getMenuShortcutKeyMask(), false); al = new ActionListener() { @Override @@ -383,7 +385,7 @@ public class GAlignFrame extends JInternalFrame JMenuItem remove2RightMenuItem = new JMenuItem( MessageManager.getString("action.remove_right")); keyStroke = KeyStroke.getKeyStroke(KeyEvent.VK_R, - jalview.util.ShortcutKeyMaskExWrapper.getMenuShortcutKeyMaskEx(), false); + Toolkit.getDefaultToolkit().getMenuShortcutKeyMask(), false); al = new ActionListener() { @Override @@ -397,7 +399,7 @@ public class GAlignFrame extends JInternalFrame JMenuItem removeGappedColumnMenuItem = new JMenuItem( MessageManager.getString("action.remove_empty_columns")); keyStroke = KeyStroke.getKeyStroke(KeyEvent.VK_E, - jalview.util.ShortcutKeyMaskExWrapper.getMenuShortcutKeyMaskEx(), false); + Toolkit.getDefaultToolkit().getMenuShortcutKeyMask(), false); al = new ActionListener() { @Override @@ -411,8 +413,8 @@ public class GAlignFrame extends JInternalFrame JMenuItem removeAllGapsMenuItem = new JMenuItem( MessageManager.getString("action.remove_all_gaps")); keyStroke = KeyStroke.getKeyStroke(KeyEvent.VK_E, - jalview.util.ShortcutKeyMaskExWrapper.getMenuShortcutKeyMaskEx() - | jalview.util.ShortcutKeyMaskExWrapper.SHIFT_DOWN_MASK, + Toolkit.getDefaultToolkit().getMenuShortcutKeyMask() + | KeyEvent.SHIFT_MASK, false); al = new ActionListener() { @@ -519,7 +521,7 @@ public class GAlignFrame extends JInternalFrame JMenuItem removeRedundancyMenuItem = new JMenuItem( MessageManager.getString("action.remove_redundancy")); keyStroke = KeyStroke.getKeyStroke(KeyEvent.VK_D, - jalview.util.ShortcutKeyMaskExWrapper.getMenuShortcutKeyMaskEx(), false); + Toolkit.getDefaultToolkit().getMenuShortcutKeyMask(), false); al = new ActionListener() { @Override @@ -543,7 +545,11 @@ public class GAlignFrame extends JInternalFrame this.getContentPane().setLayout(new BorderLayout()); alignFrameMenuBar.setFont(new java.awt.Font("Verdana", 0, 11)); - statusBar.setBackground(Color.white); + // statusBar.setBackground(Color.white); BH 2019.08.01 -- this does nothing, + // as the label is not opaque + statusBar.setOpaque(true);// BH 2019.07.01 -- setting a label opaque avoids + // frame repaint in SwingJS and has no effect in + // Java statusBar.setFont(new java.awt.Font("Verdana", 0, 11)); statusBar.setBorder(BorderFactory.createLineBorder(Color.black)); statusBar.setText(MessageManager.getString("label.status_bar")); @@ -554,7 +560,7 @@ public class GAlignFrame extends JInternalFrame annotationPanelMenuItem .setText(MessageManager.getString("label.show_annotations")); annotationPanelMenuItem - .setState(Cache.getDefault("SHOW_ANNOTATIONS", true)); + .setState(Cache.getDefault(Preferences.SHOW_ANNOTATIONS, true)); annotationPanelMenuItem.addActionListener(new ActionListener() { @Override @@ -694,7 +700,7 @@ public class GAlignFrame extends JInternalFrame undoMenuItem.setEnabled(false); undoMenuItem.setText(MessageManager.getString("action.undo")); keyStroke = KeyStroke.getKeyStroke(KeyEvent.VK_Z, - jalview.util.ShortcutKeyMaskExWrapper.getMenuShortcutKeyMaskEx(), false); + Toolkit.getDefaultToolkit().getMenuShortcutKeyMask(), false); al = new ActionListener() { @Override @@ -708,7 +714,7 @@ public class GAlignFrame extends JInternalFrame redoMenuItem.setEnabled(false); redoMenuItem.setText(MessageManager.getString("action.redo")); keyStroke = KeyStroke.getKeyStroke(KeyEvent.VK_Y, - jalview.util.ShortcutKeyMaskExWrapper.getMenuShortcutKeyMaskEx(), false); + Toolkit.getDefaultToolkit().getMenuShortcutKeyMask(), false); al = new ActionListener() { @Override @@ -732,7 +738,7 @@ public class GAlignFrame extends JInternalFrame JMenuItem printMenuItem = new JMenuItem( MessageManager.getString("action.print")); keyStroke = KeyStroke.getKeyStroke(KeyEvent.VK_P, - jalview.util.ShortcutKeyMaskExWrapper.getMenuShortcutKeyMaskEx(), false); + Toolkit.getDefaultToolkit().getMenuShortcutKeyMask(), false); al = new ActionListener() { @Override @@ -758,7 +764,7 @@ public class GAlignFrame extends JInternalFrame JMenuItem findMenuItem = new JMenuItem( MessageManager.getString("action.find")); keyStroke = KeyStroke.getKeyStroke(KeyEvent.VK_F, - jalview.util.ShortcutKeyMaskExWrapper.getMenuShortcutKeyMaskEx(), false); + Toolkit.getDefaultToolkit().getMenuShortcutKeyMask(), false); findMenuItem.setToolTipText(JvSwingUtils.wrapTooltip(true, MessageManager.getString("label.find_tip"))); al = new ActionListener() @@ -919,7 +925,7 @@ public class GAlignFrame extends JInternalFrame JMenuItem deleteGroups = new JMenuItem( MessageManager.getString("action.undefine_groups")); keyStroke = KeyStroke.getKeyStroke(KeyEvent.VK_U, - jalview.util.ShortcutKeyMaskExWrapper.getMenuShortcutKeyMaskEx(), false); + Toolkit.getDefaultToolkit().getMenuShortcutKeyMask(), false); al = new ActionListener() { @Override @@ -944,7 +950,7 @@ public class GAlignFrame extends JInternalFrame JMenuItem createGroup = new JMenuItem( MessageManager.getString("action.create_group")); keyStroke = KeyStroke.getKeyStroke(KeyEvent.VK_G, - jalview.util.ShortcutKeyMaskExWrapper.getMenuShortcutKeyMaskEx(), false); + Toolkit.getDefaultToolkit().getMenuShortcutKeyMask(), false); al = new ActionListener() { @Override @@ -958,8 +964,8 @@ public class GAlignFrame extends JInternalFrame JMenuItem unGroup = new JMenuItem( MessageManager.getString("action.remove_group")); keyStroke = KeyStroke.getKeyStroke(KeyEvent.VK_G, - jalview.util.ShortcutKeyMaskExWrapper.getMenuShortcutKeyMaskEx() - | jalview.util.ShortcutKeyMaskExWrapper.SHIFT_DOWN_MASK, + Toolkit.getDefaultToolkit().getMenuShortcutKeyMask() + | KeyEvent.SHIFT_MASK, false); al = new ActionListener() { @@ -973,7 +979,7 @@ public class GAlignFrame extends JInternalFrame copy.setText(MessageManager.getString("action.copy")); keyStroke = KeyStroke.getKeyStroke(KeyEvent.VK_C, - jalview.util.ShortcutKeyMaskExWrapper.getMenuShortcutKeyMaskEx(), false); + Toolkit.getDefaultToolkit().getMenuShortcutKeyMask(), false); al = new ActionListener() { @@ -987,7 +993,7 @@ public class GAlignFrame extends JInternalFrame cut.setText(MessageManager.getString("action.cut")); keyStroke = KeyStroke.getKeyStroke(KeyEvent.VK_X, - jalview.util.ShortcutKeyMaskExWrapper.getMenuShortcutKeyMaskEx(), false); + Toolkit.getDefaultToolkit().getMenuShortcutKeyMask(), false); al = new ActionListener() { @Override @@ -1013,8 +1019,8 @@ public class GAlignFrame extends JInternalFrame JMenuItem pasteNew = new JMenuItem( MessageManager.getString("label.to_new_alignment")); keyStroke = KeyStroke.getKeyStroke(KeyEvent.VK_V, - jalview.util.ShortcutKeyMaskExWrapper.getMenuShortcutKeyMaskEx() - | jalview.util.ShortcutKeyMaskExWrapper.SHIFT_DOWN_MASK, + Toolkit.getDefaultToolkit().getMenuShortcutKeyMask() + | KeyEvent.SHIFT_MASK, false); al = new ActionListener() { @@ -1029,7 +1035,7 @@ public class GAlignFrame extends JInternalFrame JMenuItem pasteThis = new JMenuItem( MessageManager.getString("label.to_this_alignment")); keyStroke = KeyStroke.getKeyStroke(KeyEvent.VK_V, - jalview.util.ShortcutKeyMaskExWrapper.getMenuShortcutKeyMaskEx(), false); + Toolkit.getDefaultToolkit().getMenuShortcutKeyMask(), false); al = new ActionListener() { @Override @@ -1063,7 +1069,7 @@ public class GAlignFrame extends JInternalFrame }); seqLimits.setText( MessageManager.getString("label.show_sequence_limits")); - seqLimits.setState(jalview.bin.Cache.getDefault("SHOW_JVSUFFIX", true)); + seqLimits.setState(jalview.bin.Cache.getDefault(Preferences.SHOW_JVSUFFIX, true)); seqLimits.addActionListener(new ActionListener() { @Override @@ -1214,7 +1220,7 @@ public class GAlignFrame extends JInternalFrame padGapsMenuitem.setText(MessageManager.getString("label.pad_gaps")); padGapsMenuitem - .setState(jalview.bin.Cache.getDefault("PAD_GAPS", false)); + .setState(jalview.bin.Cache.getDefault(Preferences.PAD_GAPS, false)); padGapsMenuitem.addActionListener(new ActionListener() { @Override @@ -1241,8 +1247,7 @@ public class GAlignFrame extends JInternalFrame showTranslation .setText(MessageManager.getString("label.translate_cDNA")); boolean first = true; - for (final GeneticCodeI table : GeneticCodes.getInstance() - .getCodeTables()) + for (final GeneticCodeI table : GeneticCodes.getCodeTables()) { JMenuItem item = new JMenuItem(table.getId() + " " + table.getName()); showTranslation.add(item); @@ -1358,7 +1363,7 @@ public class GAlignFrame extends JInternalFrame autoCalculate.setText( MessageManager.getString("label.autocalculate_consensus")); autoCalculate.setState( - jalview.bin.Cache.getDefault("AUTO_CALC_CONSENSUS", true)); + jalview.bin.Cache.getDefault(Preferences.AUTO_CALC_CONSENSUS, true)); autoCalculate.addActionListener(new ActionListener() { @Override @@ -1372,7 +1377,8 @@ public class GAlignFrame extends JInternalFrame sortByTree.setToolTipText("" + MessageManager.getString( "label.enable_automatically_sort_alignment_when_open_new_tree")); sortByTree - .setState(jalview.bin.Cache.getDefault("SORT_BY_TREE", false)); + .setState(jalview.bin.Cache.getDefault(Preferences.SORT_BY_TREE, + false)); sortByTree.addActionListener(new ActionListener() { @Override @@ -1546,8 +1552,8 @@ public class GAlignFrame extends JInternalFrame JMenuItem invertColSel = new JMenuItem( MessageManager.getString("action.invert_column_selection")); keyStroke = KeyStroke.getKeyStroke(KeyEvent.VK_I, - jalview.util.ShortcutKeyMaskExWrapper.getMenuShortcutKeyMaskEx() - | jalview.util.ShortcutKeyMaskExWrapper.ALT_DOWN_MASK, + Toolkit.getDefaultToolkit().getMenuShortcutKeyMask() + | KeyEvent.ALT_MASK, false); al = new ActionListener() { @@ -1610,7 +1616,7 @@ public class GAlignFrame extends JInternalFrame JMenuItem save = new JMenuItem(MessageManager.getString("action.save")); keyStroke = KeyStroke.getKeyStroke(KeyEvent.VK_S, - jalview.util.ShortcutKeyMaskExWrapper.getMenuShortcutKeyMaskEx(), false); + Toolkit.getDefaultToolkit().getMenuShortcutKeyMask(), false); al = new ActionListener() { @Override @@ -1635,7 +1641,7 @@ public class GAlignFrame extends JInternalFrame JMenuItem newView = new JMenuItem( MessageManager.getString("action.new_view")); keyStroke = KeyStroke.getKeyStroke(KeyEvent.VK_T, - jalview.util.ShortcutKeyMaskExWrapper.getMenuShortcutKeyMaskEx(), false); + Toolkit.getDefaultToolkit().getMenuShortcutKeyMask(), false); al = new ActionListener() { @Override diff --git a/src/jalview/jbgui/GAlignmentPanel.java b/src/jalview/jbgui/GAlignmentPanel.java index b703b47..3dd0205 100755 --- a/src/jalview/jbgui/GAlignmentPanel.java +++ b/src/jalview/jbgui/GAlignmentPanel.java @@ -123,6 +123,7 @@ public class GAlignmentPanel extends JPanel hscrollFillerPanel.setPreferredSize(new Dimension(70, 10)); hscrollHolder.setBackground(Color.white); annotationScroller.setBorder(null); + annotationScroller.setBackground(Color.BLUE); annotationScroller.setPreferredSize(new Dimension(10, 80)); this.setPreferredSize(new Dimension(220, 166)); diff --git a/src/jalview/jbgui/GCutAndPasteHtmlTransfer.java b/src/jalview/jbgui/GCutAndPasteHtmlTransfer.java index 3f0df21..a6e0ace 100644 --- a/src/jalview/jbgui/GCutAndPasteHtmlTransfer.java +++ b/src/jalview/jbgui/GCutAndPasteHtmlTransfer.java @@ -22,10 +22,10 @@ package jalview.jbgui; import jalview.gui.JvSwingUtils; import jalview.util.MessageManager; -import jalview.util.ShortcutKeyMaskExWrapper; import java.awt.BorderLayout; import java.awt.Font; +import java.awt.Toolkit; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.awt.event.MouseEvent; @@ -136,11 +136,11 @@ public class GCutAndPasteHtmlTransfer extends JInternalFrame }); close.setAccelerator(javax.swing.KeyStroke.getKeyStroke( java.awt.event.KeyEvent.VK_W, - ShortcutKeyMaskExWrapper.getMenuShortcutKeyMaskEx(), false)); + Toolkit.getDefaultToolkit().getMenuShortcutKeyMask(), false)); selectAll.setText(MessageManager.getString("action.select_all")); selectAll.setAccelerator(javax.swing.KeyStroke.getKeyStroke( java.awt.event.KeyEvent.VK_A, - ShortcutKeyMaskExWrapper.getMenuShortcutKeyMaskEx(), false)); + Toolkit.getDefaultToolkit().getMenuShortcutKeyMask(), false)); selectAll.addActionListener(new ActionListener() { @Override @@ -153,7 +153,7 @@ public class GCutAndPasteHtmlTransfer extends JInternalFrame save.setText(MessageManager.getString("action.save")); save.setAccelerator(javax.swing.KeyStroke.getKeyStroke( java.awt.event.KeyEvent.VK_S, - ShortcutKeyMaskExWrapper.getMenuShortcutKeyMaskEx(), false)); + Toolkit.getDefaultToolkit().getMenuShortcutKeyMask(), false)); save.addActionListener(new ActionListener() { @Override @@ -164,7 +164,7 @@ public class GCutAndPasteHtmlTransfer extends JInternalFrame }); copyItem.setAccelerator(javax.swing.KeyStroke.getKeyStroke( java.awt.event.KeyEvent.VK_C, - ShortcutKeyMaskExWrapper.getMenuShortcutKeyMaskEx(), false)); + Toolkit.getDefaultToolkit().getMenuShortcutKeyMask(), false)); editMenubar.add(jMenu1); editMenubar.add(editMenu); diff --git a/src/jalview/jbgui/GCutAndPasteTransfer.java b/src/jalview/jbgui/GCutAndPasteTransfer.java index 94a4677..97ac840 100755 --- a/src/jalview/jbgui/GCutAndPasteTransfer.java +++ b/src/jalview/jbgui/GCutAndPasteTransfer.java @@ -123,7 +123,7 @@ public class GCutAndPasteTransfer extends JInternalFrame selectAll.setText(MessageManager.getString("action.select_all")); selectAll.setAccelerator(javax.swing.KeyStroke.getKeyStroke( java.awt.event.KeyEvent.VK_A, - jalview.util.ShortcutKeyMaskExWrapper.getMenuShortcutKeyMaskEx(), false)); + Toolkit.getDefaultToolkit().getMenuShortcutKeyMask(), false)); selectAll.addActionListener(new ActionListener() { @Override @@ -136,7 +136,7 @@ public class GCutAndPasteTransfer extends JInternalFrame save.setText(MessageManager.getString("action.save")); save.setAccelerator(javax.swing.KeyStroke.getKeyStroke( java.awt.event.KeyEvent.VK_S, - jalview.util.ShortcutKeyMaskExWrapper.getMenuShortcutKeyMaskEx(), false)); + Toolkit.getDefaultToolkit().getMenuShortcutKeyMask(), false)); save.addActionListener(new ActionListener() { @Override @@ -147,10 +147,10 @@ public class GCutAndPasteTransfer extends JInternalFrame }); copyItem.setAccelerator(javax.swing.KeyStroke.getKeyStroke( java.awt.event.KeyEvent.VK_C, - jalview.util.ShortcutKeyMaskExWrapper.getMenuShortcutKeyMaskEx(), false)); + Toolkit.getDefaultToolkit().getMenuShortcutKeyMask(), false)); pasteMenu.setAccelerator(javax.swing.KeyStroke.getKeyStroke( java.awt.event.KeyEvent.VK_V, - jalview.util.ShortcutKeyMaskExWrapper.getMenuShortcutKeyMaskEx(), false)); + Toolkit.getDefaultToolkit().getMenuShortcutKeyMask(), false)); editMenubar.add(jMenu1); editMenubar.add(editMenu); textarea.setFont(new java.awt.Font("Monospaced", Font.PLAIN, 12)); diff --git a/src/jalview/jbgui/GDesktop.java b/src/jalview/jbgui/GDesktop.java index cd64e7b..051bac7 100755 --- a/src/jalview/jbgui/GDesktop.java +++ b/src/jalview/jbgui/GDesktop.java @@ -21,11 +21,13 @@ package jalview.jbgui; import jalview.api.AlignmentViewPanel; +import jalview.bin.Jalview; import jalview.io.FileFormatException; import jalview.util.MessageManager; import jalview.util.Platform; import java.awt.FlowLayout; +import java.awt.Toolkit; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; @@ -36,16 +38,14 @@ import javax.swing.JMenuBar; import javax.swing.JMenuItem; /** - * DOCUMENT ME! + * abstract class super to jalview.gui.Desktop * - * @author $author$ - * @version $Revision$ */ @SuppressWarnings("serial") -public class GDesktop extends JFrame +public abstract class GDesktop extends JFrame { - protected static JMenu windowMenu = new JMenu(); + public JMenu windowMenu = new JMenu(); // BH 2019.05.07 was static JMenuBar desktopMenubar = new JMenuBar(); @@ -109,7 +109,7 @@ public class GDesktop extends JFrame protected JCheckBoxMenuItem showConsole = new JCheckBoxMenuItem(); - protected JCheckBoxMenuItem showNews = new JCheckBoxMenuItem(); + public JCheckBoxMenuItem showNews = new JCheckBoxMenuItem(); protected JMenuItem snapShotWindow = new JMenuItem(); @@ -118,7 +118,6 @@ public class GDesktop extends JFrame */ public GDesktop() { - super(); try { jbInit(); @@ -152,7 +151,7 @@ public class GDesktop extends JFrame */ private void jbInit() throws Exception { - setName("jalview-desktop"); + setName(Jalview.getAppID("desktop")); FileMenu.setText(MessageManager.getString("action.file")); HelpMenu.setText(MessageManager.getString("action.help")); VamsasMenu.setText("Vamsas"); @@ -165,7 +164,7 @@ public class GDesktop extends JFrame .setText(MessageManager.getString("label.load_tree_from_file")); inputLocalFileMenuItem.setAccelerator( javax.swing.KeyStroke.getKeyStroke(java.awt.event.KeyEvent.VK_O, - jalview.util.ShortcutKeyMaskExWrapper.getMenuShortcutKeyMaskEx(), + Toolkit.getDefaultToolkit().getMenuShortcutKeyMask(), false)); inputLocalFileMenuItem .addActionListener(new java.awt.event.ActionListener() @@ -429,8 +428,6 @@ public class GDesktop extends JFrame } }); - Float specversion = Float.parseFloat(System.getProperty("java.specification.version")); - desktopMenubar.add(FileMenu); desktopMenubar.add(toolsMenu); VamsasMenu.setVisible(false); @@ -440,7 +437,7 @@ public class GDesktop extends JFrame FileMenu.add(inputMenu); FileMenu.add(inputSequence); FileMenu.addSeparator(); - //FileMenu.add(saveState); + FileMenu.add(saveState); FileMenu.add(saveAsState); FileMenu.add(loadState); FileMenu.addSeparator(); @@ -453,14 +450,14 @@ public class GDesktop extends JFrame VamsasMenu.add(vamsasImport); VamsasMenu.add(vamsasSave); VamsasMenu.add(vamsasStop); - if (!Platform.isMac() || specversion < 11) - { - toolsMenu.add(preferences); - } + toolsMenu.add(preferences); if (!Platform.isJS()) { toolsMenu.add(showMemusage); toolsMenu.add(showConsole); + } + if (!Platform.isJS()) + { toolsMenu.add(showNews); toolsMenu.add(garbageCollect); toolsMenu.add(groovyShell); @@ -562,7 +559,6 @@ public class GDesktop extends JFrame */ protected void quit() { - //System.out.println("********** GDesktop.quit()"); } /** diff --git a/src/jalview/jbgui/GPCAPanel.java b/src/jalview/jbgui/GPCAPanel.java index a6498d2..04aab37 100755 --- a/src/jalview/jbgui/GPCAPanel.java +++ b/src/jalview/jbgui/GPCAPanel.java @@ -20,6 +20,7 @@ */ package jalview.jbgui; +import jalview.bin.Jalview; import jalview.util.ImageMaker.TYPE; import jalview.util.MessageManager; @@ -88,8 +89,8 @@ public class GPCAPanel extends JInternalFrame private void jbInit() throws Exception { - setName("jalview-pca"); - this.getContentPane().setLayout(new BorderLayout()); + setName(Jalview.getAppID("pca")); + getContentPane().setLayout(new BorderLayout()); JPanel jPanel2 = new JPanel(); jPanel2.setLayout(new FlowLayout()); JLabel jLabel1 = new JLabel(); diff --git a/src/jalview/jbgui/GPreferences.java b/src/jalview/jbgui/GPreferences.java index 9327569..7784cf4 100755 --- a/src/jalview/jbgui/GPreferences.java +++ b/src/jalview/jbgui/GPreferences.java @@ -31,8 +31,6 @@ import jalview.gui.JvSwingUtils; import jalview.gui.StructureViewer.ViewerType; import jalview.io.BackupFilenameParts; import jalview.io.BackupFiles; -import jalview.io.BackupFilesPresetEntry; -import jalview.io.IntKeyStringValueEntry; import jalview.util.MessageManager; import jalview.util.Platform; @@ -54,8 +52,8 @@ import java.awt.event.KeyEvent; import java.awt.event.KeyListener; import java.awt.event.MouseAdapter; import java.awt.event.MouseEvent; -import java.util.Arrays; -import java.util.List; +import java.util.HashMap; +import java.util.Map; import javax.swing.AbstractCellEditor; import javax.swing.BorderFactory; @@ -66,6 +64,7 @@ import javax.swing.JCheckBox; import javax.swing.JComboBox; import javax.swing.JFileChooser; import javax.swing.JLabel; +import javax.swing.JList; import javax.swing.JPanel; import javax.swing.JRadioButton; import javax.swing.JScrollPane; @@ -93,6 +92,7 @@ import javax.swing.table.TableCellRenderer; * @author $author$ * @version $Revision$ */ +@SuppressWarnings("serial") public class GPreferences extends JPanel { private static final Font LABEL_FONT = JvSwingUtils.getLabelFont(); @@ -180,6 +180,8 @@ public class GPreferences extends JPanel protected JComboBox structViewer = new JComboBox<>(); + protected JTextField structureDimensions = new JTextField(); + protected JTextField chimeraPath = new JTextField(); protected ButtonGroup mappingMethod = new ButtonGroup(); @@ -215,13 +217,13 @@ public class GPreferences extends JPanel /* * Connections tab components */ - protected JTable linkUrlTable = new JTable(); + public JTable linkUrlTable = new JTable(); - protected JButton editLink = new JButton(); + public JButton editLink = new JButton(); - protected JButton deleteLink = new JButton(); + public JButton deleteLink = new JButton(); - protected JTextField filterTB = new JTextField(); + public JTextField filterTB = new JTextField(); protected JButton doReset = new JButton(); @@ -302,15 +304,9 @@ public class GPreferences extends JPanel protected JPanel presetsPanel = new JPanel(); - protected JLabel presetsComboLabel = new JLabel(); - - protected JCheckBox customiseCheckbox = new JCheckBox(); - protected JButton revertButton = new JButton(); - protected JComboBox backupfilesPresetsCombo = new JComboBox<>(); - - private int backupfilesPresetsComboLastSelected = 0; + protected JComboBox backupfilesPresetsCombo = new JComboBox<>(); protected JPanel suffixPanel = new JPanel(); @@ -380,11 +376,11 @@ public class GPreferences extends JPanel tabbedPane.add(initConnectionsTab(), MessageManager.getString("label.connections")); - if (!Platform.isJS()) - { - tabbedPane.add(initBackupsTab(), - MessageManager.getString("label.backups")); - } + if (!Platform.isJS()) + { + tabbedPane.add(initBackupsTab(), + MessageManager.getString("label.backups")); + } tabbedPane.add(initLinksTab(), MessageManager.getString("label.urllinks")); @@ -1287,6 +1283,7 @@ public class GPreferences extends JPanel structViewer.addItem(ViewerType.JMOL.name()); structViewer.addItem(ViewerType.CHIMERA.name()); structViewer.addActionListener(new ActionListener() + { @Override public void actionPerformed(ActionEvent e) @@ -1297,6 +1294,20 @@ public class GPreferences extends JPanel }); structureTab.add(structViewer); + // BH 2019.07.12 + ypos += lineSpacing; + JLabel dimLabel = new JLabel(); + dimLabel.setFont(new java.awt.Font("SansSerif", 0, 11)); + dimLabel.setHorizontalAlignment(SwingConstants.LEFT); + dimLabel.setText( + MessageManager.getString("label.structure_dimensions")); + dimLabel.setBounds(new Rectangle(10, ypos, 140, height)); + structureTab.add(dimLabel); + + structureDimensions.setFont(LABEL_FONT); + structureDimensions.setBounds(new Rectangle(160, ypos, 120, height)); + structureTab.add(structureDimensions); + ypos += lineSpacing; JLabel pathLabel = new JLabel(); pathLabel.setFont(new java.awt.Font("SansSerif", 0, 11)); @@ -1758,41 +1769,34 @@ public class GPreferences extends JPanel protected void loadLastSavedBackupsOptions() { - BackupFilesPresetEntry savedPreset = BackupFilesPresetEntry - .getSavedBackupEntry(); enableBackupFiles - .setSelected(Cache.getDefault(BackupFiles.ENABLED, - !Platform.isJS())); - - BackupFilesPresetEntry backupfilesCustomEntry = BackupFilesPresetEntry - .createBackupFilesPresetEntry(Cache - .getDefault(BackupFilesPresetEntry.CUSTOMCONFIG, null)); - if (backupfilesCustomEntry == null) - { - backupfilesCustomEntry = BackupFilesPresetEntry.backupfilesPresetEntriesValues - .get(BackupFilesPresetEntry.BACKUPFILESSCHEMEDEFAULT); - } - BackupFilesPresetEntry.backupfilesPresetEntriesValues.put( - BackupFilesPresetEntry.BACKUPFILESSCHEMECUSTOM, - backupfilesCustomEntry); - + .setSelected(Cache.getDefault(BackupFiles.ENABLED, !Platform.isJS())); setComboIntStringKey(backupfilesPresetsCombo, - Cache.getDefault(BackupFiles.NS + "_PRESET", - BackupFilesPresetEntry.BACKUPFILESSCHEMEDEFAULT)); - - backupsSetOptions(savedPreset); + Cache.getDefault(BackupFiles.NS + "_PRESET", 1)); + suffixTemplate.setText(Cache.getDefault(BackupFiles.SUFFIX, + ".bak" + BackupFiles.NUM_PLACEHOLDER)); + suffixDigitsSpinner + .setValue(Cache.getDefault(BackupFiles.SUFFIX_DIGITS, 3)); + suffixReverse.setSelected( + Cache.getDefault(BackupFiles.REVERSE_ORDER, false)); + backupfilesKeepAll + .setSelected(Cache.getDefault(BackupFiles.NO_MAX, false)); + backupfilesRollMaxSpinner + .setValue(Cache.getDefault(BackupFiles.ROLL_MAX, 3)); + backupfilesConfirmDelete.setSelected( + Cache.getDefault(BackupFiles.CONFIRM_DELETE_OLD, true)); backupsOptionsSetEnabled(); updateBackupFilesExampleLabel(); } - private boolean warnAboutSuffixReverseChange() + protected boolean warnAboutSuffixReverseChange() { - BackupFilesPresetEntry bfpe = BackupFilesPresetEntry - .getSavedBackupEntry(); - boolean savedSuffixReverse = bfpe.reverse; - int savedSuffixDigits = bfpe.digits; - String savedSuffixTemplate = bfpe.suffix; + boolean savedSuffixReverse = Cache.getDefault(BackupFiles.REVERSE_ORDER, + false); + int savedSuffixDigits = Cache.getDefault(BackupFiles.SUFFIX_DIGITS, 3); + String savedSuffixTemplate = Cache.getDefault(BackupFiles.SUFFIX, + ".bak" + BackupFiles.NUM_PLACEHOLDER); boolean nowSuffixReverse = suffixReverse.isSelected(); int nowSuffixDigits = getSpinnerInt(suffixDigitsSpinner, 3); @@ -1869,6 +1873,7 @@ public class GPreferences extends JPanel gbc.gridy++; // row 1 backupsTab.add(presetsPanel, gbc); + // gbc.anchor = GridBagConstraints.NORTHWEST; // now using whole row gbc.gridwidth = 2; gbc.gridheight = 1; @@ -1890,10 +1895,50 @@ public class GPreferences extends JPanel return backupsTab; } + protected static final int BACKUPFILESSCHEMECUSTOMISE = 0; + + private static final IntKeyStringValueEntry[] backupfilesPresetEntries = { + new IntKeyStringValueEntry(1, + MessageManager.getString("label.default")), + new IntKeyStringValueEntry(2, + MessageManager.getString("label.single_file")), + new IntKeyStringValueEntry(3, + MessageManager.getString("label.keep_all_versions")), + new IntKeyStringValueEntry(4, + MessageManager.getString("label.rolled_backups")), + // ... + // IMPORTANT, keep "Custom" entry with key 0 (even though it appears last) + new IntKeyStringValueEntry(BACKUPFILESSCHEMECUSTOMISE, + MessageManager.getString("label.customise")) }; + + private static final Map backupfilesPresetEntriesValues = new HashMap() + { + /** + * + */ + private static final long serialVersionUID = 125L; + + { + put(1, new BackupFilesPresetEntry( + ".bak" + BackupFiles.NUM_PLACEHOLDER, 3, false, false, 3, + false)); + put(2, new BackupFilesPresetEntry("~", 1, false, false, 1, false)); + put(3, new BackupFilesPresetEntry(".v" + BackupFiles.NUM_PLACEHOLDER, + 3, false, true, 10, true)); + put(4, new BackupFilesPresetEntry( + "_bak." + BackupFiles.NUM_PLACEHOLDER, 1, true, false, 9, + false)); + } + }; + private JPanel initBackupsTabPresetsPanel() { String title = MessageManager.getString("label.schemes"); + // TitledBorder tb = new TitledBorder(new EmptyBorder(0, 0, 0, 0), title); + // TitledBorder tb = new TitledBorder(title); + // tb.setTitleFont(LABEL_FONT); + // presetsPanel.setBorder(tb); presetsPanel.setLayout(new GridBagLayout()); @@ -1908,53 +1953,24 @@ public class GPreferences extends JPanel // "Scheme: " gbc.gridx = 0; gbc.gridy = 0; + presetsPanel.add(new JLabel(title + ":"), gbc); - presetsComboLabel = new JLabel(title + ":"); - presetsPanel.add(presetsComboLabel, gbc); - - List entries = Arrays - .asList((Object[]) BackupFilesPresetEntry.backupfilesPresetEntries); - List tooltips = Arrays.asList( - BackupFilesPresetEntry.backupfilesPresetEntryDescriptions); - backupfilesPresetsCombo = JvSwingUtils.buildComboWithTooltips(entries, - tooltips); - /* - for (int i = 0; i < BackupFilesPresetEntry.backupfilesPresetEntries.length; i++) + for (int i = 0; i < backupfilesPresetEntries.length; i++) { - backupfilesPresetsCombo - .addItem(BackupFilesPresetEntry.backupfilesPresetEntries[i]); + backupfilesPresetsCombo.addItem(backupfilesPresetEntries[i]); } - */ + // put "Previously saved scheme" item in italics (it's not really + // selectable, as such -- it deselects itself when selected) and + // "Customise" in bold + backupfilesPresetsCombo + .setRenderer(new BackupFilesPresetsComboBoxRenderer()); backupfilesPresetsCombo.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { - int key = getComboIntStringKey(backupfilesPresetsCombo); - if (!customiseCheckbox.isSelected()) - { - backupfilesPresetsComboLastSelected = key; - } - if (key == BackupFilesPresetEntry.BACKUPFILESSCHEMECUSTOM) - { - if (customiseCheckbox.isSelected()) - { - // got here by clicking on customiseCheckbox so don't change the values - backupfilesCustomOptionsSetEnabled(); - } - else - { - backupsTabUpdatePresets(); - backupfilesCustomOptionsSetEnabled(); - } - } - else - { - customiseCheckbox.setSelected(false); - backupsTabUpdatePresets(); - backupfilesCustomOptionsSetEnabled(); - } + backupsTabUpdatePresets(); } }); @@ -1963,55 +1979,20 @@ public class GPreferences extends JPanel presetsPanel.add(backupfilesPresetsCombo, gbc); revertButton.setText(MessageManager.getString("label.cancel_changes")); - revertButton.setToolTipText( - MessageManager.getString("label.cancel_changes_description")); revertButton.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { - backupsSetOptions( - BackupFilesPresetEntry.backupfilesPresetEntriesValues.get( - BackupFilesPresetEntry.BACKUPFILESSCHEMECUSTOM)); - backupfilesCustomOptionsSetEnabled(); + loadLastSavedBackupsOptions(); } }); revertButton.setFont(LABEL_FONT); - customiseCheckbox.setFont(LABEL_FONT); - customiseCheckbox.setText(MessageManager.getString("label.customise")); - customiseCheckbox.addActionListener(new ActionListener() - { - @Override - public void actionPerformed(ActionEvent e) - { - int currently = getComboIntStringKey(backupfilesPresetsCombo); - if (customiseCheckbox.isSelected()) - { - backupfilesPresetsComboLastSelected = currently; - setComboIntStringKey(backupfilesPresetsCombo, - BackupFilesPresetEntry.BACKUPFILESSCHEMECUSTOM); - } - else - { - setComboIntStringKey(backupfilesPresetsCombo, - backupfilesPresetsComboLastSelected); - - } - backupfilesCustomOptionsSetEnabled(); - } - }); - customiseCheckbox.setToolTipText( - MessageManager.getString("label.customise_description")); - - // customise checkbox - gbc.gridx = 0; - gbc.gridy++; - presetsPanel.add(customiseCheckbox, gbc); - // "Cancel changes" button (aligned with combo box above) gbc.gridx = 1; + gbc.gridy++; presetsPanel.add(revertButton, gbc); return presetsPanel; @@ -2020,7 +2001,7 @@ public class GPreferences extends JPanel private JPanel initBackupsTabFilenameExamplesPanel() { String title = MessageManager - .getString("label.scheme_examples"); + .getString("label.summary_of_backups_scheme"); TitledBorder tb = new TitledBorder(title); exampleFilesPanel.setBorder(tb); exampleFilesPanel.setLayout(new GridBagLayout()); @@ -2042,72 +2023,49 @@ public class GPreferences extends JPanel return exampleFilesPanel; } - private void backupsTabUpdatePresets() + protected void backupsTabUpdatePresets() { IntKeyStringValueEntry entry = (IntKeyStringValueEntry) backupfilesPresetsCombo .getSelectedItem(); - int key = entry.k; - String value = entry.v; + int key = entry.getKey(); + String value = entry.getValue(); - if (BackupFilesPresetEntry.backupfilesPresetEntriesValues - .containsKey(key)) + // BACKUPFILESSCHEMECUSTOMISE (==0) reserved for "Custom" + if (key != BACKUPFILESSCHEMECUSTOMISE) { - backupsSetOptions( - BackupFilesPresetEntry.backupfilesPresetEntriesValues - .get(key)); - } - else - { - Cache.log.error( - "Preset '" + value + "' [key:" + key + "] not implemented"); + if (backupfilesPresetEntriesValues.containsKey(key)) + { + backupsSetOptions(backupfilesPresetEntriesValues.get(key)); + } + else + { + System.out.println("Preset '" + value + "' not implemented"); + } } - // Custom options will now be enabled when the customiseCheckbox is checked - // (performed above) - // backupfilesCustomOptionsSetEnabled(); + backupfilesCustomOptionsSetEnabled(); updateBackupFilesExampleLabel(); } - protected int getComboIntStringKey( - JComboBox backupfilesPresetsCombo2) + protected int getComboIntStringKey(JComboBox c) { - IntKeyStringValueEntry e; - try - { - e = (IntKeyStringValueEntry) backupfilesPresetsCombo2 - .getSelectedItem(); - } catch (Exception ex) - { - Cache.log.error( - "Problem casting Combo entry to IntKeyStringValueEntry."); - e = null; - } - return e != null ? e.k : 0; + IntKeyStringValueEntry e = (IntKeyStringValueEntry) c.getSelectedItem(); + return e != null ? e.getKey() : 0; } - protected void setComboIntStringKey( - JComboBox backupfilesPresetsCombo2, + protected void setComboIntStringKey(JComboBox c, int key) { - for (int i = 0; i < backupfilesPresetsCombo2.getItemCount(); i++) + for (int i = 0; i < c.getItemCount(); i++) { - IntKeyStringValueEntry e; - try - { - e = (IntKeyStringValueEntry) backupfilesPresetsCombo2.getItemAt(i); - } catch (Exception ex) - { - Cache.log.error( - "Problem casting Combo entry to IntKeyStringValueEntry. Skipping item. "); - continue; - } - if (e.k == key) + IntKeyStringValueEntry e = c.getItemAt(i); + if (e.getKey() == key) { - backupfilesPresetsCombo2.setSelectedIndex(i); + c.setSelectedIndex(i); break; } } - // backupsTabUpdatePresets(); + backupsTabUpdatePresets(); } private JPanel initBackupsTabSuffixPanel() @@ -2131,18 +2089,16 @@ public class GPreferences extends JPanel { updateBackupFilesExampleLabel(); backupfilesCustomOptionsSetEnabled(); - backupfilesRevertButtonSetEnabled(true); } }); - suffixTemplate.addKeyListener(new KeyListener() + KeyListener kl = new KeyListener() { @Override public void keyReleased(KeyEvent e) { updateBackupFilesExampleLabel(); backupfilesCustomOptionsSetEnabled(); - backupfilesRevertButtonSetEnabled(true); } @Override @@ -2162,25 +2118,26 @@ public class GPreferences extends JPanel } } - }); + }; + suffixTemplate.addKeyListener(kl); // digits spinner suffixDigitsLabel .setText(MessageManager.getString("label.index_digits")); suffixDigitsLabel.setHorizontalAlignment(SwingConstants.LEFT); suffixDigitsLabel.setFont(LABEL_FONT); + int defaultmin = 1; + int defaultmax = 6; ChangeListener c = new ChangeListener() { @Override public void stateChanged(ChangeEvent e) { - backupfilesRevertButtonSetEnabled(true); updateBackupFilesExampleLabel(); } }; - setIntegerSpinner(suffixDigitsSpinner, BackupFilesPresetEntry.DIGITSMIN, - BackupFilesPresetEntry.DIGITSMAX, 3, c); + setIntegerSpinner(suffixDigitsSpinner, defaultmin, defaultmax, 3, c); suffixReverse.setLabels(MessageManager.getString("label.reverse_roll"), MessageManager.getString("label.increment_index")); @@ -2197,13 +2154,12 @@ public class GPreferences extends JPanel } if (okay) { - backupfilesRevertButtonSetEnabled(true); updateBackupFilesExampleLabel(); } else { - boolean savedSuffixReverse = BackupFilesPresetEntry - .getSavedBackupEntry().reverse; + boolean savedSuffixReverse = Cache + .getDefault(BackupFiles.REVERSE_ORDER, false); suffixReverse.setSelected(savedSuffixReverse); } } @@ -2250,12 +2206,12 @@ public class GPreferences extends JPanel return suffixPanel; } - private boolean confirmSuffixReverseChange() + protected boolean confirmSuffixReverseChange() { boolean ret = false; String warningMessage = MessageManager .getString("label.warning_confirm_change_reverse"); - int confirm = JvOptionPane.showConfirmDialog(Desktop.desktop, + int confirm = JvOptionPane.showConfirmDialog(Desktop.getDesktopPane(), warningMessage, MessageManager.getString("label.change_increment_decrement"), JvOptionPane.YES_NO_OPTION, JvOptionPane.WARNING_MESSAGE); @@ -2279,7 +2235,6 @@ public class GPreferences extends JPanel @Override public void actionPerformed(ActionEvent e) { - backupfilesRevertButtonSetEnabled(true); updateBackupFilesExampleLabel(); } }); @@ -2288,7 +2243,6 @@ public class GPreferences extends JPanel @Override public void actionPerformed(ActionEvent e) { - backupfilesRevertButtonSetEnabled(true); keepRollMaxOptionsEnabled(); updateBackupFilesExampleLabel(); } @@ -2299,26 +2253,15 @@ public class GPreferences extends JPanel @Override public void stateChanged(ChangeEvent e) { - backupfilesRevertButtonSetEnabled(true); updateBackupFilesExampleLabel(); } }; - setIntegerSpinner(backupfilesRollMaxSpinner, - BackupFilesPresetEntry.ROLLMAXMIN, - BackupFilesPresetEntry.ROLLMAXMAX, 4, true, c); + setIntegerSpinner(backupfilesRollMaxSpinner, 1, 999, 4, true, c); backupfilesConfirmDelete.setLabels( MessageManager.getString("label.always_ask"), MessageManager.getString("label.auto_delete")); - backupfilesConfirmDelete.addActionListener(new ActionListener() - { - @Override - public void actionPerformed(ActionEvent e) - { - backupfilesRevertButtonSetEnabled(true); - } - }); // update the enabled section keepRollMaxOptionsEnabled(); @@ -2354,6 +2297,13 @@ public class GPreferences extends JPanel kgbc.gridwidth = GridBagConstraints.REMAINDER; kgbc.fill = GridBagConstraints.HORIZONTAL; kgbc.weightx = 1.0; + /* + keepfilesPanel.add(backupfilesConfirmDelete.getTrueButton(), kgbc); + + // fourth row (indented) + kgbc.gridy = 3; + keepfilesPanel.add(backupfilesConfirmDelete.getFalseButton(), kgbc); + */ JPanel jp = new JPanel(); jp.setLayout(new FlowLayout()); @@ -2409,7 +2359,6 @@ public class GPreferences extends JPanel int uppersurround = 0; StringBuilder exampleSB = new StringBuilder(); boolean firstLine = true; - int lineNumber = 0; if (reverse) { @@ -2420,7 +2369,6 @@ public class GPreferences extends JPanel if (index == min + lowersurround && index < max - uppersurround - 1) { exampleSB.append("\n..."); - lineNumber++; } else if (index > min + lowersurround && index < max - uppersurround) { @@ -2435,7 +2383,6 @@ public class GPreferences extends JPanel else { exampleSB.append("\n"); - lineNumber++; } exampleSB.append(BackupFilenameParts.getBackupFilename(index, base, suffix, digits)); @@ -2475,7 +2422,6 @@ public class GPreferences extends JPanel if (index == min + lowersurround && index < max - uppersurround - 1) { exampleSB.append("\n..."); - lineNumber++; } else if (index > min + lowersurround && index < max - uppersurround) { @@ -2490,7 +2436,6 @@ public class GPreferences extends JPanel else { exampleSB.append("\n"); - lineNumber++; } exampleSB.append(BackupFilenameParts.getBackupFilename(index, base, suffix, digits)); @@ -2519,18 +2464,6 @@ public class GPreferences extends JPanel } - // add some extra empty lines to pad out the example files box. ugh, please tell - // me how to do this better - int remainingLines = lowersurround + uppersurround + 1 - lineNumber; - if (remainingLines > 0) - { - for (int i = 0; i < remainingLines; i++) - { - exampleSB.append("\n "); - lineNumber++; - } - } - backupfilesExampleLabel.setText(exampleSB.toString()); } @@ -2545,7 +2478,7 @@ public class GPreferences extends JPanel i = Integer.parseInt((String) s.getValue()); } catch (Exception e) { - Cache.log.error( + System.out.println( "Exception casting the initial value of s.getValue()"); } } @@ -2577,12 +2510,12 @@ public class GPreferences extends JPanel i = (Integer) s.getValue(); } catch (Exception e) { - Cache.log.error("Failed casting (Integer) JSpinner s.getValue()"); + System.out.println("Failed casting (Integer) JSpinner s.getValue()"); } return i; } - private void keepRollMaxOptionsEnabled() + protected void keepRollMaxOptionsEnabled() { boolean enabled = backupfilesKeepAll.isEnabled() && !backupfilesKeepAll.isSelected(); @@ -2591,10 +2524,10 @@ public class GPreferences extends JPanel backupfilesConfirmDelete.setEnabled(enabled); } - private void backupfilesKeepAllSetEnabled(boolean tryEnabled) + protected void backupfilesKeepAllSetEnabled(boolean tryEnabled) { boolean enabled = tryEnabled && enableBackupFiles.isSelected() - && customiseCheckbox.isSelected() + && getComboIntStringKey(backupfilesPresetsCombo) == 0 && suffixTemplate.getText() .indexOf(BackupFiles.NUM_PLACEHOLDER) > -1; keepfilesPanel.setEnabled(enabled); @@ -2615,48 +2548,18 @@ public class GPreferences extends JPanel private void backupfilesSuffixTemplateSetEnabled(boolean tryEnabled) { boolean enabled = tryEnabled && enableBackupFiles.isSelected() - && customiseCheckbox.isSelected(); + && getComboIntStringKey(backupfilesPresetsCombo) == 0; suffixPanel.setEnabled(enabled); suffixTemplateLabel.setEnabled(enabled); suffixTemplate.setEnabled(enabled); backupfilesSuffixTemplateDigitsSetEnabled(); } - private void backupfilesRevertButtonSetEnabled(boolean tryEnabled) - { - boolean enabled = tryEnabled && enableBackupFiles.isSelected() - && customiseCheckbox.isSelected() && backupfilesCustomChanged(); - revertButton.setEnabled(enabled); - } - - private boolean backupfilesCustomChanged() - { - BackupFilesPresetEntry custom = BackupFilesPresetEntry.backupfilesPresetEntriesValues - .get(BackupFilesPresetEntry.BACKUPFILESSCHEMECUSTOM); - BackupFilesPresetEntry current = getBackupfilesCurrentEntry(); - return !custom.equals(current); - } - - protected BackupFilesPresetEntry getBackupfilesCurrentEntry() - { - String suffix = suffixTemplate.getText(); - int digits = getSpinnerInt(suffixDigitsSpinner, 3); - boolean reverse = suffixReverse.isSelected(); - boolean keepAll = backupfilesKeepAll.isSelected(); - int rollMax = getSpinnerInt(backupfilesRollMaxSpinner, 3); - boolean confirmDelete = backupfilesConfirmDelete.isSelected(); - - BackupFilesPresetEntry bfpe = new BackupFilesPresetEntry(suffix, digits, - reverse, keepAll, rollMax, confirmDelete); - - return bfpe; - } - protected void backupfilesCustomOptionsSetEnabled() { - boolean enabled = customiseCheckbox.isSelected(); + int scheme = getComboIntStringKey(backupfilesPresetsCombo); + boolean enabled = scheme == 0 && enableBackupFiles.isSelected(); - backupfilesRevertButtonSetEnabled(enabled); backupfilesSuffixTemplateSetEnabled(enabled); backupfilesKeepAllSetEnabled(enabled); } @@ -2672,10 +2575,7 @@ public class GPreferences extends JPanel { boolean enabled = enableBackupFiles.isSelected(); presetsPanel.setEnabled(enabled); - presetsComboLabel.setEnabled(enabled); backupfilesPresetsCombo.setEnabled(enabled); - customiseCheckbox.setEnabled(enabled); - revertButton.setEnabled(enabled); } protected void backupsOptionsSetEnabled() @@ -2864,6 +2764,7 @@ public class GPreferences extends JPanel button.setHorizontalAlignment(SwingConstants.CENTER); this.button.addActionListener(new ActionListener() { + @SuppressWarnings("synthetic-access") @Override public void actionPerformed(ActionEvent e) { @@ -2889,3 +2790,85 @@ public class GPreferences extends JPanel } } +class IntKeyStringValueEntry +{ + int k; + + String v; + + public IntKeyStringValueEntry(int k, String v) + { + this.k = k; + this.v = v; + } + + @Override + public String toString() + { + return this.getValue(); + } + + public int getKey() + { + return k; + } + + public String getValue() + { + return v; + } +} + +class BackupFilesPresetEntry +{ + String suffix; + + int digits; + + boolean reverse; + + boolean keepAll; + + int rollMax; + + boolean confirmDelete; + + public BackupFilesPresetEntry(String suffix, int digits, boolean reverse, + boolean keepAll, int rollMax, boolean confirmDelete) + { + this.suffix = suffix; + this.digits = digits; + this.reverse = reverse; + this.keepAll = keepAll; + this.rollMax = rollMax; + this.confirmDelete = confirmDelete; + } +} + +class BackupFilesPresetsComboBoxRenderer extends DefaultListCellRenderer +{ + /** + * + */ + private static final long serialVersionUID = 88L; + + @Override + public Component getListCellRendererComponent(JList list, Object value, + int index, boolean isSelected, boolean cellHasFocus) + { + super.getListCellRendererComponent(list, value, index, isSelected, cellHasFocus); + + try { + IntKeyStringValueEntry e = (IntKeyStringValueEntry) value; + if (e.getKey() == GPreferences.BACKUPFILESSCHEMECUSTOMISE) + { + // "Customise" item + this.setFont(this.getFont().deriveFont(Font.BOLD)); + } + } catch (Exception e) { + return this; + } + + return this; + } +} diff --git a/src/jalview/jbgui/GRnaStructureViewer.java b/src/jalview/jbgui/GRnaStructureViewer.java index e0bec25..a90bd48 100644 --- a/src/jalview/jbgui/GRnaStructureViewer.java +++ b/src/jalview/jbgui/GRnaStructureViewer.java @@ -20,6 +20,8 @@ */ package jalview.jbgui; +import jalview.bin.Jalview; + import javax.swing.JInternalFrame; @SuppressWarnings("serial") @@ -38,9 +40,7 @@ public class GRnaStructureViewer extends JInternalFrame private void jbInit() throws Exception { - - setName("jalview-rnastructureviewer"); - + setName(Jalview.getAppID("rnastructureviewer")); } } diff --git a/src/jalview/jbgui/GSequenceLink.java b/src/jalview/jbgui/GSequenceLink.java index a43e504..2ec7051 100755 --- a/src/jalview/jbgui/GSequenceLink.java +++ b/src/jalview/jbgui/GSequenceLink.java @@ -219,7 +219,7 @@ public class GSequenceLink extends JPanel return true; } - JvOptionPane.showInternalMessageDialog(jalview.gui.Desktop.desktop, + JvOptionPane.showInternalMessageDialog(jalview.gui.Desktop.getDesktopPane(), MessageManager.getString("warn.url_must_contain"), MessageManager.getString("label.invalid_url"), JvOptionPane.WARNING_MESSAGE); @@ -228,7 +228,7 @@ public class GSequenceLink extends JPanel public void notifyDuplicate() { - JvOptionPane.showInternalMessageDialog(jalview.gui.Desktop.desktop, + JvOptionPane.showInternalMessageDialog(jalview.gui.Desktop.getDesktopPane(), MessageManager.getString("warn.name_cannot_be_duplicate"), MessageManager.getString("label.invalid_name"), JvOptionPane.WARNING_MESSAGE); diff --git a/src/jalview/jbgui/GSliderPanel.java b/src/jalview/jbgui/GSliderPanel.java index d841be5..452ba61 100755 --- a/src/jalview/jbgui/GSliderPanel.java +++ b/src/jalview/jbgui/GSliderPanel.java @@ -49,6 +49,7 @@ import javax.swing.SwingConstants; * @author $author$ * @version $Revision$ */ +@SuppressWarnings("serial") public class GSliderPanel extends JPanel { private static final Font VERDANA_11 = new java.awt.Font("Verdana", 0, 11); @@ -58,9 +59,9 @@ public class GSliderPanel extends JPanel protected static final int FRAME_HEIGHT = 120; // this is used for conservation colours, PID colours and redundancy threshold - protected JSlider slider = new JSlider(); + public JSlider slider = new JSlider(); - protected JTextField valueField = new JTextField(); + public JTextField valueField = new JTextField(); protected JLabel label = new JLabel(); diff --git a/src/jalview/jbgui/GSplitFrame.java b/src/jalview/jbgui/GSplitFrame.java index a75760d..ed715c8 100644 --- a/src/jalview/jbgui/GSplitFrame.java +++ b/src/jalview/jbgui/GSplitFrame.java @@ -20,6 +20,7 @@ */ package jalview.jbgui; +import jalview.bin.Jalview; import jalview.util.Platform; import java.awt.Component; @@ -57,7 +58,7 @@ public class GSplitFrame extends JInternalFrame */ public GSplitFrame(GAlignFrame top, GAlignFrame bottom) { - setName("jalview-splitframe"); + setName(Jalview.getAppID("splitframe")); this.topFrame = top; this.bottomFrame = bottom; diff --git a/src/jalview/jbgui/GStructureChooser.java b/src/jalview/jbgui/GStructureChooser.java index b9c9267..4261d67 100644 --- a/src/jalview/jbgui/GStructureChooser.java +++ b/src/jalview/jbgui/GStructureChooser.java @@ -106,13 +106,13 @@ public abstract class GStructureChooser extends JPanel protected String frameTitle = MessageManager .getString("label.structure_chooser"); - protected JInternalFrame mainFrame = new JInternalFrame(frameTitle); + public JInternalFrame mainFrame = new JInternalFrame(frameTitle); - protected JComboBox cmb_filterOption = new JComboBox<>(); + public JComboBox cmb_filterOption = new JComboBox<>(); - protected AlignmentPanel ap; + public AlignmentPanel ap; - protected StringBuilder errorWarning = new StringBuilder(); + public StringBuilder errorWarning = new StringBuilder(); protected JButton btn_add; @@ -123,14 +123,14 @@ public abstract class GStructureChooser extends JPanel protected JCheckBox chk_superpose = new JCheckBox( MessageManager.getString("label.superpose_structures")); - protected JTextField txt_search = new JTextField(14); + public JTextField txt_search = new JTextField(14); protected JPanel pnl_switchableViews = new JPanel(new CardLayout()); protected CardLayout layout_switchableViews = (CardLayout) (pnl_switchableViews .getLayout()); - protected JCheckBox chk_invertFilter = new JCheckBox( + public JCheckBox chk_invertFilter = new JCheckBox( MessageManager.getString("label.invert")); protected ImageIcon loadingImage = new ImageIcon( @@ -145,29 +145,29 @@ public abstract class GStructureChooser extends JPanel protected ImageIcon warningImage = new ImageIcon( getClass().getResource("/images/warning.gif")); - protected JLabel lbl_loading = new JLabel(loadingImage); + public JLabel lbl_loading = new JLabel(loadingImage); protected JLabel lbl_pdbManualFetchStatus = new JLabel(errorImage); protected JLabel lbl_fromFileStatus = new JLabel(errorImage); - protected AssociateSeqPanel idInputAssSeqPanel = new AssociateSeqPanel(); + public AssociateSeqPanel idInputAssSeqPanel = new AssociateSeqPanel(); - protected AssociateSeqPanel fileChooserAssSeqPanel = new AssociateSeqPanel(); + public AssociateSeqPanel fileChooserAssSeqPanel = new AssociateSeqPanel(); protected JComboBox targetView = new JComboBox<>(); - protected JTable tbl_local_pdb = new JTable(); + public JTable tbl_local_pdb = new JTable(); protected JTabbedPane pnl_filter = new JTabbedPane(); - protected FTSDataColumnPreferences pdbDocFieldPrefs = new FTSDataColumnPreferences( + public FTSDataColumnPreferences pdbDocFieldPrefs = new FTSDataColumnPreferences( PreferenceSource.STRUCTURE_CHOOSER, PDBFTSRestClient.getInstance()); protected FTSDataColumnI[] previousWantedFields; - protected static Map tempUserPrefs = new HashMap<>(); + public static Map tempUserPrefs = new HashMap<>(); private JTable tbl_summary = new JTable() { @@ -662,7 +662,7 @@ public abstract class GStructureChooser extends JPanel } -protected void closeAction(int preferredHeight) + public void closeAction(int preferredHeight) { // System.out.println(">>>>>>>>>> closing internal frame!!!"); // System.out.println("width : " + mainFrame.getWidth()); diff --git a/src/jalview/jbgui/GStructureViewer.java b/src/jalview/jbgui/GStructureViewer.java index dfee3e2..e16d63a 100644 --- a/src/jalview/jbgui/GStructureViewer.java +++ b/src/jalview/jbgui/GStructureViewer.java @@ -21,6 +21,7 @@ package jalview.jbgui; import jalview.api.structures.JalviewStructureDisplayI; +import jalview.bin.Jalview; import jalview.gui.ColourMenuHelper.ColourChangeListener; import jalview.util.ImageMaker.TYPE; import jalview.util.MessageManager; @@ -89,7 +90,7 @@ public abstract class GStructureViewer extends JInternalFrame private void jbInit() throws Exception { - setName("jalview-structureviewer"); + setName(Jalview.getAppID("structureviewer")); JMenuBar menuBar = new JMenuBar(); this.setJMenuBar(menuBar); diff --git a/src/jalview/jbgui/GTreePanel.java b/src/jalview/jbgui/GTreePanel.java index d184e76..0f9c2a2 100755 --- a/src/jalview/jbgui/GTreePanel.java +++ b/src/jalview/jbgui/GTreePanel.java @@ -20,6 +20,7 @@ */ package jalview.jbgui; +import jalview.bin.Jalview; import jalview.util.ImageMaker.TYPE; import jalview.util.MessageManager; @@ -92,7 +93,7 @@ public class GTreePanel extends JInternalFrame private void jbInit() throws Exception { - setName("jalview-tree"); + setName(Jalview.getAppID("tree")); this.getContentPane().setLayout(borderLayout1); this.setBackground(Color.white); this.setFont(new java.awt.Font("Verdana", 0, 12)); diff --git a/src/jalview/project/Jalview2XML.java b/src/jalview/project/Jalview2XML.java index 5618529..1a25270 100644 --- a/src/jalview/project/Jalview2XML.java +++ b/src/jalview/project/Jalview2XML.java @@ -28,6 +28,7 @@ import jalview.analysis.Conservation; import jalview.analysis.PCA; import jalview.analysis.scoremodels.ScoreModels; import jalview.analysis.scoremodels.SimilarityParams; +import jalview.api.AlignmentViewPanel; import jalview.api.FeatureColourI; import jalview.api.ViewStyleI; import jalview.api.analysis.ScoreModelI; @@ -82,7 +83,6 @@ import jalview.schemes.ColourSchemeProperty; import jalview.schemes.FeatureColour; import jalview.schemes.ResidueProperties; import jalview.schemes.UserColourScheme; -import jalview.structure.StructureSelectionManager; import jalview.structures.models.AAStructureBindingModel; import jalview.util.Format; import jalview.util.MessageManager; @@ -163,7 +163,6 @@ 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; @@ -624,13 +623,14 @@ public class Jalview2XML * core method for storing state for a set of AlignFrames. * * @param frames - * - frames involving all data to be exported (including containing - * splitframes) + * - frames involving all data to be exported (including those + * contained in splitframes, though not the split frames themselves) * @param jout * - project output stream */ private void saveAllFrames(List frames, JarOutputStream jout) { + Hashtable dsses = new Hashtable<>(); /* @@ -653,21 +653,22 @@ public class Jalview2XML for (int i = frames.size() - 1; i > -1; i--) { AlignFrame af = frames.get(i); + AlignViewport vp = af.getViewport(); // skip ? if (skipList != null && skipList - .containsKey(af.getViewport().getSequenceSetId())) + .containsKey(vp.getSequenceSetId())) { continue; } String shortName = makeFilename(af, shortNames); - int apSize = af.getAlignPanels().size(); - + AlignmentI alignment = vp.getAlignment(); + List panels = af.getAlignPanels(); + int apSize = panels.size(); for (int ap = 0; ap < apSize; ap++) - { - AlignmentPanel apanel = (AlignmentPanel) af.getAlignPanels() - .get(ap); + { + AlignmentPanel apanel = (AlignmentPanel) panels.get(ap); String fileName = apSize == 1 ? shortName : ap + shortName; if (!fileName.endsWith(".xml")) { @@ -675,11 +676,17 @@ public class Jalview2XML } saveState(apanel, fileName, jout, viewIds); - - String dssid = getDatasetIdRef( - af.getViewport().getAlignment().getDataset()); + } + if (apSize > 0) + { + // BH moved next bit out of inner loop, not that it really matters. + // so we are testing to make sure we actually have an alignment, + // apparently. + String dssid = getDatasetIdRef(alignment.getDataset()); if (!dsses.containsKey(dssid)) { + // We have not already covered this data by reference from another + // frame. dsses.put(dssid, af); } } @@ -797,10 +804,22 @@ public class Jalview2XML } } + /** + * Each AlignFrame has a single data set associated with it. Note that none of + * these frames are split frames, because Desktop.getAlignFrames() collects + * top and bottom separately here. + * + * @param dsses + * @param fileName + * @param jout + */ private void writeDatasetFor(Hashtable dsses, String fileName, JarOutputStream jout) { + // Note that in saveAllFrames we have associated each specific dataset to + // ONE of its associated frames. + for (String dssids : dsses.keySet()) { AlignFrame _af = dsses.get(dssids); @@ -1081,7 +1100,7 @@ public class Jalview2XML * only view *should* be coped with sensibly. */ // This must have been loaded, is it still visible? - JInternalFrame[] frames = Desktop.desktop.getAllFrames(); + JInternalFrame[] frames = Desktop.getDesktopPane().getAllFrames(); String matchedFile = null; for (int f = frames.length - 1; f > -1; f--) { @@ -1233,9 +1252,9 @@ public class Jalview2XML { // FIND ANY ASSOCIATED TREES // NOT IMPLEMENTED FOR HEADLESS STATE AT PRESENT - if (Desktop.desktop != null) + if (Desktop.getDesktopPane() != null) { - JInternalFrame[] frames = Desktop.desktop.getAllFrames(); + JInternalFrame[] frames = Desktop.getDesktopPane().getAllFrames(); for (int t = 0; t < frames.length; t++) { @@ -1279,9 +1298,9 @@ public class Jalview2XML /* * save PCA viewers */ - if (!storeDS && Desktop.desktop != null) + if (!storeDS && Desktop.getDesktopPane() != null) { - for (JInternalFrame frame : Desktop.desktop.getAllFrames()) + for (JInternalFrame frame : Desktop.getDesktopPane().getAllFrames()) { if (frame instanceof PCAPanel) { @@ -1672,7 +1691,7 @@ public class Jalview2XML // using save and then load try { - fileName = fileName.replace('\\', '/'); + fileName = fileName.replace('\\', '/'); System.out.println("Writing jar entry " + fileName); JarEntry entry = new JarEntry(fileName); jout.putNextEntry(entry); @@ -1919,11 +1938,11 @@ public class Jalview2XML final SequenceI jds, List viewIds, AlignmentPanel ap, boolean storeDataset) { - if (Desktop.desktop == null) + if (Desktop.getDesktopPane() == null) { return; } - JInternalFrame[] frames = Desktop.desktop.getAllFrames(); + JInternalFrame[] frames = Desktop.getDesktopPane().getAllFrames(); for (int f = frames.length - 1; f > -1; f--) { if (frames[f] instanceof AppVarna) @@ -2379,7 +2398,7 @@ public class Jalview2XML if (calcIdParam.getVersion().equals("1.0")) { final String[] calcIds = calcIdParam.getServiceURL().toArray(new String[0]); - Jws2Instance service = Jws2Discoverer.getDiscoverer() + Jws2Instance service = Jws2Discoverer.getInstance() .getPreferredServiceFor(calcIds); if (service != null) { @@ -2755,7 +2774,8 @@ public class Jalview2XML { try { - SwingUtilities.invokeAndWait(new Runnable() + // BH 2019 -- can't wait + SwingUtilities.invokeLater(new Runnable() { @Override public void run() @@ -2771,52 +2791,52 @@ public class Jalview2XML return af; } - @SuppressWarnings("unused") - private jarInputStreamProvider createjarInputStreamProvider(final Object ofile) throws MalformedURLException { + @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()); + // 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://")) { - url = new URL(file); - } - final URL _url = url; - return new jarInputStreamProvider() { - - @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; - } - } + URL url = null; + errorMessage = null; + uniqueSetSuffix = null; + seqRefIds = null; + viewportsAdded.clear(); + frefedSequence = null; + + if (file.startsWith("http://")) { + url = new URL(file); + } + final URL _url = url; + return new jarInputStreamProvider() { + + @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 @@ -2842,12 +2862,19 @@ public class Jalview2XML IdentityHashMap importedDatasets = new IdentityHashMap<>(); Map gatherToThisFrame = new HashMap<>(); final String file = jprovider.getFilename(); + + List alignFrames = new ArrayList<>(); + try { JarInputStream jin = null; JarEntry jarentry = null; int entryCount = 1; + + // Look for all the entry names ending with ".xml" + // This includes all panels and at least one frame. +// Platform.timeCheck(null, Platform.TIME_MARK); do { jin = jprovider.getJarInputStream(); @@ -2855,9 +2882,27 @@ public class Jalview2XML { jarentry = jin.getNextJarEntry(); } + String name = (jarentry == null ? null : jarentry.getName()); - if (jarentry != null && jarentry.getName().endsWith(".xml")) +// System.out.println("Jalview2XML opening " + name); + if (name != null && name.endsWith(".xml")) { + + // DataSet for.... is read last. + + + // The question here is what to do with the two + // .xml files in the jvp file. + // Some number of them, "...Dataset for...", will be the + // Only AlignPanels and will have Viewport. + // One or more will be the source data, with the DBRefs. + // + // JVP file writing (above) ensures tha the AlignPanels are written + // first, then all relevant datasets (which are + // Jalview.datamodel.Alignment). + // + +// Platform.timeCheck("Jalview2XML JAXB " + name, Platform.TIME_MARK); JAXBContext jc = JAXBContext .newInstance("jalview.xml.binding.jalview"); XMLStreamReader streamReader = XMLInputFactory.newInstance() @@ -2865,14 +2910,25 @@ public class Jalview2XML javax.xml.bind.Unmarshaller um = jc.createUnmarshaller(); JAXBElement jbe = um .unmarshal(streamReader, JalviewModel.class); - JalviewModel object = jbe.getValue(); + JalviewModel model = jbe.getValue(); if (true) // !skipViewport(object)) { - _af = loadFromObject(object, file, true, jprovider); - if (_af != null && object.getViewport().size() > 0) - // getJalviewModelSequence().getViewportCount() > 0) + // Q: Do we have to load from the model, even if it + // does not have a viewport, could we discover that early on? + // Q: Do we need to load this object? + _af = loadFromObject(model, file, true, jprovider); +// Platform.timeCheck("Jalview2XML.loadFromObject", + // Platform.TIME_MARK); + + if (_af != null) + { + alignFrames.add(_af); + } + if (_af != null && model.getViewport().size() > 0) { + + // That is, this is one of the AlignmentPanel models if (af == null) { // store a reference to the first view @@ -2892,6 +2948,7 @@ public class Jalview2XML af.getViewport().getAlignment().getDataset()); } } +// Platform.timeCheck("JAXB " + name, Platform.TIME_MARK); entryCount++; } else if (jarentry != null) @@ -2900,7 +2957,10 @@ public class Jalview2XML entryCount++; } } while (jarentry != null); +// Platform.timeCheck("JAXB loop exit", Platform.TIME_MARK); resolveFrefedSequences(); +// Platform.timeCheck("JAXB resolveFrefed", Platform.TIME_MARK); + } catch (IOException ex) { ex.printStackTrace(); @@ -2915,9 +2975,9 @@ public class Jalview2XML { // used to attempt to parse as V1 castor-generated xml } - if (Desktop.instance != null) + if (Desktop.getInstance() != null) { - Desktop.instance.stopLoading(); + Desktop.getInstance().stopLoading(); } if (af != null) { @@ -2934,6 +2994,13 @@ public class Jalview2XML errorMessage = "Out of memory loading jalview XML file"; System.err.println("Out of memory whilst loading jalview XML file"); e.printStackTrace(); + } finally + { + for (AlignFrame alf : alignFrames) + { + alf.alignPanel.setHoldRepaint(false); + } + } /* @@ -2945,7 +3012,7 @@ public class Jalview2XML */ for (AlignFrame fr : gatherToThisFrame.values()) { - Desktop.instance.gatherViews(fr); + Desktop.getInstance().gatherViews(fr); } restoreSplitFrames(); @@ -2953,8 +3020,7 @@ public class Jalview2XML { if (ds.getCodonFrames() != null) { - StructureSelectionManager - .getStructureSelectionManager(Desktop.instance) + Desktop.getStructureSelectionManager() .registerMappings(ds.getCodonFrames()); } } @@ -2963,9 +3029,9 @@ public class Jalview2XML reportErrors(); } - if (Desktop.instance != null) + if (Desktop.getInstance() != null) { - Desktop.instance.stopLoading(); + Desktop.getInstance().stopLoading(); } return af; @@ -3046,7 +3112,7 @@ public class Jalview2XML */ for (SplitFrame sf : gatherTo) { - Desktop.instance.gatherViews(sf); + Desktop.getInstance().gatherViews(sf); } splitFrameCandidates.clear(); @@ -3105,7 +3171,7 @@ public class Jalview2XML @Override public void run() { - JvOptionPane.showInternalMessageDialog(Desktop.desktop, + JvOptionPane.showInternalMessageDialog(Desktop.getDesktopPane(), finalErrorMessage, "Error " + (saving ? "saving" : "loading") + " Jalview file", @@ -3264,7 +3330,9 @@ public class Jalview2XML } /** - * Load alignment frame from jalview XML DOM object + * Load alignment frame from jalview XML DOM object. For a DOM object that + * includes one or more Viewport elements (one with a title that does NOT + * contain "Dataset for"), create the frame. * * @param jalviewModel * DOM @@ -3279,9 +3347,13 @@ public class Jalview2XML AlignFrame loadFromObject(JalviewModel jalviewModel, String file, boolean loadTreesAndStructures, jarInputStreamProvider jprovider) { + +// Platform.timeCheck("Jalview2XML.loadFromObject0", Platform.TIME_MARK); + SequenceSet vamsasSet = jalviewModel.getVamsasModel().getSequenceSet().get(0); List vamsasSeqs = vamsasSet.getSequence(); + // JalviewModelSequence jms = object.getJalviewModelSequence(); // Viewport view = (jms.getViewportCount() > 0) ? jms.getViewport(0) @@ -3312,6 +3384,7 @@ public class Jalview2XML : view.getId() + uniqueSetSuffix); } +// Platform.timeCheck("Jalview2XML.loadFromObject1", Platform.TIME_MARK); // //////////////////////////////// // LOAD SEQUENCES @@ -3332,6 +3405,7 @@ public class Jalview2XML SequenceI tmpSeq = seqRefIds.get(seqId); if (tmpSeq != null) { + // if (!incompleteSeqs.containsKey(seqId)) { // may not need this check, but keep it for at least 2.9,1 release @@ -3396,6 +3470,8 @@ public class Jalview2XML } } +// Platform.timeCheck("Jalview2XML.loadFromObject-seq", +// Platform.TIME_MARK); // / // Create the alignment object from the sequence set // /////////////////////////////// @@ -3436,6 +3512,8 @@ public class Jalview2XML recoverDatasetFor(vamsasSet, al, isdsal, uniqueSeqSetId); } +// Platform.timeCheck("Jalview2XML.loadFromObject-align", +// Platform.TIME_MARK); if (referenceseqForView != null) { al.setSeqrep(referenceseqForView); @@ -3448,6 +3526,8 @@ public class Jalview2XML al.setProperty(ssp.getKey(), ssp.getValue()); } +// Platform.timeCheck("Jalview2XML.loadFromObject-setseqprop", +// Platform.TIME_MARK); // /////////////////////////////// Hashtable pdbloaded = new Hashtable(); // TODO nothing writes to this?? @@ -3461,6 +3541,7 @@ public class Jalview2XML // now, for 2.10 projects, this is also done if the xml doc includes // dataset sequences not actually present in any particular view. // +// Platform.timeCheck("J2XML features0", Platform.TIME_RESET); for (int i = 0; i < vamsasSeqs.size(); i++) { JSeq jseq = jseqs.get(i); @@ -3515,7 +3596,9 @@ public class Jalview2XML } // adds feature to datasequence's feature set (since Jalview 2.10) +// Platform.timeCheck(null, Platform.TIME_SET); al.getSequenceAt(i).addSequenceFeature(sf); +// Platform.timeCheck(null, Platform.TIME_MARK); } } if (vamsasSeqs.get(i).getDBRef().size() > 0) @@ -3575,8 +3658,7 @@ public class Jalview2XML { entry.setProperty(prop.getName(), prop.getValue()); } - StructureSelectionManager - .getStructureSelectionManager(Desktop.instance) + Desktop.getStructureSelectionManager() .registerPDBEntry(entry); // adds PDBEntry to datasequence's set (since Jalview 2.10) if (al.getSequenceAt(i).getDatasetSequence() != null) @@ -3589,7 +3671,12 @@ public class Jalview2XML } } } + } + +// Platform.timeCheck("features done", Platform.TIME_GET); +// Platform.timeCheck("Jalview2XML.loadFromObject-endmultiview", +// Platform.TIME_MARK); } // end !multipleview // /////////////////////////////// @@ -3631,6 +3718,8 @@ public class Jalview2XML al.addCodonFrame(cf); } } +// Platform.timeCheck("Jalview2XML.loadFromObject-seqmap", +// Platform.TIME_MARK); } // //////////////////////////////// @@ -3691,6 +3780,9 @@ public class Jalview2XML } // Construct new annotation from model. List ae = annotation.getAnnotationElement(); +// System.err.println( +// "Jalview2XML processing " + ae.size() + " annotations"); + jalview.datamodel.Annotation[] anot = null; java.awt.Color firstColour = null; int anpos; @@ -3726,6 +3818,7 @@ public class Jalview2XML } } } + // create the new AlignmentAnnotation jalview.datamodel.AlignmentAnnotation jaa = null; if (annotation.isGraph()) @@ -3762,6 +3855,7 @@ public class Jalview2XML jaa._linecolour = firstColour; } // register new annotation + // Annotation graphs such as Conservation will not have id. if (annotation.getId() != null) { annotationIds.put(annotation.getId(), jaa); @@ -3850,6 +3944,8 @@ public class Jalview2XML al.addAnnotation(jaa); } } +// Platform.timeCheck("Jalview2XML.loadFromObject-annot", +// Platform.TIME_MARK); } // /////////////////////// // LOAD GROUPS @@ -3964,6 +4060,8 @@ public class Jalview2XML jGroup.getAnnotationColours(), null, al, jalviewModel, false)); } } +// Platform.timeCheck("Jalview2XML.loadFromObject-groups", +// Platform.TIME_MARK); } if (view == null) { @@ -3973,8 +4071,6 @@ public class Jalview2XML // /////////////////////////////// // LOAD VIEWPORT - AlignFrame af = null; - AlignViewport av = null; // now check to see if we really need to create a new viewport. if (multipleView && viewportsAdded.size() == 0) { @@ -4005,6 +4101,8 @@ public class Jalview2XML } } +// Platform.timeCheck("Jalview2XML.loadFromObject-viewport", +// Platform.TIME_MARK); } /** * indicate that annotation colours are applied across all groups (pre @@ -4013,8 +4111,9 @@ public class Jalview2XML boolean doGroupAnnColour = Jalview2XML.isVersionStringLaterThan("2.8.1", jalviewModel.getVersion()); + AlignFrame af = null; AlignmentPanel ap = null; - boolean isnewview = true; + AlignViewport av = null; if (viewId != null) { // Check to see if this alignment already has a view id == viewId @@ -4024,25 +4123,27 @@ public class Jalview2XML { for (int v = 0; v < views.length; v++) { - if (views[v].av.getViewId().equalsIgnoreCase(viewId)) + ap = views[v]; + av = ap.av; + if (av.getViewId().equalsIgnoreCase(viewId)) { // recover the existing alignpanel, alignframe, viewport - af = views[v].alignFrame; - av = views[v].av; - ap = views[v]; + af = ap.alignFrame; + break; // TODO: could even skip resetting view settings if we don't want to // change the local settings from other jalview processes - isnewview = false; } } } } - if (isnewview) + if (af == null) { af = loadViewport(file, jseqs, hiddenSeqs, al, jalviewModel, view, uniqueSeqSetId, viewId, autoAlan); av = af.getViewport(); + // note that this only retrieves the most recently accessed + // tab of an AlignFrame. ap = af.alignPanel; } @@ -4051,14 +4152,61 @@ public class Jalview2XML * * Not done if flag is false (when this method is used for New View) */ + final AlignFrame af0 = af; + final AlignViewport av0 = av; + final AlignmentPanel ap0 = ap; +// Platform.timeCheck("Jalview2XML.loadFromObject-beforetree", +// Platform.TIME_MARK); if (loadTreesAndStructures) { - loadTrees(jalviewModel, view, af, av, ap); - loadPCAViewers(jalviewModel, ap); - loadPDBStructures(jprovider, jseqs, af, ap); - loadRnaViewers(jprovider, jseqs, ap); + if (!jalviewModel.getTree().isEmpty()) + { + SwingUtilities.invokeLater(new Runnable() + { + @Override + public void run() + { +// Platform.timeCheck(null, Platform.TIME_MARK); + loadTrees(jalviewModel, view, af0, av0, ap0); +// Platform.timeCheck("Jalview2XML.loadTrees", Platform.TIME_MARK); + } + }); + } + if (!jalviewModel.getPcaViewer().isEmpty()) + { + SwingUtilities.invokeLater(new Runnable() + { + @Override + public void run() + { +// Platform.timeCheck(null, Platform.TIME_MARK); + loadPCAViewers(jalviewModel, ap0); +// Platform.timeCheck("Jalview2XML.loadPCA", Platform.TIME_MARK); + } + }); + } + SwingUtilities.invokeLater(new Runnable() + { + @Override + public void run() + { +// Platform.timeCheck(null, Platform.TIME_MARK); + loadPDBStructures(jprovider, jseqs, af0, ap0); +// Platform.timeCheck("Jalview2XML.loadPDB", Platform.TIME_MARK); + } + }); + SwingUtilities.invokeLater(new Runnable() + { + @Override + public void run() + { + loadRnaViewers(jprovider, jseqs, ap0); + } + }); } // and finally return. + // but do not set holdRepaint true just yet, because this could be the + // initial frame with just its dataset. return af; } @@ -4075,7 +4223,7 @@ public class Jalview2XML * @param jseqs * @param ap */ - private void loadRnaViewers(jarInputStreamProvider jprovider, + protected void loadRnaViewers(jarInputStreamProvider jprovider, List jseqs, AlignmentPanel ap) { /* @@ -4294,7 +4442,7 @@ public class Jalview2XML int height = safeInt(structureState.getHeight()); // Probably don't need to do this anymore... - // Desktop.desktop.getComponentAt(x, y); + // Desktop.getDesktop().getComponentAt(x, y); // TODO: NOW: check that this recovers the PDB file correctly. String pdbFile = loadPDBFile(jprovider, pdbid.getId(), pdbid.getFile()); @@ -4536,7 +4684,7 @@ public class Jalview2XML String reformatedOldFilename = oldfilenam.replaceAll("/", "\\\\"); filedat = oldFiles.get(new File(reformatedOldFilename)); } - newFileLoc.append(Platform.escapeBackslashes(filedat.getFilePath())); + newFileLoc.append(Platform.escapeString(filedat.getFilePath())); pdbfilenames.add(filedat.getFilePath()); pdbids.add(filedat.getPdbId()); seqmaps.add(filedat.getSeqList().toArray(new SequenceI[0])); @@ -4613,9 +4761,9 @@ public class Jalview2XML final AlignFrame alf = af; final Rectangle rect = new Rectangle(svattrib.getX(), svattrib.getY(), svattrib.getWidth(), svattrib.getHeight()); - try - { - javax.swing.SwingUtilities.invokeAndWait(new Runnable() + // try + // { + javax.swing.SwingUtilities.invokeLater(new Runnable() { @Override public void run() @@ -4642,14 +4790,14 @@ public class Jalview2XML } } }); - } catch (InvocationTargetException ex) - { - warn("Unexpected error when opening Jmol view.", ex); - - } catch (InterruptedException e) - { - // e.printStackTrace(); - } + // } catch (InvocationTargetException ex) + // { + // warn("Unexpected error when opening Jmol view.", ex); + // + // } catch (InterruptedException e) + // { + // // e.printStackTrace(); + // } } @@ -4778,7 +4926,7 @@ public class Jalview2XML { try { - frames = Desktop.desktop.getAllFrames(); + frames = Desktop.getDesktopPane().getAllFrames(); } catch (ArrayIndexOutOfBoundsException e) { // occasional No such child exceptions are thrown here... @@ -4855,19 +5003,19 @@ 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); -// -// } -// +// +// @Override +// protected void processKeyEvent(java.awt.event.KeyEvent e) { +// System.out.println("Jalview2XML AF " + e); +// super.processKeyEvent(e); +// +// } +// // } ; - + af.alignPanel.setHoldRepaint(true); af.setFileName(file, FileFormat.Jalview); final AlignViewport viewport = af.getViewport(); @@ -4976,8 +5124,18 @@ public class Jalview2XML viewport.setViewName(view.getViewName()); af.setInitialTabVisible(); } - af.setBounds(safeInt(view.getXpos()), safeInt(view.getYpos()), - safeInt(view.getWidth()), safeInt(view.getHeight())); + int x = safeInt(view.getXpos()); + int y = safeInt(view.getYpos()); + int w = safeInt(view.getWidth()); + int h = safeInt(view.getHeight()); + // // BH we cannot let the title bar go off the top + // if (Platform.isJS()) + // { + // x = Math.max(50 - w, x); + // y = Math.max(0, y); + // } + + af.setBounds(x, y, w, h); // startSeq set in af.alignPanel.updateLayout below af.alignPanel.updateLayout(); ColourSchemeI cs = null; @@ -5140,7 +5298,7 @@ public class Jalview2XML } else { - featureOrder.put(featureType, Float.valueOf( + featureOrder.put(featureType, new Float( fs / jm.getFeatureSettings().getSetting().size())); } if (safeBoolean(setting.isDisplay())) @@ -5152,7 +5310,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(), Boolean.valueOf(grp.isDisplay())); + fgtable.put(grp.getName(), new Boolean(grp.isDisplay())); } // FeatureRendererSettings frs = new FeatureRendererSettings(renderOrder, // fgtable, featureColours, jms.getFeatureSettings().hasTransparency() ? @@ -5545,8 +5703,8 @@ public class Jalview2XML SequenceI[] dsseqs = new SequenceI[dseqs.size()]; dseqs.copyInto(dsseqs); ds = new jalview.datamodel.Alignment(dsseqs); - debug("Created new dataset " + vamsasSet.getDatasetId() - + " for alignment " + System.identityHashCode(al)); +// debug("Jalview2XML Created new dataset " + vamsasSet.getDatasetId() +// + " for alignment " + System.identityHashCode(al)); addDatasetRef(vamsasSet.getDatasetId(), ds); } // set the dataset for the newly imported alignment. diff --git a/src/jalview/renderer/OverviewRenderer.java b/src/jalview/renderer/OverviewRenderer.java index c9096e2..36b5847 100644 --- a/src/jalview/renderer/OverviewRenderer.java +++ b/src/jalview/renderer/OverviewRenderer.java @@ -22,6 +22,7 @@ package jalview.renderer; import jalview.api.AlignmentColsCollectionI; import jalview.api.AlignmentRowsCollectionI; +import jalview.api.AlignmentViewPanel; import jalview.api.RendererListenerI; import jalview.datamodel.AlignmentAnnotation; import jalview.datamodel.AlignmentI; @@ -29,15 +30,23 @@ import jalview.datamodel.Annotation; import jalview.datamodel.SequenceGroup; import jalview.datamodel.SequenceI; import jalview.renderer.seqfeatures.FeatureColourFinder; -import jalview.renderer.seqfeatures.FeatureRenderer; +import jalview.util.Platform; import jalview.viewmodel.OverviewDimensions; import java.awt.AlphaComposite; import java.awt.Color; import java.awt.Graphics; import java.awt.Graphics2D; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; import java.awt.image.BufferedImage; +import java.awt.image.DataBufferInt; +import java.awt.image.WritableRaster; import java.beans.PropertyChangeSupport; +import java.util.BitSet; +import java.util.Iterator; + +import javax.swing.Timer; public class OverviewRenderer { @@ -56,9 +65,17 @@ public class OverviewRenderer // image to render on private BufferedImage miniMe; - // raw number of pixels to allocate to each column + /** + * Number of pixelsPerCol; + */ private float pixelsPerCol; + /** + * Number of visible columns per pixel. + * + */ + private float colsPerPixel; + // raw number of pixels to allocate to each row private float pixelsPerSeq; @@ -75,126 +92,331 @@ public class OverviewRenderer private OverviewResColourFinder resColFinder; - public OverviewRenderer(FeatureRenderer fr, OverviewDimensions od, - AlignmentI alignment, - ResidueShaderI resshader, OverviewResColourFinder colFinder) + private boolean showProgress; + + private AlignmentViewPanel panel; + + // private int sequencesHeight; + + public OverviewRenderer(AlignmentViewPanel panel, + jalview.api.FeatureRenderer fr, OverviewDimensions od, + AlignmentI alignment, ResidueShaderI resshader, + OverviewResColourFinder colFinder) { - finder = new FeatureColourFinder(fr); - resColFinder = colFinder; + this(panel, fr, od, alignment, resshader, colFinder, true); + } + /** + * @param panel + * @param fr + * @param od + * @param alignment + * @param resshader + * @param colFinder + * @param shwoProgress + * possibly not, in JavaScript and for testng + */ + public OverviewRenderer(AlignmentViewPanel panel, + jalview.api.FeatureRenderer fr, OverviewDimensions od, + AlignmentI alignment, ResidueShaderI resshader, + OverviewResColourFinder colFinder, boolean showProgress) + { + { + this.panel = panel; + finder = new FeatureColourFinder(fr); al = alignment; shader = resshader; + resColFinder = colFinder; + this.showProgress = showProgress; - pixelsPerCol = od.getPixelsPerCol(); - pixelsPerSeq = od.getPixelsPerSeq(); + w = od.getWidth(); + h = od.getHeight(); + rows = od.getRows(alignment); + cols = od.getColumns(alignment); graphHeight = od.getGraphHeight(); - miniMe = new BufferedImage(od.getWidth(), od.getHeight(), - BufferedImage.TYPE_INT_RGB); + alignmentHeight = od.getSequencesHeight(); + + pixelsPerSeq = od.getPixelsPerSeq(); + pixelsPerCol = od.getPixelsPerCol(); + colsPerPixel = Math.max(1, 1f / pixelsPerCol); + } } + final static int STATE_INIT = 0; + final static int STATE_NEXT = 1; + final static int STATE_DONE = 2; + + int state; + + boolean isJS = Platform.isJS(); + + Timer timer; + int delay = (isJS ? 1 : 0); + + int seqIndex; + + int pixelRow; + + private Integer row; + /** - * Draw alignment rows and columns onto an image + * Draw alignment rows and columns onto an image. This method is asynchronous + * in JavaScript and interruptible in Java. + * + * Whether hidden rows or columns are drawn depends upon the type of + * collection. * - * @param rit - * Iterator over rows to be drawn - * @param cit - * Iterator over columns to be drawn + * Updated to skip through high-density sequences, where columns/pixels > 1. + * + * When the process is complete, the image is passed to the AlignmentViewPanel + * provided by the constructor. + * + * @param rows + * collection of rows to be drawn + * @param cols + * collection of columns to be drawn * @return image containing the drawing + * + * @author Bob Hanson 2019.07.30 */ - public BufferedImage draw(AlignmentRowsCollectionI rows, - AlignmentColsCollectionI cols) + public void drawMiniMe() { - int rgbcolor = Color.white.getRGB(); - int seqIndex = 0; - int pixelRow = 0; - int alignmentHeight = miniMe.getHeight() - graphHeight; - int totalPixels = miniMe.getWidth() * alignmentHeight; + state = STATE_INIT; + mainLoop(); + } - int lastRowUpdate = 0; - int lastUpdate = 0; - changeSupport.firePropertyChange(UPDATE, -1, 0); + protected void mainLoop() + { + out: while (!redraw) + { + switch (state) + { + case STATE_INIT: + init(); + state = STATE_NEXT; + continue; + case STATE_NEXT: + if (!rowIterator.hasNext()) + { + state = STATE_DONE; + continue; + } + nextRow(); + if (!loop()) + { + // Java + continue; + } + // JavaScript + return; + case STATE_DONE: + break out; + } + // Java will continue without a timeout + } + done(); + } - for (int alignmentRow : rows) + private void init() + { + rowIterator = rows.iterator(); + seqIndex = 0; + pixelRow = 0; + lastRowUpdate = 0; + lastUpdate = 0; + totalPixels = w * alignmentHeight; + + if (showProgress) + { + changeSupport.firePropertyChange(UPDATE, -1, 0); + } + + miniMe = new BufferedImage(w, h, BufferedImage.TYPE_INT_RGB); + WritableRaster raster = miniMe.getRaster(); + DataBufferInt db = (DataBufferInt) raster.getDataBuffer(); + pixels = db.getBankData()[0]; + bscol = cols.getOverviewBitSet(); + Platform.timeCheck(null, Platform.TIME_MARK); + } + + private void nextRow() + { + row = rowIterator.next(); + // get details of this alignment row + SequenceI seq = rows.getSequence(row); + + // rate limiting step when rendering overview for lots of groups + SequenceGroup[] allGroups = al.findAllGroups(seq); + + // calculate where this row extends to in pixels + int endRow = Math.min(Math.round((++seqIndex) * pixelsPerSeq), h); + for (int pixelCol = 0, colNext = 0, pixelEnd = 0, icol = bscol + .nextSetBit(0); icol >= 0; icol = getNextCol(icol, pixelEnd)) { if (redraw) { break; } - - // get details of this alignment row - SequenceI seq = rows.getSequence(alignmentRow); - - // rate limiting step when rendering overview for lots of groups - SequenceGroup[] allGroups = al.findAllGroups(seq); - - // calculate where this row extends to in pixels - int endRow = Math.min(Math.round((seqIndex + 1) * pixelsPerSeq) - 1, - miniMe.getHeight() - 1); - - int colIndex = 0; - int pixelCol = 0; - for (int alignmentCol : cols) + + ++colNext; + pixelEnd = getNextPixel(colNext, colNext); + + if (pixelCol == pixelEnd) { - if (redraw) - { - break; - } - - // calculate where this column extends to in pixels - int endCol = Math.min(Math.round((colIndex + 1) * pixelsPerCol) - 1, - miniMe.getWidth() - 1); - - // don't do expensive colour determination if we're not going to use it - // NB this is important to avoid performance issues in the overview - // panel - if (pixelCol <= endCol) + break; + } + else if (pixelCol < pixelEnd) + { + int rgb = getColumnColourFromSequence(allGroups, seq, icol); + // fill in the appropriate number of pixels + // System.out.println( + // "OR colNext=" + colNext + " " + pixelCol + // + "-" + pixelEnd + " icol=" + icol + " " + rgb + " " + // + pixelsPerCol); + for (int row = pixelRow; row < endRow; ++row) { - rgbcolor = getColumnColourFromSequence(allGroups, seq, - alignmentCol); - - // fill in the appropriate number of pixels - for (int row = pixelRow; row <= endRow; ++row) + for (int col = pixelCol; col < pixelEnd; ++col) { - for (int col = pixelCol; col <= endCol; ++col) - { - miniMe.setRGB(col, row, rgbcolor); - } + // BH 2019.07.27 was: + // + // miniMe.setRGB(col, row, rgbcolor); + // + // but just directly writing to the int[] pixel buffer + // is three times faster by my experimentation + pixels[row * w + col] = rgb; + ndone++; } - - // store last update value + } + pixelCol = pixelEnd; + // store last update value + if (showProgress) + { lastUpdate = sendProgressUpdate( - (pixelCol + 1) * (endRow - pixelRow), totalPixels, - lastRowUpdate, lastUpdate); - - pixelCol = endCol + 1; + pixelEnd * (endRow - 1 - pixelRow), + totalPixels, lastRowUpdate, lastUpdate); } - colIndex++; } - if (pixelRow != endRow + 1) + } + if (pixelRow < endRow) + { + pixelRow = endRow; + // store row offset and last update value + if (showProgress) { - // store row offset and last update value - lastRowUpdate = sendProgressUpdate(endRow + 1, alignmentHeight, 0, + // BH 2019.07.29 was (old) endRow + 1 (now endRow), but should be + // pixelRow + 1, surely + lastRowUpdate = sendProgressUpdate(endRow, alignmentHeight, 0, lastUpdate); lastUpdate = lastRowUpdate; - pixelRow = endRow + 1; } - seqIndex++; } + } - overlayHiddenRegions(rows, cols); - // final update to progress bar if present - if (redraw) + /** + * The next column is either the next set bit (when there are multiple pixels + * per column) or the next set bit for the column that aligns with the next + * pixel (when there are more columns than pixels). + * + * @param icol + * @param pixel + * @return + */ + private int getNextCol(int icol, int pixel) + { + return bscol.nextSetBit( + pixelsPerCol >= 1 ? icol + 1 : (int) (pixel * colsPerPixel)); + } + + private int getNextPixel(int icol, int pixel) + { + return Math.min( + pixelsPerCol >= 1 || pixel == 0 + ? Math.round(icol * pixelsPerCol) + : pixel, + w); + } + + private ActionListener listener = new ActionListener() + { + @Override + public void actionPerformed(ActionEvent e) { - sendProgressUpdate(pixelRow - 1, alignmentHeight, 0, 0); + mainLoop(); + } + + }; + + private boolean loop() + { + if (delay <= 0) + { + return false; + } + if (timer == null) + { + timer = new Timer(delay, listener); + timer.setRepeats(false); + timer.start(); } else { - sendProgressUpdate(alignmentHeight, miniMe.getHeight(), 0, 0); + timer.restart(); } - return miniMe; + return true; } + private void done() + { + if (!redraw) + { + Platform.timeCheck( + "overviewrender " + ndone + " pixels row:" + row + " redraw:" + + redraw, + Platform.TIME_MARK); + } + + overlayHiddenRegions(); + if (showProgress) + { + // final update to progress bar if present + if (redraw) + { + // aborted in Java + // BH was pixelRow - 1, but that could go negative + sendProgressUpdate(pixelRow, alignmentHeight, 0, 0); + } + else + { + // sendProgressUpdate(alignmentHeight, miniMe.getHeight(), 0, 0); + sendProgressUpdate(1, 1, 0, 0); + } + } + panel.overviewDone(miniMe); + } + + int ndone = 0; + + private AlignmentRowsCollectionI rows; + + private AlignmentColsCollectionI cols; + + Iterator rowIterator; + + int alignmentHeight; + + int totalPixels; + + int lastRowUpdate; + + int lastUpdate; + + int[] pixels; + + BitSet bscol; + + int w, h; + /* * Calculate progress update value and fire event * @param rowOffset number of rows to offset calculation by @@ -222,40 +444,30 @@ public class OverviewRenderer * column position to get colour for * @return colour of sequence at this position, as RGB */ - int getColumnColourFromSequence(SequenceGroup[] allGroups, - SequenceI seq, int lastcol) + int getColumnColourFromSequence(SequenceGroup[] allGroups, SequenceI seq, + int icol) { - Color color = resColFinder.GAP_COLOUR; - - if ((seq != null) && (seq.getLength() > lastcol)) - { - color = resColFinder.getResidueColour(true, shader, allGroups, seq, - lastcol, finder); - } - - return color.getRGB(); + return (seq == null || icol >= seq.getLength() + ? resColFinder.GAP_COLOUR + : resColFinder.getResidueColourInt(true, shader, allGroups, seq, + icol, finder)); } /** * Overlay the hidden regions on the overview image * - * @param rows - * collection of rows the overview is built over - * @param cols - * collection of columns the overview is built over */ - private void overlayHiddenRegions(AlignmentRowsCollectionI rows, - AlignmentColsCollectionI cols) + private void overlayHiddenRegions() { if (cols.hasHidden() || rows.hasHidden()) { - BufferedImage mask = buildHiddenImage(rows, cols, miniMe.getWidth(), - miniMe.getHeight()); + BufferedImage mask = buildHiddenImage(); Graphics2D g = (Graphics2D) miniMe.getGraphics(); g.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER, TRANSPARENCY)); g.drawImage(mask, 0, 0, miniMe.getWidth(), miniMe.getHeight(), null); + g.dispose(); } } @@ -273,20 +485,17 @@ public class OverviewRenderer * height of overview in pixels * @return BufferedImage containing mask of hidden regions */ - private BufferedImage buildHiddenImage(AlignmentRowsCollectionI rows, - AlignmentColsCollectionI cols, int width, int height) + private BufferedImage buildHiddenImage() { // new masking image - BufferedImage hiddenImage = new BufferedImage(width, height, + BufferedImage hiddenImage = new BufferedImage(w, h, BufferedImage.TYPE_INT_ARGB); - int colIndex = 0; - int pixelCol = 0; - Color hidden = resColFinder.getHiddenColour(); Graphics2D g2d = (Graphics2D) hiddenImage.getGraphics(); + g2d.setColor(hidden); // set background to transparent // g2d.setComposite(AlphaComposite.Clear); // g2d.fillRect(0, 0, width, height); @@ -294,124 +503,109 @@ public class OverviewRenderer // set next colour to opaque g2d.setComposite(AlphaComposite.Src); - for (int alignmentCol : cols) + // System.out.println(cols.getClass().getName()); + if (cols.hasHidden()) { - if (redraw) - { - break; - } - - // calculate where this column extends to in pixels - int endCol = Math.min(Math.round((colIndex + 1) * pixelsPerCol) - 1, - hiddenImage.getWidth() - 1); - - if (pixelCol <= endCol) + // AllColsCollection only + BitSet bs = cols.getHiddenBitSet(); + for (int pixelCol = -1, icol2 = 0, icol = bs + .nextSetBit(0); icol >= 0; icol = bs.nextSetBit(icol2)) { - // determine the colour based on the sequence and column position - if (cols.isHidden(alignmentCol)) + if (redraw) { - g2d.setColor(hidden); - g2d.fillRect(pixelCol, 0, endCol - pixelCol + 1, height); + break; + } + icol2 = bs.nextClearBit(icol + 1); + int pixelEnd = getNextPixel(icol2, 0); + if (pixelEnd > pixelCol) + { + pixelCol = getNextPixel(icol, 0); + g2d.fillRect(pixelCol, 0, Math.max(1, pixelEnd - pixelCol), + h); + pixelCol = pixelEnd; } - - pixelCol = endCol + 1; } - colIndex++; - } - - int seqIndex = 0; - int pixelRow = 0; - for (int alignmentRow : rows) + if (rows.hasHidden()) { - if (redraw) + int seqIndex = 0; + int pixelRow = 0; + for (int alignmentRow : rows) { - break; - } + if (redraw) + { + break; + } - // calculate where this row extends to in pixels - int endRow = Math.min(Math.round((seqIndex + 1) * pixelsPerSeq) - 1, - miniMe.getHeight() - 1); + // calculate where this row extends to in pixels + int endRow = Math.min(Math.round((++seqIndex) * pixelsPerSeq), + h); - // get details of this alignment row - if (rows.isHidden(alignmentRow)) - { - g2d.setColor(hidden); - g2d.fillRect(0, pixelRow, width, endRow - pixelRow + 1); + // get details of this alignment row + if (rows.isHidden(alignmentRow)) + { + g2d.fillRect(0, pixelRow, w, endRow - 1 - pixelRow); + } + pixelRow = endRow; } - pixelRow = endRow + 1; - seqIndex++; } - + g2d.dispose(); return hiddenImage; } /** * Draw the alignment annotation in the overview panel * - * @param g - * the graphics object to draw on * @param anno * alignment annotation information - * @param y - * y-position for the annotation graph - * @param cols - * the collection of columns used in the overview panel */ - public void drawGraph(Graphics g, AlignmentAnnotation anno, int y, - AlignmentColsCollectionI cols) + public void drawGraph(AlignmentAnnotation anno) { + int y = graphHeight; + Graphics g = miniMe.getGraphics(); + g.translate(0, alignmentHeight); + Annotation[] annotations = anno.annotations; + float max = anno.graphMax; g.setColor(Color.white); - g.fillRect(0, 0, miniMe.getWidth(), y); + g.fillRect(0, 0, w, y); - int height; - int colIndex = 0; - int pixelCol = 0; - for (int alignmentCol : cols) + for (int pixelCol = 0, colNext = 0, pixelEnd = 0, len = annotations.length, icol = bscol + .nextSetBit(0); icol >= 0 + && icol < len; icol = getNextCol(icol, pixelEnd)) { if (redraw) { - changeSupport.firePropertyChange(UPDATE, MAX_PROGRESS - 1, 0); + if (showProgress) + { + changeSupport.firePropertyChange(UPDATE, MAX_PROGRESS - 1, 0); + } break; } - if (alignmentCol >= annotations.length) + ++colNext; + pixelEnd = getNextPixel(colNext, colNext); + Annotation ann = annotations[icol]; + if (ann != null) { - break; // no more annotations to draw here + Color color = ann.colour; + g.setColor(color == null ? Color.black : color); + int height = Math.min(y, (int) ((ann.value / max) * y)); + g.fillRect(pixelCol, y - height, Math.max(1, pixelEnd - pixelCol), + height); } - else - { - int endCol = Math.min(Math.round((colIndex + 1) * pixelsPerCol) - 1, - miniMe.getWidth() - 1); - - if (annotations[alignmentCol] != null) - { - if (annotations[alignmentCol].colour == null) - { - g.setColor(Color.black); - } - else - { - g.setColor(annotations[alignmentCol].colour); - } - - height = (int) ((annotations[alignmentCol].value / anno.graphMax) - * y); - if (height > y) - { - height = y; - } + pixelCol = pixelEnd; + } - g.fillRect(pixelCol, y - height, endCol - pixelCol + 1, height); - } + g.translate(0, -alignmentHeight); + g.dispose(); - pixelCol = endCol + 1; - colIndex++; - } + if (showProgress) + { + changeSupport.firePropertyChange(UPDATE, MAX_PROGRESS - 1, + MAX_PROGRESS); } - changeSupport.firePropertyChange(UPDATE, MAX_PROGRESS - 1, - MAX_PROGRESS); + } /** diff --git a/src/jalview/renderer/OverviewResColourFinder.java b/src/jalview/renderer/OverviewResColourFinder.java index a497d92..a98f3b3 100644 --- a/src/jalview/renderer/OverviewResColourFinder.java +++ b/src/jalview/renderer/OverviewResColourFinder.java @@ -22,15 +22,16 @@ package jalview.renderer; import jalview.datamodel.SequenceGroup; import jalview.datamodel.SequenceI; +import jalview.renderer.seqfeatures.FeatureColourFinder; import jalview.util.Comparison; import java.awt.Color; public class OverviewResColourFinder extends ResidueColourFinder { - final Color GAP_COLOUR; // default colour to use at gaps + final int GAP_COLOUR; // default colour to use at gaps - final Color RESIDUE_COLOUR; // default colour to use at residues + final int RESIDUE_COLOUR; // default colour to use at residues final Color HIDDEN_COLOUR; // colour for hidden regions @@ -66,69 +67,99 @@ public class OverviewResColourFinder extends ResidueColourFinder { if (useLegacyColouring) { - GAP_COLOUR = Color.white; - RESIDUE_COLOUR = Color.lightGray; - HIDDEN_COLOUR = hiddenCol; + GAP_COLOUR = Color.white.getRGB(); + RESIDUE_COLOUR = Color.lightGray.getRGB(); } else { - GAP_COLOUR = gapCol; - RESIDUE_COLOUR = Color.white; - HIDDEN_COLOUR = hiddenCol; + GAP_COLOUR = gapCol.getRGB(); + RESIDUE_COLOUR = Color.white.getRGB(); } + HIDDEN_COLOUR = hiddenCol; } @Override + /** + * for Test suite only. + */ public Color getBoxColour(ResidueShaderI shader, SequenceI seq, int i) { - Color resBoxColour = RESIDUE_COLOUR; - char currentChar = seq.getCharAt(i); + return new Color(getBoxColourInt(shader, seq, i)); + } + public int getBoxColourInt(ResidueShaderI shader, SequenceI seq, int i) + { + char currentChar = seq.getCharAt(i); // In the overview window, gaps are coloured grey, unless the colour scheme // specifies a gap colour, in which case gaps honour the colour scheme // settings - if (shader.getColourScheme() != null) + boolean isGap = Comparison.isGap(currentChar); + if (shader.getColourScheme() == null) { - if (Comparison.isGap(currentChar) - && (!shader.getColourScheme().hasGapColour())) - { - resBoxColour = GAP_COLOUR; - } - else - { - resBoxColour = shader.findColour(currentChar, i, seq); - } + return (isGap ? GAP_COLOUR : RESIDUE_COLOUR); } - else if (Comparison.isGap(currentChar)) + return (isGap && !shader.getColourScheme().hasGapColour() ? GAP_COLOUR + : shader.findColourInt(currentChar, i, seq)); + } + + /** + * For test suite only. + */ + @Override + public Color getResidueColour(boolean showBoxes, ResidueShaderI shader, + SequenceGroup[] allGroups, final SequenceI seq, int i, + FeatureColourFinder finder) + { + return new Color(getResidueColourInt(showBoxes, shader, allGroups, seq, + i, finder)); + } + + + public int getResidueColourInt(boolean showBoxes, ResidueShaderI shader, + SequenceGroup[] allGroups, final SequenceI seq, int i, + FeatureColourFinder finder) + { + + int c = seq.getColor(i); + if (c != 0) { - resBoxColour = GAP_COLOUR; + return c; } - return resBoxColour; + int col = getResidueBoxColourInt(showBoxes, shader, allGroups, seq, i); + + // if there's a FeatureColourFinder we might override the residue colour + // here with feature colouring + return seq.setColor(i, + finder == null || finder.noFeaturesDisplayed() ? col + : finder.findFeatureColourInt(col, seq, i)); } /** - * {@inheritDoc} In the overview, the showBoxes setting is ignored, as the - * overview displays the colours regardless. + * For test suite only. */ @Override protected Color getResidueBoxColour(boolean showBoxes, - ResidueShaderI shader, - SequenceGroup[] allGroups, SequenceI seq, int i) + ResidueShaderI shader, SequenceGroup[] allGroups, SequenceI seq, + int i) + { + return new Color( + getResidueBoxColourInt(showBoxes, shader, allGroups, seq, i)); + } + + /** + * In the overview, the showBoxes setting is ignored, as the overview displays + * the colours regardless. + */ + protected int getResidueBoxColourInt(boolean showBoxes, + ResidueShaderI shader, SequenceGroup[] allGroups, SequenceI seq, + int i) { - ResidueShaderI currentShader; SequenceGroup currentSequenceGroup = getCurrentSequenceGroup(allGroups, i); - if (currentSequenceGroup != null) - { - currentShader = currentSequenceGroup.getGroupColourScheme(); - } - else - { - currentShader = shader; - } - - return getBoxColour(currentShader, seq, i); + ResidueShaderI currentShader = (currentSequenceGroup == null ? shader + : currentSequenceGroup.getGroupColourScheme()); + return getBoxColourInt(currentShader, seq, i); } /** diff --git a/src/jalview/renderer/ResidueColourFinder.java b/src/jalview/renderer/ResidueColourFinder.java index 2da7233..2e45117 100644 --- a/src/jalview/renderer/ResidueColourFinder.java +++ b/src/jalview/renderer/ResidueColourFinder.java @@ -116,12 +116,13 @@ public class ResidueColourFinder public SequenceGroup getCurrentSequenceGroup(SequenceGroup[] allGroups, int res) { - if (allGroups == null) + int n; + if (allGroups == null || (n = allGroups.length) == 0) { return null; } - for (int i = 0; i < allGroups.length; i++) + for (int i = 0; i < n; i++) { if ((allGroups[i].getStartRes() <= res) && (allGroups[i].getEndRes() >= res)) diff --git a/src/jalview/renderer/ResidueShader.java b/src/jalview/renderer/ResidueShader.java index c031170..73a5efd 100644 --- a/src/jalview/renderer/ResidueShader.java +++ b/src/jalview/renderer/ResidueShader.java @@ -262,6 +262,36 @@ public class ResidueShader implements ResidueShaderI return colour; } + @Override + public int findColourInt(char symbol, int position, SequenceI seq) + { + if (colourScheme == null) + { + return -1;// Color.white; // Colour is 'None' + } + + /* + * get 'base' colour + */ + ProfileI profile = consensus == null ? null : consensus.get(position); + String modalResidue = profile == null ? null + : profile.getModalResidue(); + float pid = profile == null ? 0f + : profile.getPercentageIdentity(ignoreGaps); + int colour = colourScheme + .findColour(symbol, position, seq, modalResidue, pid).getRGB(); + + /* + * apply PID threshold and consensus fading if in force + */ + if (!Comparison.isGap(symbol)) + { + colour = adjustColourInt(symbol, position, colour); + } + + return colour; + } + /** * Adjusts colour by applying thresholding or conservation shading, if in * force. That is @@ -293,6 +323,20 @@ public class ResidueShader implements ResidueShaderI return colour; } + protected int adjustColourInt(char symbol, int column, int colour) + { + if (!aboveThreshold(symbol, column)) + { + colour = -1;// Color.white; + } + + if (conservationColouring) + { + colour = applyConservationInt(colour, column); + } + return colour; + } + /** * Answers true if there is a consensus profile for the specified column, and * the given residue matches the consensus (or joint consensus) residue for @@ -398,6 +442,45 @@ public class ResidueShader implements ResidueShaderI return ColorUtils.bleachColour(currentColour, bleachFactor); } + protected int applyConservationInt(int currentColour, int column) + { + if (conservation == null || conservation.length <= column) + { + return currentColour; + } + char conservationScore = conservation[column]; + + /* + * if residues are fully conserved (* or 11), or all properties + * are conserved (+ or 10), leave colour unchanged + */ + if (conservationScore == '*' || conservationScore == '+' + || conservationScore == (char) 10 + || conservationScore == (char) 11) + { + return currentColour; + } + + if (Comparison.isGap(conservationScore)) + { + return -1;// Color.white; + } + + /* + * convert score 0-9 to a bleaching factor 1.1 - 0.2 + */ + float bleachFactor = (11 - (conservationScore - '0')) / 10f; + + /* + * scale this up by 0-5 (percentage slider / 20) + * as a result, scores of: 0 1 2 3 4 5 6 7 8 9 + * fade to white at slider value: 18 20 22 25 29 33 40 50 67 100% + */ + bleachFactor *= (conservationIncrement / 20f); + + return ColorUtils.bleachColourInt(currentColour, bleachFactor); + } + /** * @see jalview.renderer.ResidueShaderI#getColourScheme() */ diff --git a/src/jalview/renderer/ResidueShaderI.java b/src/jalview/renderer/ResidueShaderI.java index 4d97171..2f14a5d 100644 --- a/src/jalview/renderer/ResidueShaderI.java +++ b/src/jalview/renderer/ResidueShaderI.java @@ -82,4 +82,6 @@ public interface ResidueShaderI public abstract void setColourScheme(ColourSchemeI cs); + int findColourInt(char symbol, int position, SequenceI seq); + } \ No newline at end of file diff --git a/src/jalview/renderer/seqfeatures/FeatureColourFinder.java b/src/jalview/renderer/seqfeatures/FeatureColourFinder.java index cfe2735..8da880a 100644 --- a/src/jalview/renderer/seqfeatures/FeatureColourFinder.java +++ b/src/jalview/renderer/seqfeatures/FeatureColourFinder.java @@ -48,6 +48,8 @@ public class FeatureColourFinder */ private BufferedImage offscreenImage; + private Graphics goff; + /** * Constructor * @@ -57,6 +59,7 @@ public class FeatureColourFinder { featureRenderer = fr; offscreenImage = new BufferedImage(1, 1, BufferedImage.TYPE_INT_ARGB); + goff = offscreenImage.getGraphics(); } /** @@ -94,7 +97,7 @@ public class FeatureColourFinder */ if (featureRenderer.getTransparency() != 1f) { - g = offscreenImage.getGraphics(); + g = goff; if (defaultColour != null) { offscreenImage.setRGB(0, 0, defaultColour.getRGB()); @@ -114,13 +117,48 @@ public class FeatureColourFinder return c; } + public int findFeatureColourInt(int defaultColour, SequenceI seq, + int column) + { + // if (noFeaturesDisplayed()) + // { + // return defaultColour; + // } + + Graphics g = null; + + /* + * if transparency applies, provide a notional 1x1 graphics context + * that has been primed with the default colour + */ + if (featureRenderer.getTransparency() != 1f) + { + g = goff; + if (defaultColour != 0) + { + offscreenImage.setRGB(0, 0, defaultColour); + } + } + + Color c = featureRenderer.findFeatureColour(seq, column + 1, g); + if (c == null) + { + return defaultColour; + } + + if (g != null) + { + return offscreenImage.getRGB(0, 0); + } + return c.getRGB(); + } /** * Answers true if feature display is turned off, or there are no features * configured to be visible * * @return */ - boolean noFeaturesDisplayed() + public boolean noFeaturesDisplayed() { if (featureRenderer == null || !featureRenderer.getViewport().isShowSequenceFeatures()) diff --git a/src/jalview/renderer/seqfeatures/FeatureRenderer.java b/src/jalview/renderer/seqfeatures/FeatureRenderer.java index 13885b4..9988076 100644 --- a/src/jalview/renderer/seqfeatures/FeatureRenderer.java +++ b/src/jalview/renderer/seqfeatures/FeatureRenderer.java @@ -26,6 +26,7 @@ import jalview.datamodel.ContiguousI; import jalview.datamodel.SequenceFeature; import jalview.datamodel.SequenceI; import jalview.util.Comparison; +import jalview.util.Platform; import jalview.viewmodel.seqfeatures.FeatureRendererModel; import java.awt.AlphaComposite; @@ -33,6 +34,7 @@ import java.awt.Color; import java.awt.FontMetrics; import java.awt.Graphics; import java.awt.Graphics2D; +import java.util.ArrayList; import java.util.List; public class FeatureRenderer extends FeatureRendererModel @@ -90,11 +92,13 @@ public class FeatureRenderer extends FeatureRendererModel int pady = (y1 + charHeight) - charHeight / 5; FontMetrics fm = g.getFontMetrics(); + char s = '\0'; for (int i = featureStart; i <= featureEnd; i++) { - char s = seq.getCharAt(i); - if (Comparison.isGap(s)) + // colourOnly is just for Overview -- no need to check this again + + if (!colourOnly && Comparison.isGap(s = seq.getCharAt(i))) { continue; } @@ -103,7 +107,12 @@ public class FeatureRenderer extends FeatureRendererModel g.fillRect((i - start) * charWidth, y1, charWidth, charHeight); - if (colourOnly || !validCharWidth) + if (colourOnly) + { + return true; + } + + if (!validCharWidth) { continue; } @@ -117,6 +126,9 @@ public class FeatureRenderer extends FeatureRendererModel } /** + * + * BH - this method is never called? + * * Renders the sequence using the given SCORE feature colour between the given * start and end columns. Returns true if at least one column is drawn, else * false (the feature range does not overlap the start and end positions). @@ -211,10 +223,12 @@ public class FeatureRenderer extends FeatureRendererModel @Override public Color findFeatureColour(SequenceI seq, int column, Graphics g) { - if (!av.isShowSequenceFeatures()) - { - return null; - } + // BH 2019.08.01 + // this is already checked in FeatureColorFinder + // if (!av.isShowSequenceFeatures()) + // { + // return null; + // } // column is 'base 1' but getCharAt is an array index (ie from 0) if (Comparison.isGap(seq.getCharAt(column - 1))) @@ -252,7 +266,8 @@ public class FeatureRenderer extends FeatureRendererModel * applies), or null if no feature is drawn in the range given. * * @param g - * the graphics context to draw on (may be null if colourOnly==true) + * the graphics context to draw on (may be null only if t == 1 from + * colourOnly==true) * @param seq * @param start * start column @@ -269,21 +284,27 @@ public class FeatureRenderer extends FeatureRendererModel final SequenceI seq, int start, int end, int y1, boolean colourOnly) { + // from SeqCanvas and OverviewRender /* * if columns are all gapped, or sequence has no features, nothing to do */ - ContiguousI visiblePositions = seq.findPositions(start + 1, end + 1); - if (visiblePositions == null || !seq.getFeatures().hasFeatures()) + ContiguousI visiblePositions; + if (!seq.getFeatures().hasFeatures() || (visiblePositions = seq + .findPositions(start + 1, end + 1)) == null) { return null; } + int vp0 = visiblePositions.getBegin(); + int vp1 = visiblePositions.getEnd(); + updateFeatures(); - if (transparency != 1f && g != null) + if (transparency != 1f) // g cannot be null here if trans == 1f - BH // && g + // != null) { - Graphics2D g2 = (Graphics2D) g; - g2.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER, + ((Graphics2D) g).setComposite( + AlphaComposite.getInstance(AlphaComposite.SRC_OVER, transparency)); } @@ -292,25 +313,28 @@ public class FeatureRenderer extends FeatureRendererModel /* * iterate over features in ordering of their rendering (last is on top) */ - for (int renderIndex = 0; renderIndex < renderOrder.length; renderIndex++) + for (int renderIndex = 0, n = renderOrder.length; renderIndex < n; renderIndex++) { String type = renderOrder[renderIndex]; - if (!showFeatureOfType(type)) + if (!seq.hasFeatures(type) || !showFeatureOfType(type)) { continue; } FeatureColourI fc = getFeatureStyle(type); - List overlaps = seq.getFeatures().findFeatures( - visiblePositions.getBegin(), visiblePositions.getEnd(), type); + List overlaps = seq.getFeatures().findFeatures(vp0, + vp1, type); - if (fc.isSimpleColour()) + // colourOnly (i.e. Overview) can only be here if translucent, so + // there is no need to check for filtering + if (!colourOnly && fc.isSimpleColour()) { filterFeaturesForDisplay(overlaps); } - for (SequenceFeature sf : overlaps) + for (int i = overlaps.size(); --i >= 0;) { + SequenceFeature sf = overlaps.get(i); Color featureColour = getColor(sf, fc); if (featureColour == null) { @@ -325,22 +349,22 @@ public class FeatureRenderer extends FeatureRendererModel * restrict to visible positions (or if a contact feature, * to a single position) */ - int visibleStart = sf.getBegin(); - if (visibleStart < visiblePositions.getBegin()) + int sf0 = sf.getBegin(); + int sf1 = sf.getEnd(); + int visibleStart = sf0; + if (visibleStart < vp0) { - visibleStart = sf.isContactFeature() ? sf.getEnd() - : visiblePositions.getBegin(); + visibleStart = sf.isContactFeature() ? sf1 : vp0; } - int visibleEnd = sf.getEnd(); - if (visibleEnd > visiblePositions.getEnd()) + int visibleEnd = sf1; + if (visibleEnd > vp1) { - visibleEnd = sf.isContactFeature() ? sf.getBegin() - : visiblePositions.getEnd(); + visibleEnd = sf.isContactFeature() ? sf0 : vp1; } int featureStartCol = seq.findIndex(visibleStart); - int featureEndCol = sf.begin == sf.end ? featureStartCol : seq - .findIndex(visibleEnd); + int featureEndCol = (sf.begin == sf.end ? featureStartCol + : seq.findIndex(visibleEnd)); // Color featureColour = getColour(sequenceFeature); @@ -381,26 +405,24 @@ public class FeatureRenderer extends FeatureRendererModel else { */ - boolean drawn = renderFeature(g, seq, - featureStartCol - 1, - featureEndCol - 1, featureColour, - start, end, y1, colourOnly); - if (drawn) - { - drawnColour = featureColour; - } + boolean drawn = renderFeature(g, seq, featureStartCol - 1, + featureEndCol - 1, featureColour, start, end, y1, + colourOnly); + if (drawn) + { + drawnColour = featureColour; + } /*}*/ } } } - if (transparency != 1.0f && g != null) + if (transparency != 1.0f) { /* * reset transparency */ - Graphics2D g2 = (Graphics2D) g; - g2.setComposite(NO_TRANSPARENCY); + ((Graphics2D) g).setComposite(NO_TRANSPARENCY); } return drawnColour; @@ -417,6 +439,10 @@ public class FeatureRenderer extends FeatureRendererModel findAllFeatures(); } + private List overlaps = (Platform.isJS() + ? new ArrayList<>() + : null); + /** * Returns the sequence feature colour rendered at the given column position, * or null if none found. The feature of highest render order (i.e. on top) is @@ -428,12 +454,18 @@ public class FeatureRenderer extends FeatureRendererModel * colour for features enclosing a gapped column. Check for gap before calling * if different behaviour is wanted. * + * BH 2019.07.30 + * + * Adds a result ArrayList to parameters in order to avoid an unnecessary + * construction of that for every pixel checked. + * + * * @param seq * @param column * (1..) * @return */ - Color findFeatureColour(SequenceI seq, int column) + private Color findFeatureColour(SequenceI seq, int column) { /* * check for new feature added while processing @@ -444,22 +476,29 @@ public class FeatureRenderer extends FeatureRendererModel * inspect features in reverse renderOrder (the last in the array is * displayed on top) until we find one that is rendered at the position */ - for (int renderIndex = renderOrder.length - - 1; renderIndex >= 0; renderIndex--) + for (int renderIndex = renderOrder.length; --renderIndex >= 0;) { String type = renderOrder[renderIndex]; - if (!showFeatureOfType(type)) + if (!seq.hasFeatures(type) || !showFeatureOfType(type)) { continue; } - List overlaps = seq.findFeatures(column, column, - type); - for (SequenceFeature sequenceFeature : overlaps) + if (overlaps != null) { - if (!featureGroupNotShown(sequenceFeature)) + overlaps.clear(); + } + List list = seq.findFeatures(column, type, overlaps); + if (list.size() > 0) + { + for (int i = 0, n = list.size(); i < n; i++) { - Color col = getColour(sequenceFeature); + SequenceFeature sf = list.get(i); + if (featureGroupNotShown(sf)) + { + continue; + } + Color col = getColour(sf); if (col != null) { return col; diff --git a/src/jalview/rest/RestHandler.java b/src/jalview/rest/RestHandler.java index a37882f..7c8c9a6 100644 --- a/src/jalview/rest/RestHandler.java +++ b/src/jalview/rest/RestHandler.java @@ -20,6 +20,8 @@ */ package jalview.rest; +import jalview.bin.ApplicationSingletonProvider; +import jalview.bin.ApplicationSingletonProvider.ApplicationSingletonI; import jalview.httpserver.AbstractRequestHandler; import java.io.IOException; @@ -30,20 +32,16 @@ import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; /** - * A simple handler to process (or delegate) HTTP requests on /jalview/rest + * A simple handler to process (or delegate) HTTP requests on /jalview/rest. */ public class RestHandler extends AbstractRequestHandler + implements ApplicationSingletonI { private static final String MY_PATH = "rest"; private static final String MY_NAME = "Rest"; /** - * Singleton instance of this class - */ - private static RestHandler instance = null; - - /** * Returns the singleton instance of this class * * @return @@ -53,12 +51,8 @@ public class RestHandler extends AbstractRequestHandler { synchronized (RestHandler.class) { - if (instance == null) - { - instance = new RestHandler(); - } + return (RestHandler) ApplicationSingletonProvider.getInstance(RestHandler.class); } - return instance; } /** diff --git a/src/jalview/schemes/AnnotationColourGradient.java b/src/jalview/schemes/AnnotationColourGradient.java index 75a07b9..5461ec0 100755 --- a/src/jalview/schemes/AnnotationColourGradient.java +++ b/src/jalview/schemes/AnnotationColourGradient.java @@ -167,8 +167,8 @@ public class AnnotationColourGradient extends FollowerColourScheme if (annotation.isRNA()) { // reset colour palette - ColourSchemeProperty.resetRnaHelicesShading(); - ColourSchemeProperty.initRnaHelicesShading(1 + (int) aamax); + ColourSchemes.resetRnaHelicesShading(); + ColourSchemes.initRnaHelicesShading(1 + (int) aamax); } } @@ -218,7 +218,7 @@ public class AnnotationColourGradient extends FollowerColourScheme } if (rna) { - ColourSchemeProperty.initRnaHelicesShading(1 + (int) aamax); + ColourSchemes.initRnaHelicesShading(1 + (int) aamax); } } } @@ -355,7 +355,7 @@ public class AnnotationColourGradient extends FollowerColourScheme { if (ann.isRNA()) { - result = ColourSchemeProperty.rnaHelices[(int) aj.value]; + result = ColourSchemes.getInstance().rnaHelices[(int) aj.value]; } else { diff --git a/src/jalview/schemes/ColourSchemeProperty.java b/src/jalview/schemes/ColourSchemeProperty.java index 2d5b23d..0123384 100755 --- a/src/jalview/schemes/ColourSchemeProperty.java +++ b/src/jalview/schemes/ColourSchemeProperty.java @@ -22,9 +22,6 @@ package jalview.schemes; import jalview.api.AlignViewportI; import jalview.datamodel.AnnotatedCollectionI; -import jalview.util.ColorUtils; - -import java.awt.Color; /** * ColourSchemeProperty binds names to hardwired colourschemes and tries to deal @@ -41,6 +38,11 @@ import java.awt.Color; public class ColourSchemeProperty { + private ColourSchemeProperty() + { + // requires static call to getColourScheme(...). + } + /** * Returns a colour scheme for the given name, with which the given data may * be coloured. The name is not case-sensitive, and may be one of @@ -109,41 +111,6 @@ public class ColourSchemeProperty return ucs; } - public static Color rnaHelices[] = null; - - public static void initRnaHelicesShading(int n) - { - int j = 0; - if (rnaHelices == null) - { - rnaHelices = new Color[n + 1]; - } - else if (rnaHelices != null && rnaHelices.length <= n) - { - Color[] t = new Color[n + 1]; - System.arraycopy(rnaHelices, 0, t, 0, rnaHelices.length); - j = rnaHelices.length; - rnaHelices = t; - } - else - { - return; - } - // Generate random colors and store - for (; j <= n; j++) - { - rnaHelices[j] = ColorUtils.generateRandomColor(Color.white); - } - } - - /** - * delete the existing cached RNA helices colours - */ - public static void resetRnaHelicesShading() - { - rnaHelices = null; - } - /** * Returns the name of the colour scheme (or "None" if it is null) * diff --git a/src/jalview/schemes/ColourSchemes.java b/src/jalview/schemes/ColourSchemes.java index d31fbba..e11540c 100644 --- a/src/jalview/schemes/ColourSchemes.java +++ b/src/jalview/schemes/ColourSchemes.java @@ -21,24 +21,19 @@ package jalview.schemes; import jalview.api.AlignViewportI; +import jalview.bin.ApplicationSingletonProvider; +import jalview.bin.ApplicationSingletonProvider.ApplicationSingletonI; import jalview.datamodel.AnnotatedCollectionI; import jalview.datamodel.SequenceCollectionI; import jalview.datamodel.SequenceI; +import jalview.util.ColorUtils; +import java.awt.Color; import java.util.LinkedHashMap; import java.util.Map; -public class ColourSchemes +public class ColourSchemes implements ApplicationSingletonI { - /* - * singleton instance of this class - */ - private static ColourSchemes instance = new ColourSchemes(); - - /* - * a map from scheme name (lower-cased) to an instance of it - */ - private Map schemes; /** * Returns the singleton instance of this class @@ -47,7 +42,8 @@ public class ColourSchemes */ public static ColourSchemes getInstance() { - return instance; + return (ColourSchemes) ApplicationSingletonProvider + .getInstance(ColourSchemes.class); } private ColourSchemes() @@ -56,6 +52,51 @@ public class ColourSchemes } /** + * ColourSchemeProperty "static" + */ + public Color[] rnaHelices = null; + + /** + * delete the existing cached RNA helices colours + */ + public static void resetRnaHelicesShading() + { + getInstance().rnaHelices = null; + } + + public static void initRnaHelicesShading(int n) + { + int i = 0; + ColourSchemes j = getInstance(); + + if (j.rnaHelices == null) + { + j.rnaHelices = new Color[n + 1]; + } + else if (j.rnaHelices != null && j.rnaHelices.length <= n) + { + Color[] t = new Color[n + 1]; + System.arraycopy(j.rnaHelices, 0, t, 0, j.rnaHelices.length); + i = j.rnaHelices.length; + j.rnaHelices = t; + } + else + { + return; + } + // Generate random colors and store + for (; i <= n; i++) + { + j.rnaHelices[i] = ColorUtils.generateRandomColor(Color.white); + } + } + + /** + * a map from scheme name (lower-cased) to an instance of it + */ + private Map schemes; + + /** * Loads an instance of each standard or user-defined colour scheme * * @return @@ -72,16 +113,12 @@ public class ColourSchemes { try { - registerColourScheme( - cs.getSchemeClass().getDeclaredConstructor().newInstance()); + registerColourScheme(cs.getSchemeClass().newInstance()); } catch (InstantiationException | IllegalAccessException e) { System.err.println("Error instantiating colour scheme for " + cs.toString() + " " + e.getMessage()); e.printStackTrace(); - } catch (ReflectiveOperationException roe) - { - roe.printStackTrace(); } } } diff --git a/src/jalview/schemes/Consensus.java b/src/jalview/schemes/Consensus.java index 9d2c738..f0d1990 100755 --- a/src/jalview/schemes/Consensus.java +++ b/src/jalview/schemes/Consensus.java @@ -53,10 +53,8 @@ public class Consensus /** * @deprecated Use {@link #isConserved(int[][],int,int,boolean)} instead */ - @Deprecated public boolean isConserved(int[][] cons2, int col, int size) { - System.out.println("DEPRECATED!!!!"); return isConserved(cons2, col, size, true); } @@ -73,7 +71,7 @@ public class Consensus tot += cons2[col][mask[i]]; } - if (tot > ((threshold * size) / 100)) + if ((double) tot > ((threshold * size) / 100)) { // System.out.println("True conserved "+tot+" from "+threshold+" out of // "+size+" : "+maskstr); diff --git a/src/jalview/schemes/FeatureColour.java b/src/jalview/schemes/FeatureColour.java index 0d36f4f..6483b85 100644 --- a/src/jalview/schemes/FeatureColour.java +++ b/src/jalview/schemes/FeatureColour.java @@ -323,7 +323,7 @@ public class FeatureColour implements FeatureColourI { if (minval.length() > 0) { - min = Float.valueOf(minval).floatValue(); + min = new Float(minval).floatValue(); } } catch (Exception e) { @@ -335,7 +335,7 @@ public class FeatureColour implements FeatureColourI { if (maxval.length() > 0) { - max = Float.valueOf(maxval).floatValue(); + max = new Float(maxval).floatValue(); } } catch (Exception e) { @@ -403,7 +403,7 @@ public class FeatureColour implements FeatureColourI { gcol.nextToken(); tval = gcol.nextToken(); - featureColour.setThreshold(Float.valueOf(tval).floatValue()); + featureColour.setThreshold(new Float(tval).floatValue()); } catch (Exception e) { System.err.println("Couldn't parse threshold value as a float: (" diff --git a/src/jalview/schemes/RNAHelicesColour.java b/src/jalview/schemes/RNAHelicesColour.java index 33b275d..c61eeed 100644 --- a/src/jalview/schemes/RNAHelicesColour.java +++ b/src/jalview/schemes/RNAHelicesColour.java @@ -70,14 +70,14 @@ public class RNAHelicesColour extends ResidueColourScheme { super(ResidueProperties.nucleotideIndex); this.annotation = annotation; - ColourSchemeProperty.resetRnaHelicesShading(); + ColourSchemes.resetRnaHelicesShading(); refresh(); } public RNAHelicesColour(AnnotatedCollectionI alignment) { super(ResidueProperties.nucleotideIndex); - ColourSchemeProperty.resetRnaHelicesShading(); + ColourSchemes.resetRnaHelicesShading(); alignmentChanged(alignment, null); } @@ -160,7 +160,7 @@ public class RNAHelicesColour extends ResidueColourScheme } } - ColourSchemeProperty.initRnaHelicesShading(numHelix); + ColourSchemes.initRnaHelicesShading(numHelix); } } @@ -200,7 +200,7 @@ public class RNAHelicesColour extends ResidueColourScheme currentHelix = positionsToHelix.get(j); if (currentHelix != null) { - currentColour = ColourSchemeProperty.rnaHelices[Integer + currentColour = ColourSchemes.getInstance().rnaHelices[Integer .parseInt(currentHelix)]; } return currentColour; diff --git a/src/jalview/schemes/ResidueProperties.java b/src/jalview/schemes/ResidueProperties.java index 5f84ca0..df6610a 100755 --- a/src/jalview/schemes/ResidueProperties.java +++ b/src/jalview/schemes/ResidueProperties.java @@ -498,34 +498,35 @@ public class ResidueProperties * Color.white, // R Color.white, // Y Color.white, // N Color.white, // Gap */ - public static String STOP = "STOP"; + public static final String STOP = "STOP"; - public static List STOP_CODONS = Arrays.asList("TGA", "TAA", "TAG"); + public static final List STOP_CODONS = Arrays.asList("TGA", "TAA", + "TAG"); - public static String START = "ATG"; + public static final String START = "ATG"; // Stores residue codes/names and colours and other things - public static Map> propHash = new Hashtable<>(); + public static final Map> propHash = new Hashtable<>(); - public static Map hydrophobic = new Hashtable<>(); + public static final Map hydrophobic = new Hashtable<>(); - public static Map polar = new Hashtable<>(); + public static final Map polar = new Hashtable<>(); - public static Map small = new Hashtable<>(); + public static final Map small = new Hashtable<>(); - public static Map positive = new Hashtable<>(); + public static final Map positive = new Hashtable<>(); - public static Map negative = new Hashtable<>(); + public static final Map negative = new Hashtable<>(); - public static Map charged = new Hashtable<>(); + public static final Map charged = new Hashtable<>(); - public static Map aromatic = new Hashtable<>(); + public static final Map aromatic = new Hashtable<>(); - public static Map aliphatic = new Hashtable<>(); + public static final Map aliphatic = new Hashtable<>(); - public static Map tiny = new Hashtable<>(); + public static final Map tiny = new Hashtable<>(); - public static Map proline = new Hashtable<>(); + public static final Map proline = new Hashtable<>(); static { @@ -896,8 +897,7 @@ public class ResidueProperties public static String codonTranslate(String lccodon) { - String peptide = GeneticCodes.getInstance().getStandardCodeTable() - .translate(lccodon); + String peptide = GeneticCodes.getStandardCodeTable().translate(lccodon); if ("*".equals(peptide)) { return "STOP"; @@ -909,7 +909,7 @@ public class ResidueProperties * lookup of (A-Z) alternative secondary structure symbols' * equivalents in DSSP3 notation */ - private static char[] toDssp3State; + private final static char[] toDssp3State; static { toDssp3State = new char[9]; // for 'A'-'I'; extend if needed diff --git a/src/jalview/structure/StructureImportSettings.java b/src/jalview/structure/StructureImportSettings.java index 9662fee..b5672ab 100644 --- a/src/jalview/structure/StructureImportSettings.java +++ b/src/jalview/structure/StructureImportSettings.java @@ -20,6 +20,8 @@ */ package jalview.structure; +import jalview.bin.ApplicationSingletonProvider; +import jalview.bin.ApplicationSingletonProvider.ApplicationSingletonI; import jalview.datamodel.PDBEntry; import jalview.datamodel.PDBEntry.Type; @@ -30,27 +32,39 @@ import jalview.datamodel.PDBEntry.Type; * @author tcofoegbu * */ -public class StructureImportSettings +public class StructureImportSettings implements ApplicationSingletonI { + + private StructureImportSettings() + { + // private singleton + } + + private static StructureImportSettings getInstance() + { + return (StructureImportSettings) ApplicationSingletonProvider + .getInstance(StructureImportSettings.class); + } + /** * set to true to add derived sequence annotations (temp factor read from * file, or computed secondary structure) to the alignment */ - private static boolean visibleChainAnnotation = false; + private boolean visibleChainAnnotation = false; /** * Set true to predict secondary structure (using JMol for protein, Annotate3D * for RNA) */ - private static boolean processSecStr = false; + private boolean processSecStr = false; /** * Set true (with predictSecondaryStructure=true) to predict secondary * structure using an external service (currently Annotate3D for RNA only) */ - private static boolean externalSecondaryStructure = false; + private boolean externalSecondaryStructure = false; - private static boolean showSeqFeatures = true; + private boolean showSeqFeatures = true; public enum StructureParser { @@ -61,92 +75,93 @@ public class StructureImportSettings * Determines the default file format for structure files to be downloaded * from the PDB sequence fetcher. Possible options include: PDB|mmCIF */ - private static PDBEntry.Type defaultStructureFileFormat = Type.PDB; + private PDBEntry.Type defaultStructureFileFormat = Type.PDB; /** * Determines the parser used for parsing PDB format file. Possible options * are : JMolParser|JalveiwParser */ - private static StructureParser defaultPDBFileParser = StructureParser.JMOL_PARSER; + private StructureParser defaultPDBFileParser = StructureParser.JMOL_PARSER; public static void addSettings(boolean addAlignmentAnnotations, boolean processSecStr, boolean externalSecStr) { - StructureImportSettings.visibleChainAnnotation = addAlignmentAnnotations; - StructureImportSettings.processSecStr = processSecStr; - StructureImportSettings.externalSecondaryStructure = externalSecStr; - StructureImportSettings.showSeqFeatures = true; + StructureImportSettings s = getInstance(); + s.visibleChainAnnotation = addAlignmentAnnotations; + s.processSecStr = processSecStr; + s.externalSecondaryStructure = externalSecStr; + s.showSeqFeatures = true; } public static boolean isVisibleChainAnnotation() { - return visibleChainAnnotation; + return getInstance().visibleChainAnnotation; } public static void setVisibleChainAnnotation( boolean visibleChainAnnotation) { - StructureImportSettings.visibleChainAnnotation = visibleChainAnnotation; + getInstance().visibleChainAnnotation = visibleChainAnnotation; } public static boolean isProcessSecondaryStructure() { - return processSecStr; + return getInstance().processSecStr; } public static void setProcessSecondaryStructure( boolean processSecondaryStructure) { - StructureImportSettings.processSecStr = processSecondaryStructure; + getInstance().processSecStr = processSecondaryStructure; } public static boolean isExternalSecondaryStructure() { - return externalSecondaryStructure; + return getInstance().externalSecondaryStructure; } public static void setExternalSecondaryStructure( boolean externalSecondaryStructure) { - StructureImportSettings.externalSecondaryStructure = externalSecondaryStructure; + getInstance().externalSecondaryStructure = externalSecondaryStructure; } public static boolean isShowSeqFeatures() { - return showSeqFeatures; + return getInstance().showSeqFeatures; } public static void setShowSeqFeatures(boolean showSeqFeatures) { - StructureImportSettings.showSeqFeatures = showSeqFeatures; + getInstance().showSeqFeatures = showSeqFeatures; } public static PDBEntry.Type getDefaultStructureFileFormat() { - return defaultStructureFileFormat; + return getInstance().defaultStructureFileFormat; } public static void setDefaultStructureFileFormat( String defaultStructureFileFormat) { - StructureImportSettings.defaultStructureFileFormat = PDBEntry.Type + getInstance().defaultStructureFileFormat = PDBEntry.Type .valueOf(defaultStructureFileFormat.toUpperCase()); } public static String getDefaultPDBFileParser() { - return defaultPDBFileParser.toString(); + return getInstance().defaultPDBFileParser.toString(); } public static void setDefaultPDBFileParser( StructureParser defaultPDBFileParser) { - StructureImportSettings.defaultPDBFileParser = defaultPDBFileParser; + getInstance().defaultPDBFileParser = defaultPDBFileParser; } public static void setDefaultPDBFileParser(String defaultPDBFileParser) { - StructureImportSettings.defaultPDBFileParser = StructureParser + getInstance().defaultPDBFileParser = StructureParser .valueOf(defaultPDBFileParser.toUpperCase()); } diff --git a/src/jalview/structure/StructureSelectionManager.java b/src/jalview/structure/StructureSelectionManager.java index 1744467..012dff3 100644 --- a/src/jalview/structure/StructureSelectionManager.java +++ b/src/jalview/structure/StructureSelectionManager.java @@ -22,6 +22,8 @@ package jalview.structure; import jalview.analysis.AlignSeq; import jalview.api.StructureSelectionManagerProvider; +import jalview.bin.ApplicationSingletonProvider; +import jalview.bin.ApplicationSingletonProvider.ApplicationSingletonI; import jalview.commands.CommandI; import jalview.commands.EditCommand; import jalview.commands.OrderCommand; @@ -41,7 +43,6 @@ import jalview.io.DataSourceType; import jalview.io.StructureFile; import jalview.util.MappingUtils; import jalview.util.MessageManager; -import jalview.util.Platform; import jalview.ws.sifts.SiftsClient; import jalview.ws.sifts.SiftsException; import jalview.ws.sifts.SiftsSettings; @@ -61,12 +62,10 @@ import mc_view.Atom; import mc_view.PDBChain; import mc_view.PDBfile; -public class StructureSelectionManager +public class StructureSelectionManager implements ApplicationSingletonI { public final static String NEWLINE = System.lineSeparator(); - static IdentityHashMap instances; - private List mappings = new ArrayList<>(); private boolean processSecondaryStructure = false; @@ -84,6 +83,77 @@ public class StructureSelectionManager private List sel_listeners = new ArrayList<>(); + /* + * instances of this class scoped by some context class + */ + private IdentityHashMap structureSelections; + + /** + * Answers an instance of this class for the current application (Java or JS + * 'applet') scope + * + * @return + */ + private static StructureSelectionManager getInstance() + { + return (StructureSelectionManager) ApplicationSingletonProvider + .getInstance(StructureSelectionManager.class); + } + + /** + * Answers an instance of this class for the current application (Java or JS + * 'applet') scope, and scoped to the specified context + * + * @param context + * @return + */ + public static StructureSelectionManager getStructureSelectionManager( + StructureSelectionManagerProvider context) + { + return getInstance().getInstanceForContext(context); + } + + /** + * Answers an instance of this class scoped to the given context. The instance + * is created on the first request for the context, thereafter the same + * instance is returned. Note that the context may be null (this is the case + * when running headless without a Desktop). + * + * @param context + * @return + */ + StructureSelectionManager getInstanceForContext( + StructureSelectionManagerProvider context) + { + StructureSelectionManager instance = structureSelections.get(context); + if (instance == null) + { + instance = new StructureSelectionManager(); + structureSelections.put(context, instance); + } + return instance; + } + + /** + * Removes the instance associated with this provider + * + * @param provider + */ + + public static void release(StructureSelectionManagerProvider provider) + { + getInstance().structureSelections.remove(provider); + } + + /** + * Private constructor as all 'singleton' instances are managed here or by + * ApplicationSingletonProvider + */ + private StructureSelectionManager() + { + structureSelections = new IdentityHashMap<>(); + } + /** * @return true if will try to use external services for processing secondary * structure @@ -198,49 +268,6 @@ public class StructureSelectionManager || pdbIdFileName.containsKey(idOrFile); } - private static StructureSelectionManager nullProvider = null; - - public static StructureSelectionManager getStructureSelectionManager( - StructureSelectionManagerProvider context) - { - if (context == null) - { - if (nullProvider == null) - { - if (instances != null) - { - throw new Error(MessageManager.getString( - "error.implementation_error_structure_selection_manager_null"), - new NullPointerException(MessageManager - .getString("exception.ssm_context_is_null"))); - } - else - { - nullProvider = new StructureSelectionManager(); - } - return nullProvider; - } - } - if (instances == null) - { - instances = new java.util.IdentityHashMap<>(); - } - StructureSelectionManager instance = instances.get(context); - if (instance == null) - { - if (nullProvider != null) - { - instance = nullProvider; - } - else - { - instance = new StructureSelectionManager(); - } - instances.put(context, instance); - } - return instance; - } - /** * flag controlling whether SeqMappings are relayed from received sequence * mouse over events to other sequences @@ -270,7 +297,7 @@ public class StructureSelectionManager return relaySeqMappings; } - Vector listeners = new Vector(); + Vector listeners = new Vector<>(); /** * register a listener for alignment sequence mouseover events @@ -308,6 +335,8 @@ public class StructureSelectionManager * Import structure data and register a structure mapping for broadcasting * colouring, mouseovers and selection events (convenience wrapper). * + * This is the standard entry point. + * * @param sequence * - one or more sequences to be mapped to pdbFile * @param targetChains @@ -332,8 +361,11 @@ public class StructureSelectionManager * broadcasting colouring, mouseovers and selection events (convenience * wrapper). * + * + * * @param forStructureView - * when true, record the mapping for use in mouseOvers + * when true (testng only), record the mapping for use in mouseOvers + * (testng only) * @param sequence * - one or more sequences to be mapped to pdbFile * @param targetChains @@ -377,7 +409,7 @@ public class StructureSelectionManager * mapping operation * @return null or the structure data parsed as a pdb file */ - synchronized public StructureFile computeMapping( + synchronized private StructureFile computeMapping( boolean forStructureView, SequenceI[] sequenceArray, String[] targetChainIds, String pdbFile, DataSourceType sourceType, IProgressIndicator progress) @@ -651,7 +683,6 @@ public class StructureSelectionManager { ds = ds.getDatasetSequence(); } - ; if (ds.getAnnotation() != null) { for (AlignmentAnnotation ala : ds.getAnnotation()) @@ -1171,8 +1202,7 @@ public class StructureSelectionManager StringBuilder sb = new StringBuilder(64); for (StructureMapping sm : mappings) { - if (Platform.pathEquals(sm.pdbfile, pdbfile) - && seqs.contains(sm.sequence)) + if (sm.pdbfile.equals(pdbfile) && seqs.contains(sm.sequence)) { sb.append(sm.mappingDetails); sb.append(NEWLINE); @@ -1234,43 +1264,22 @@ public class StructureSelectionManager } /** - * Resets this object to its initial state by removing all registered - * listeners, codon mappings, PDB file mappings + * Reset this object to its initial state by removing all registered + * listeners, codon mappings, PDB file mappings. + * + * Called only by Desktop and testng. + * */ public void resetAll() { - if (mappings != null) - { - mappings.clear(); - } - if (seqmappings != null) - { - seqmappings.clear(); - } - if (sel_listeners != null) - { - sel_listeners.clear(); - } - if (listeners != null) - { - listeners.clear(); - } - if (commandListeners != null) - { - commandListeners.clear(); - } - if (view_listeners != null) - { - view_listeners.clear(); - } - if (pdbFileNameId != null) - { - pdbFileNameId.clear(); - } - if (pdbIdFileName != null) - { - pdbIdFileName.clear(); - } + mappings.clear(); + seqmappings.clear(); + sel_listeners.clear(); + listeners.clear(); + commandListeners.clear(); + view_listeners.clear(); + pdbFileNameId.clear(); + pdbIdFileName.clear(); } public void addSelectionListener(SelectionListener selecter) @@ -1321,41 +1330,10 @@ public class StructureSelectionManager { slis.viewPosition(startRes, endRes, startSeq, endSeq, source); } - ; } } } - - /** - * release all references associated with this manager provider - * - * @param jalviewLite - */ - public static void release(StructureSelectionManagerProvider jalviewLite) - { - // synchronized (instances) - { - if (instances == null) - { - return; - } - StructureSelectionManager mnger = (instances.get(jalviewLite)); - if (mnger != null) - { - instances.remove(jalviewLite); - try - { - /* bsoares 2019-03-20 finalize deprecated, no apparent external - * resources to close - */ - // mnger.finalize(); - } catch (Throwable x) - { - } - } - } - } - + public void registerPDBEntry(PDBEntry pdbentry) { if (pdbentry.getFile() != null diff --git a/src/jalview/structures/models/AAStructureBindingModel.java b/src/jalview/structures/models/AAStructureBindingModel.java index 2528286..a98e4b1 100644 --- a/src/jalview/structures/models/AAStructureBindingModel.java +++ b/src/jalview/structures/models/AAStructureBindingModel.java @@ -355,8 +355,8 @@ public abstract class AAStructureBindingModel { Integer.valueOf(pe).toString() })); } final String nullChain = "TheNullChain"; - List s = new ArrayList(); - List c = new ArrayList(); + List s = new ArrayList<>(); + List c = new ArrayList<>(); if (getChains() == null) { setChains(new String[getPdbCount()][]); @@ -425,8 +425,8 @@ public abstract class AAStructureBindingModel public synchronized PDBEntry[] addSequenceAndChain(PDBEntry[] pdbe, SequenceI[][] seq, String[][] chns) { - List v = new ArrayList(); - List rtn = new ArrayList(); + List v = new ArrayList<>(); + List rtn = new ArrayList<>(); for (int i = 0; i < getPdbCount(); i++) { v.add(getPdbEntry(i)); @@ -512,12 +512,10 @@ public abstract class AAStructureBindingModel } /** - * Returns a readable description of all mappings for the wrapped pdbfile to - * any mapped sequences * - * @param pdbfile - * @param seqs - * @return + * @return a readable description of all mappings for the wrapped pdbfile to + * any mapped sequences + * */ public String printMappings() { diff --git a/src/jalview/urls/IdOrgSettings.java b/src/jalview/urls/IdOrgSettings.java index 7dd1a19..cd7e98e 100644 --- a/src/jalview/urls/IdOrgSettings.java +++ b/src/jalview/urls/IdOrgSettings.java @@ -21,35 +21,46 @@ package jalview.urls; +import jalview.bin.ApplicationSingletonProvider; +import jalview.bin.ApplicationSingletonProvider.ApplicationSingletonI; + /** * Holds settings for identifiers.org e.g. url, download location - * - * @author $author$ - * @version $Revision$ */ -public class IdOrgSettings +public class IdOrgSettings implements ApplicationSingletonI { - private static String url; + private String url; - private static String location; + private String location; + + private static IdOrgSettings getInstance() + { + return (IdOrgSettings) ApplicationSingletonProvider + .getInstance(IdOrgSettings.class); + } public static void setUrl(String seturl) { - url = seturl; + getInstance().url = seturl; } public static void setDownloadLocation(String setloc) { - location = setloc; + getInstance().location = setloc; } public static String getUrl() { - return url; + return getInstance().url; } public static String getDownloadLocation() { - return location; + return getInstance().location; + } + + private IdOrgSettings() + { + // private singleton } } diff --git a/src/jalview/urls/IdentifiersUrlProvider.java b/src/jalview/urls/IdentifiersUrlProvider.java index 07eb23e..a44b9b9 100644 --- a/src/jalview/urls/IdentifiersUrlProvider.java +++ b/src/jalview/urls/IdentifiersUrlProvider.java @@ -85,6 +85,7 @@ private HashMap readIdentifiers(String idFileName) { // NOTE: THIS WILL FAIL IN SWINGJS BECAUSE IT INVOLVES A FILE READER + System.out.println("IDentifiersURL " + idFileName); FileReader reader = new FileReader(idFileName); String key = ""; Map obj = (Map) JSONUtils.parse(reader); @@ -118,7 +119,8 @@ private HashMap readIdentifiers(String idFileName) } } catch (IOException | ParseException e) { - // unnecessary e.printStackTrace(); + // unnecessary + e.printStackTrace(); // Note how in JavaScript we can grab the first bytes from any file reader. // Typical report here is "NetworkError" because the file does not exist. // "https://." is coming from System.getProperty("user.home"), but this could diff --git a/src/jalview/util/BrowserLauncher.java b/src/jalview/util/BrowserLauncher.java index 8119daa..ca2e55e 100755 --- a/src/jalview/util/BrowserLauncher.java +++ b/src/jalview/util/BrowserLauncher.java @@ -28,9 +28,14 @@ import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; /** - * BrowserLauncher is a class that provides one static method, openURL, which - * opens the default web browser for the current user of the system to the given - * URL. It may support other protocols depending on the system -- mailto, ftp, + * BrowserLauncher is a class that provides two static methods: + * + * openURL(String url), which opens the default web browser for the current user + * of the system to the given URL, and + * + * resetBrowser(), which allows switching browsers in Java. + * + * openURL may support other protocols depending on the system -- mailto, ftp, * etc. -- but that has not been rigorously tested and is not guaranteed to * work. *

      @@ -79,6 +84,14 @@ import java.lang.reflect.Method; * "mailto:ejalbert@cs.stanford.edu">ejalbert@cs.stanford.edu) * @version 1.4b1 (Released June 20, 2001) */ +/* + * + * SwingJS note: Do not use methods in this class directly. Use + * + * Platform.openURL(String url) only. + * + * JavaScript does not see this class. + */ public class BrowserLauncher { /** @@ -101,22 +114,22 @@ public class BrowserLauncher private static boolean loadedWithoutErrors; /** The com.apple.mrj.MRJFileUtils class */ - private static Class mrjFileUtilsClass; + private static Class mrjFileUtilsClass; /** The com.apple.mrj.MRJOSType class */ - private static Class mrjOSTypeClass; + private static Class mrjOSTypeClass; /** The com.apple.MacOS.AEDesc class */ - private static Class aeDescClass; + private static Class aeDescClass; /** The <init>(int) method of com.apple.MacOS.AETarget */ - private static Constructor aeTargetConstructor; + private static Constructor aeTargetConstructor; /** The <init>(int, int, int) method of com.apple.MacOS.AppleEvent */ - private static Constructor appleEventConstructor; + private static Constructor appleEventConstructor; /** The <init>(String) method of com.apple.MacOS.AEDesc */ - private static Constructor aeDescConstructor; + private static Constructor aeDescConstructor; /** The findFolder method of com.apple.mrj.MRJFileUtils */ private static Method findFolder; @@ -236,14 +249,6 @@ public class BrowserLauncher loadedWithoutErrors = true; - if (!Platform.isJS()) - /** - * Java only - * - * @j2sIgnore - * - */ - { String osName = System.getProperty("os.name"); if (osName.startsWith("Mac OS")) @@ -316,7 +321,6 @@ public class BrowserLauncher { // if we haven't hit any errors yet loadedWithoutErrors = loadClasses(); } - } } /** @@ -336,24 +340,17 @@ public class BrowserLauncher private static boolean loadClasses() { - if (!Platform.isJS()) - /** - * Java only - * - * @j2sIgnore - * - */ - { switch (jvm) { case MRJ_2_0: try { - Class aeTargetClass = Class.forName("com.apple.MacOS.AETarget"); - Class osUtilsClass = Class.forName("com.apple.MacOS.OSUtils"); - Class appleEventClass = Class.forName("com.apple.MacOS.AppleEvent"); - Class aeClass = Class.forName("com.apple.MacOS.ae"); + Class aeTargetClass = Class.forName("com.apple.MacOS.AETarget"); + Class osUtilsClass = Class.forName("com.apple.MacOS.OSUtils"); + Class appleEventClass = Class + .forName("com.apple.MacOS.AppleEvent"); + Class aeClass = Class.forName("com.apple.MacOS.ae"); aeDescClass = Class.forName("com.apple.MacOS.AEDesc"); aeTargetConstructor = aeTargetClass @@ -464,8 +461,8 @@ public class BrowserLauncher try { - Class linker = Class.forName("com.apple.mrj.jdirect.Linker"); - Constructor constructor = linker + Class linker = Class.forName("com.apple.mrj.jdirect.Linker"); + Constructor constructor = linker .getConstructor(new Class[] { Class.class }); linkage = constructor @@ -526,7 +523,6 @@ public class BrowserLauncher break; } - } return true; } @@ -543,14 +539,6 @@ public class BrowserLauncher */ private static Object locateBrowser() { - if (!Platform.isJS()) - /** - * Java only - * - * @j2sIgnore - * - */ - { if (browser != null) { return browser; @@ -716,11 +704,7 @@ public class BrowserLauncher break; } - - } - return browser; - } /** @@ -742,20 +726,11 @@ public class BrowserLauncher */ public static void openURL(String url) throws IOException { - if (Platform.isJS()) { Platform.openURL(url); return; } - else - /** - * Java only - * - * @j2sIgnore - */ - { - if (!loadedWithoutErrors) { throw new IOException(MessageManager @@ -934,14 +909,11 @@ public class BrowserLauncher break; default: - // This should never occur, but if it does, we'll try the simplest thing // possible Runtime.getRuntime().exec(new String[] { (String) browser, url }); - break; } - } } diff --git a/src/jalview/util/ColorUtils.java b/src/jalview/util/ColorUtils.java index 60129fb..a2d8d3e 100644 --- a/src/jalview/util/ColorUtils.java +++ b/src/jalview/util/ColorUtils.java @@ -199,6 +199,42 @@ public class ColorUtils } } + public static int bleachColourInt(int colour, float bleachFactor) + { + if (bleachFactor >= 1f) + { + return -1;// Color.WHITE; + } + if (bleachFactor <= -1f) + { + return 0xFF000000;// Color.BLACK; + } + if (bleachFactor == 0f) + { + return colour; + } + + int red = (colour >> 16) & 0xFF;// getRed(); + int green = (colour >> 8) & 0xFF;// colour.getGreen(); + int blue = colour & 0xFF;// .getBlue(); + + if (bleachFactor > 0) + { + red += (255 - red) * bleachFactor; + green += (255 - green) * bleachFactor; + blue += (255 - blue) * bleachFactor; + } + else + { + float factor = 1 + bleachFactor; + red *= factor; + green *= factor; + blue *= factor; + } + return 0xFF000000 | (red << 16) | (green << 8) | blue;// new Color(red, + // green, blue); + } + /** * Parses a string into a Color, where the accepted formats are *

        @@ -225,6 +261,7 @@ public class ColorUtils col = new Color(value); } catch (NumberFormatException ex) { + col = Platform.getColorFromName(colour); } if (col == null) @@ -319,57 +356,8 @@ public class ColorUtils */ public static Color getAWTColorFromName(String name) { - if (name == null) - { - return null; - } - Color col = null; - name = name.toLowerCase(); - - // or make a static map; or use reflection on the field name - switch (name) - { - case "black": - col = Color.black; - break; - case "blue": - col = Color.blue; - break; - case "cyan": - col = Color.cyan; - break; - case "darkgray": - col = Color.darkGray; - break; - case "gray": - col = Color.gray; - break; - case "green": - col = Color.green; - break; - case "lightgray": - col = Color.lightGray; - break; - case "magenta": - col = Color.magenta; - break; - case "orange": - col = Color.orange; - break; - case "pink": - col = Color.pink; - break; - case "red": - col = Color.red; - break; - case "white": - col = Color.white; - break; - case "yellow": - col = Color.yellow; - break; - } - - return col; + return Platform.getColorFromName(name); // BH 2019 -- allows for wide range + // of JavaScript colors (for + // JavaScript only) } } diff --git a/src/jalview/util/DBRefUtils.java b/src/jalview/util/DBRefUtils.java index fb54bba..197261a 100755 --- a/src/jalview/util/DBRefUtils.java +++ b/src/jalview/util/DBRefUtils.java @@ -32,7 +32,6 @@ import java.util.HashMap; import java.util.HashSet; import java.util.List; import java.util.Map; -import java.util.Set; import com.stevesoft.pat.Regex; @@ -96,14 +95,14 @@ public class DBRefUtils } // BH TODO (what?) - HashSet srcs = new HashSet(); + HashSet srcs = new HashSet<>(); for (String src : sources) { srcs.add(src.toUpperCase()); } int nrefs = dbrefs.size(); - List res = new ArrayList(); + List res = new ArrayList<>(); for (int ib = 0; ib < nrefs; ib++) { DBRefEntry dbr = dbrefs.get(ib); @@ -217,7 +216,7 @@ public class DBRefUtils * @return */ public static List searchRefs(List refs, String accId) { - List rfs = new ArrayList(); + List rfs = new ArrayList<>(); if (refs == null || accId == null) { return rfs; } @@ -243,7 +242,7 @@ public class DBRefUtils * @return */ static List searchRefs(List refs, DBRefEntry entry, DbRefComp comparator, int mode) { - List rfs = new ArrayList(); + List rfs = new ArrayList<>(); if (refs == null || entry == null) { return rfs; } @@ -450,6 +449,14 @@ public class DBRefUtils return matches; } + private static Regex PARSE_REGEX; + + private static Regex getParseRegex() + { + return (PARSE_REGEX == null ? PARSE_REGEX = Platform.newRegex( + "([0-9][0-9A-Za-z]{3})\\s*(.?)\\s*;\\s*([0-9]+)-([0-9]+)", null) + : PARSE_REGEX); + } /** * Parses a DBRefEntry and adds it to the sequence, also a PDBEntry if the * database is PDB. @@ -471,7 +478,7 @@ public class DBRefUtils /* * Check for PFAM style stockhom PDB accession id citation e.g. "1WRI A; 7-80;" */ - Regex r = new com.stevesoft.pat.Regex("([0-9][0-9A-Za-z]{3})\\s*(.?)\\s*;\\s*([0-9]+)-([0-9]+)"); + Regex r = getParseRegex(); if (r.search(acn.trim())) { String pdbid = r.stringMatched(1); String chaincode = r.stringMatched(2); @@ -558,7 +565,7 @@ public class DBRefUtils * @return */ public static List searchRefsForSource(List dbRefs, String source) { - List matches = new ArrayList(); + List matches = new ArrayList<>(); if (dbRefs != null && source != null) { for (DBRefEntry dbref : dbRefs) { if (source.equalsIgnoreCase(dbref.getSource())) { @@ -621,7 +628,9 @@ public class DBRefUtils bsSelect.set(0, dbrefs.size()); if (!selectRefsBS(dbrefs, isProtein ? DBRefSource.PROTEIN_MASK : DBRefSource.DNA_CODING_MASK, bsSelect)) - return; + { + return; + } // selfs.addAll(selfArray); // } @@ -631,7 +640,9 @@ public class DBRefUtils DBRefEntry p = pr.get(ip); for (int i = bsSelect.nextSetBit(0); i >= 0; i = bsSelect.nextSetBit(i + 1)) { if (dbrefs.get(i) == p) - bsSelect.clear(i); + { + bsSelect.clear(i); + } } // while (selfs.contains(p)) // { @@ -655,7 +666,9 @@ public class DBRefUtils // TODO: promote transcript refs ?? } if (keys == 0 || !selectRefsBS(dbrefs, keys, bsSelect)) - return; + { + return; + } // if (candidates != null) { for (int ic = bsSelect.nextSetBit(0); ic >= 0; ic = bsSelect.nextSetBit(ic + 1)) diff --git a/src/jalview/util/GroupUrlLink.java b/src/jalview/util/GroupUrlLink.java index 67309a0..e4c4ad0 100644 --- a/src/jalview/util/GroupUrlLink.java +++ b/src/jalview/util/GroupUrlLink.java @@ -20,13 +20,22 @@ */ package jalview.util; -import jalview.datamodel.Sequence; import jalview.datamodel.SequenceI; import java.util.Hashtable; +import com.stevesoft.pat.Regex; + +/** + * This class is not implemented because Preferences never puts anything in + * groupURLLinks. + * + * @author hansonr + * + */ public class GroupUrlLink { + @SuppressWarnings("serial") public class UrlStringTooLongException extends Exception { public UrlStringTooLongException(int lng) @@ -66,11 +75,6 @@ public class GroupUrlLink private String invalidMessage = null; /** - * tokens that can be replaced in the URL. - */ - private static String[] tokens; - - /** * position of each token (which can appear once only) in the url */ private int[] segs; @@ -79,32 +83,34 @@ public class GroupUrlLink * contains tokens in the order they appear in the URL template. */ private String[] mtch; - static - { - if (tokens == null) - { - tokens = new String[] { "SEQUENCEIDS", "SEQUENCES", "DATASETID" }; - } - } - - /** - * test for GroupURLType bitfield (with default tokens) - */ - public static final int SEQUENCEIDS = 1; - - /** - * test for GroupURLType bitfield (with default tokens) - */ - public static final int SEQUENCES = 2; /** - * test for GroupURLType bitfield (with default tokens) + * tokens that can be replaced in the URL. */ - public static final int DATASETID = 4; - + private static final String[] tokens = new String[] { "SEQUENCEIDS", + "SEQUENCES", "DATASETID" }; + + // /** + // * test for GroupURLType bitfield (with default tokens) + // */ + // private static final int SEQUENCEIDS = 1; + // + // /** + // * test for GroupURLType bitfield (with default tokens) + // */ + // private static final int SEQUENCES = 2; + // + // /** + // * test for GroupURLType bitfield (with default tokens) + // */ + // private static final int DATASETID = 4; + // // private int idseg = -1, seqseg = -1; /** + * + * called by PopupMenu.buildGroupURLMenu() + * * parse the given linkString of the form '