package jalview.api; import java.awt.EventQueue; //import java.applet.AppletContext; import java.io.IOException; 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 jalview.bin.ArgsParser; import jalview.bin.Jalview; import jalview.bin.JalviewJSApi; 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.AlignmentPanel; import jalview.gui.CalculationChooser; import jalview.gui.Desktop; import jalview.gui.StructureViewer; 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.renderer.seqfeatures.FeatureRenderer; import jalview.structure.SelectionListener; import jalview.structure.SelectionSource; import jalview.structure.StructureSelectionManager; import jalview.structure.VamsasSource; import jalview.util.HttpUtils; import jalview.util.MessageManager; import jalview.util.Platform; //import netscape.javascript.JSObject; /** * Basically the JalviewLite application, but without JalviewLite * * @author hansonr * */ public class JalviewJSApp implements JalviewJSApi { private ArgsParser aparser; private String j2sAppletID; private boolean debug; private String[] ret = new String[1]; private String separator = "\u00AC"; // JalviewLite note: the default used to // be '|', but many sequence IDS include // pipes. public JalviewJSApp(ArgsParser aparser) { this.aparser = aparser; this.j2sAppletID = (String) aparser.getAppletValue("j2sAppletID", "Jalview", true); Platform.setAppClass(this); } public void load(AlignFrame af) { String sep = (String) getAppletParameter("separator", true); if (sep != null) { if (sep.length() > 0) { separator = sep; } else { throw new Error(MessageManager .getString("error.invalid_separator_parameter")); } } loadTree(af); loadScoreFile(); loadFeatures(af); loadAnnotations(af); loadJnetFile(af); loadPdbFiles(af); } public String getAppID(String frameType) { return j2sAppletID + (frameType == null ? "" : "-" + frameType); } // 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 (String) getAppletParameter(name, true); } @Override public Object getAppletParameter(String name, boolean asString) { return aparser.getAppletValue(name, null, asString); } /** * Get the applet-like code base even though this is an application. */ @Override public URL getCodeBase() { return Platform.getCodeBase(); } /** * Get the applet-like document base even though this is an application. */ @Override public URL getDocumentBase() { return Platform.getDocumentBase(); } @Override public Object getFrameForSource(VamsasSource source) { if (source != null) { AlignFrame af; if (source instanceof jalview.gui.AlignViewport && source == (af = Jalview.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 Hashtable getJSHashes() { return (jshashes == null ? (jshashes = new Hashtable<>()) : jshashes); } @Override public Hashtable> getJSMessages() { return (jsmessages == null ? (jsmessages = new Hashtable<>()) : jsmessages); } @Override public Object getJSObject() { return Jalview.getInstance(); } @Override public FeatureRenderer getNewFeatureRenderer(AlignViewportI vp) { return new jalview.gui.FeatureRenderer((AlignmentPanel) vp); } @Override public Object[] getSelectionForListener(SequenceGroup seqsel, ColumnSelection colsel, HiddenColumns hidden, SelectionSource source, Object alignFrame) { return getSelectionForListener(null, seqsel, colsel, hidden, source, alignFrame); } /** * scorefile * */ @Override public boolean loadScoreFile(String sScoreFile) throws IOException { return loadScoreFile(null, sScoreFile); } public boolean loadScoreFile(AlignFrame af, String sScoreFile) throws IOException { (af == null ? Jalview.getCurrentAlignFrame() : af).loadJalviewDataFile(sScoreFile, null, null, null); return true; } public void loadTree(AlignFrame af, NewickFile nf, String treeFile) throws IOException { if (af == null) af = Jalview.getCurrentAlignFrame(); af.getViewport() .setCurrentTree(af.showNewickTree(nf, treeFile).getTree()); } @Override public void newFeatureSettings() { System.err.println( "Jalview applet interface newFeatureSettings not implemented"); } // // // public void setAlignPdbStructures(boolean defaultParameter) // { // alignPDBStructures = true; // } // @Override public void newStructureView(PDBEntry pdb, SequenceI[] seqs, String[] chains, DataSourceType protocol) { newStructureView(null, pdb, seqs, chains, protocol); } public void newStructureView(AlignFrame af, PDBEntry pdb, SequenceI[] seqs, String[] chains, DataSourceType protocol) { StructureViewer.launchStructureViewer( (af == null ? Jalview.getCurrentAlignFrame() : af).alignPanel, pdb, seqs); } /** * features * @param af * */ @Override public boolean parseFeaturesFile(String filename, DataSourceType protocol) { return parseFeaturesFile(null, filename, protocol); } public boolean parseFeaturesFile(AlignFrame af, String filename, DataSourceType protocol) { return af.parseFeaturesFile(filename, protocol); } @Override public void setFeatureGroupState(String[] groups, boolean state) { setFeatureGroupState(null, groups, state); } public void setFeatureGroupState(AlignFrame af, String[] groups, boolean state) { (af == null ? Jalview.getCurrentAlignFrame() : af).setFeatureGroupState(groups, state); } /** * annotations, jpredfile, jnetfile * */ @Override public void updateForAnnotations() { updateForAnnotations(null); } public void updateForAnnotations(AlignFrame af) { (af == null ? Jalview.getCurrentAlignFrame() : af).updateForAnnotations(); } @Override public boolean addPdbFile(AlignFrame alf, String sequenceId, String pdbEntryString, String pdbFile) { if (alf == null) { alf = Jalview.getCurrentAlignFrame(); } SequenceI toaddpdb = alf.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); alf.alignPanel.getStructureSelectionManager() .registerPDBEntry(pdbentry); } } return true; } @Override public String arrayToSeparatorList(String[] array) { return arrayToSeparatorList(array, 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; } @Override public String getAlignment(String format) { return getAlignmentFrom(null, format, null); } @Override public String getAlignment(String format, String suffix) { return getAlignmentFrom(Jalview.getCurrentAlignFrame(), format, suffix); } @Override public String getAlignmentFrom(AlignFrame alf, String format) { return getAlignmentFrom(alf, format, null); } @Override public String getAlignmentFrom(AlignFrame alf, String format, String suffix) { try { if (alf == null) { alf = Jalview.getCurrentAlignFrame(); } boolean seqlimits = (suffix == null || suffix.equalsIgnoreCase("true")); FileFormatI theFormat = FileFormats.getInstance().forName(format); String reply = new AppletFormatAdapter().formatSequences(theFormat, alf.getViewport().getAlignment(), seqlimits); return reply; } catch (IllegalArgumentException ex) { ex.printStackTrace(); return "Error retrieving alignment, possibly invalid format specifier: " + format; } } @Override public String getAlignmentOrder() { return getAlignmentFrom(Jalview.getCurrentAlignFrame(), null); } @Override public String getAlignmentOrderFrom(AlignFrame alf) { return getAlignmentFrom(alf, null); } @Override public String getAlignmentOrderFrom(AlignFrame alf, String sep) { if (alf == null) { alf = Jalview.getCurrentAlignFrame(); } AlignmentI alorder = 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); } @Override public String getAnnotation() { return getAnnotationFrom(null); } @Override public String getAnnotationFrom(AlignFrame alf) { if (alf == null) { alf = Jalview.getCurrentAlignFrame(); } String annotation = new AnnotationFile() .printAnnotationsForView(alf.getViewport()); return annotation; } @Override public String getFeatureGroups() { return getFeatureGroupsOn(null); } @Override public String getFeatureGroupsOfState(boolean visible) { return getFeatureGroupsOfStateOn(null, visible); } @Override public String getFeatureGroupsOfStateOn(AlignFrame alf, boolean visible) { if (alf == null) { alf = Jalview.getCurrentAlignFrame(); } return arrayToSeparatorList(alf.getFeatureGroupsOfState(visible)); } @Override public String getFeatureGroupsOn(AlignFrame alf) { if (alf == null) { alf = Jalview.getCurrentAlignFrame(); } return arrayToSeparatorList(alf.getFeatureGroups()); } @Override public String getFeatures(String format) { return getFeaturesFrom(null, format); } /** * JavaScript interface to print the alignment frame * * @param alf * @param format * "jalview" or "gff" with or without ";includeComplement" or * ";includeNonpositional"; default with no ";" is * ";includeNonpositional" * @return */ @Override public String getFeaturesFrom(AlignFrame alf, String format) { if (alf == null) { alf = Jalview.getCurrentAlignFrame(); } String features; FeaturesFile formatter = new FeaturesFile(); format = format.toLowerCase(); if (format.indexOf(";") < 0) format += ";includenonpositional"; boolean nonpos = format.indexOf(";includenonpositional") > 0; boolean compl = format.indexOf(";includecomplement") >= 0; if (format.startsWith("jalview")) { features = formatter.printJalviewFormat( alf.getViewport().getAlignment().getSequencesArray(), alf.alignPanel.getFeatureRenderer(), nonpos, compl); } else { features = formatter.printGffFormat( alf.getViewport().getAlignment().getSequencesArray(), alf.alignPanel.getFeatureRenderer(), nonpos, compl); } if (features == null) { features = ""; } return features; } @Override public String getJsMessage(String messageclass, String viewId) { // TODO Auto-generated method stub return null; } /** * read sequence1...sequenceN as a raw alignment * * @param jalviewApp * @return */ public String getPastedSequence(JalviewJSApp jalviewApp) { StringBuffer data = new StringBuffer("PASTE"); int i = 1; String file = null; while ((file = (String) getAppletParameter("sequence" + i, true)) != null) { data.append(file.toString() + "\n"); i++; } if (data.length() > 5) { file = data.toString(); } return file; } /** * * @see jalview.appletgui.js.JalviewLiteJsApi#getSelectedSequences() */ @Override public String getSelectedSequences() { return getSelectedSequencesFrom(Jalview.getCurrentAlignFrame()); } /** * * @see jalview.appletgui.js.JalviewLiteJsApi#getSelectedSequences(java.lang.String) */ @Override public String getSelectedSequences(String sep) { return getSelectedSequencesFrom(Jalview.getCurrentAlignFrame(), sep); } @Override public String getSelectedSequencesAsAlignment(String format, String suffix) { return getSelectedSequencesAsAlignmentFrom(null, format, suffix); } @Override public String getSelectedSequencesAsAlignmentFrom(AlignFrame alf, String format, String suffix) { if (alf == null) { alf = Jalview.getCurrentAlignFrame(); } boolean seqlimits = (suffix == null || suffix.equalsIgnoreCase("true")); try { AlignViewport vp = alf.getViewport(); FileFormatI theFormat = FileFormats.getInstance().forName(format); 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 ""; } /** * * @see jalview.appletgui.js.JalviewLiteJsApi#getSelectedSequencesFrom(jalview.appletgui * .AlignFrame) */ @Override public String getSelectedSequencesFrom(AlignFrame alf) { return getSelectedSequencesFrom(alf, null); } @Override public String getSelectedSequencesFrom(AlignFrame alf, String sep) { if (alf == null) { alf = Jalview.getCurrentAlignFrame(); } StringBuffer result = new StringBuffer(""); if (sep == null || sep.length() == 0) { sep = separator; // "+0x00AC; } AlignViewport v = 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 Object[] getSelectionForListener(AlignFrame alf, SequenceGroup seqsel, ColumnSelection colsel, HiddenColumns hidden, SelectionSource source, Object alignFrame) { if (alf == null) { alf = Jalview.getCurrentAlignFrame(); } // System.err.println("Testing selection event relay to // jsfunction:"+_listener); String setid = ""; AlignFrame src = (AlignFrame) alignFrame; if (source != null) { if (source instanceof AlignViewport && alf.getViewport() == source) { // should be valid if it just generated an event! src = alf; } } 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 getSeparator() { return separator; } /** * * @see jalview.appletgui.js.JalviewLiteJsApi#getSelectedSequencesFrom(jalview.appletgui * .AlignFrame, java.lang.String) */ @Override public void highlight(String sequenceId, String position, String alignedPosition) { highlightIn(null, sequenceId, position, alignedPosition); } @Override public void highlightIn(AlignFrame alf, final String sequenceId, final String position, final String alignedPosition) { if (alf == null) { alf = Jalview.getCurrentAlignFrame(); } // TODO: could try to highlight in all alignments if alf==null jalview.analysis.SequenceIdMatcher matcher = new jalview.analysis.SequenceIdMatcher( alf.getViewport().getAlignment().getSequencesArray()); final SequenceI sq = matcher.findIdMatch(sequenceId); if (sq != null) { int apos = -1; try { apos = Integer.valueOf(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 AlignFrame 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 void setMouseoverListener(String listener) // { // appLoader.setMouseoverListener(listener); // } // // // public void setMouseoverListener(AlignFrame af, String listener) // { // } // @Override public AlignFrame loadAlignment(String text, String title) { return loadAlignment(text, AlignFrame.DEFAULT_WIDTH, AlignFrame.DEFAULT_HEIGHT, title); } @Override public void loadAnnotation(String annotation) { loadAnnotationFrom(null, annotation); } @Override public void loadAnnotationFrom(AlignFrame alf, String annotation) { if (alf == null) { alf = Jalview.getCurrentAlignFrame(); } if (new AnnotationFile().annotateAlignmentView(alf.getViewport(), annotation, DataSourceType.PASTE)) { alf.alignPanel.fontChanged(); alf.alignPanel.setScrollValues(0, 0); } else { alf.parseFeaturesFile(annotation, DataSourceType.PASTE); } } /** * Load annotations if specified by parameter. Returns true if loaded, else * false. * * * @param alignFrame * @return */ protected boolean loadAnnotations(AlignFrame af) { boolean result = false; String param = (String) getAppletParameter("annotations", true); if (param != null) { ret[0] = param; DataSourceType protocol = resolveFileProtocol(ret); param = ret[0]; if (new AnnotationFile().annotateAlignmentView(af.getViewport(), param, protocol)) { updateForAnnotations(); result = true; } else { System.err .println("Annotations were not added from annotation file '" + param + "'"); } } return result; } //// JalviewJSApi /** * Load features file and view settings as specified by parameters. Returns * true if features were loaded, else false. * @param * * @param alignFrame * @return */ protected boolean loadFeatures(AlignFrame af) { 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 = (String) getAppletParameter("hidefeaturegroups", true); if (param != null) { setFeatureGroupState(af, separatorListToArray(param, separator), false); // setFeatureGroupStateOn(newAlignFrame, param, false); } // show specific groups param = (String) getAppletParameter("showfeaturegroups", true); if (param != null) { setFeatureGroupState(af, separatorListToArray(param, separator), true); // setFeatureGroupStateOn(newAlignFrame, param, true); } // and now load features param = (String) getAppletParameter("features", true); if (param != null) { ret[0] = param; DataSourceType protocol = resolveFileProtocol(ret); result = parseFeaturesFile(af, ret[0], protocol); } param = (String) getAppletParameter("showFeatureSettings", true); if (param != null && param.equalsIgnoreCase("true")) { newFeatureSettings(); } return result; } @Override public void loadFeatures(String features, boolean autoenabledisplay) { loadFeaturesFrom(null, features, autoenabledisplay); } @Override public boolean loadFeaturesFrom(AlignFrame alf, String features, boolean autoenabledisplay) { if (alf == null) { alf = Jalview.getCurrentAlignFrame(); } boolean ret = alf.parseFeaturesFile(features, DataSourceType.PASTE); if (!ret) { return false; } if (autoenabledisplay) { alf.getViewport().setShowSequenceFeatures(true); // this next was for a checkbox in JalviewLite // ((AlignFrame) alf).getViewport().sequenceFeatures.setState(true); } return true; } /** * Load in a Jnetfile if specified by parameter. Returns true if loaded, else * false. * * @param alignFrame * @return */ protected boolean loadJnetFile(AlignFrame af) { boolean result = false; String param = (String) getAppletParameter("jnetfile", true); if (param == null) { // jnet became jpred around 2016 param = (String) getAppletParameter("jpredfile", true); } if (param != null) { try { ret[0] = param; DataSourceType protocol = resolveFileProtocol(ret); JPredFile predictions = new JPredFile(ret[0], protocol); JnetAnnotationMaker.add_annotation(predictions, af.getViewport().getAlignment(), 0, false); // false == do not add sequence profile from concise output af.getViewport().getAlignment().setupJPredAlignment(); updateForAnnotations(); result = true; } catch (Exception ex) { ex.printStackTrace(); } } return result; } /** * Load PDBFiles if any specified by parameter(s). Returns true if loaded, * else false. * * @param loaderFrame * @return */ protected boolean loadPdbFiles(AlignFrame af) { boolean result = false; /* * Undocumented for 2.6 - * related to JAL-434 */ // not supported (as for JalviewLite) // boolean doAlign = false;//"true".equalsIgnoreCase("" + // getAppletParameter("alignpdbfiles", false)); // setAlignPdbStructures(doAlign); /* * * * * * */ // Accumulate pdbs here if they are heading for the same view (if // alignPdbStructures is true) // ArrayList pdbs = new ArrayList<>(); // create a lazy matcher if we're asked to boolean relaxed = "true".equalsIgnoreCase( "" + getAppletParameter("relaxedidmatch", false)); jalview.analysis.SequenceIdMatcher matcher = relaxed ? new jalview.analysis.SequenceIdMatcher( af.getViewport().getAlignment().getSequencesArray()) : null; int pdbFileCount = 0; String param; do { if (pdbFileCount > 0) { param = (String) getAppletParameter("PDBFILE" + pdbFileCount, true); } else { param = (String) getAppletParameter("PDBFILE", true); } 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 = (String) getAppletParameter("PDBSEQ", true); if (sequence != null) { seqs = new SequenceI[] { matcher == null ? (Sequence) af.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) af.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(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) this) .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.add(new Object[] { pdb, seqs, chains, protocol }); // } // else { newStructureView(af, pdb, seqs, chains, protocol); } } } pdbFileCount++; } while (param != null || pdbFileCount < 10); // // if (doAlign && 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.get(pdbsi); // pdb[pdbsi] = (PDBEntry) o[0]; // seqs[pdbsi] = (SequenceI[]) o[1]; // chains[pdbsi] = (String[]) o[2]; // protocols[pdbsi] = (String) o[3]; // } //// alignedStructureView(pdb, seqs, chains, protocols); // result = true; // } 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 = (String) getAppletParameter("scoreFile", true); if (sScoreFile != null && !"".equals(sScoreFile)) { try { if (debug) { System.err.println( "Attempting to load T-COFFEE score file from the scoreFile parameter"); } result = 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. * * @return */ protected boolean loadTree(AlignFrame af) { boolean result = false; String treeFile = (String) getAppletParameter("tree", true); if (treeFile == null) { treeFile = (String) getAppletParameter("treefile", true); } if (treeFile != null) { try { ret[0] = treeFile; NewickFile fin = new NewickFile(treeFile, resolveFileProtocol(ret)); fin.parse(); if (fin.getTree() != null) { loadTree(af, 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; } /** * 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) { if (af == null) { af = Jalview.getCurrentAlignFrame(); } return CalculationChooser.openPcaPanel(af, modelName, 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) { if (af == null) { af = Jalview.getCurrentAlignFrame(); } return CalculationChooser.openTreePanel(af, treeType, modelName, null); } @Override public String orderAlignmentBy(AlignFrame alf, String order, String undoName, String sep) { if (sep == null || sep.length() == 0) { sep = separator; } String[] ids = separatorListToArray(order, sep); SequenceI[] sqs = null; if (ids != null && ids.length > 0) { if (alf == null) { alf = Jalview.getCurrentAlignFrame(); } jalview.analysis.SequenceIdMatcher matcher = new jalview.analysis.SequenceIdMatcher( 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 alf.sortBy(aorder, _undoName) ? "true" : ""; } @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(Jalview.getCurrentAlignFrame(), order, undoName, sep); } /** * 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 { Jalview.getInstance().parseArguments(new ArgsParser(args), false); return null; } catch (Throwable t) { return t; } } @Override public void removeSelectionListener(AlignFrame af, String listener) { List listeners = Desktop .getStructureSelectionManager().getListeners(); for (int i = listeners.size(); --i >= 0;) { SelectionListener l = listeners.get(i); if (l instanceof JsSelectionListener && ((JsSelectionListener) l).isFor(af, listener)) { listeners.remove(i); break; } } } @Override public void scrollViewToColumnIn(final AlignFrame alf, final String leftHandColumn) { java.awt.EventQueue.invokeLater(new Runnable() { @Override public void run() { try { (alf == null ? Jalview.getCurrentAlignFrame() : alf) .scrollToColumn( Integer.valueOf(leftHandColumn).intValue()); } catch (Exception ex) { System.err.println( "Couldn't parse integer arguments (leftHandColumn='" + leftHandColumn + "')"); ex.printStackTrace(); } } }); } @Override public void scrollViewToIn(final AlignFrame alf, final String topRow, final String leftHandColumn) { // TODO test java.awt.EventQueue.invokeLater(new Runnable() { @Override public void run() { try { (alf == null ? Jalview.getCurrentAlignFrame() : alf).scrollTo( Integer.valueOf(topRow).intValue(), Integer.valueOf(leftHandColumn).intValue()); } catch (Exception ex) { System.err.println("Couldn't parse integer arguments (topRow='" + topRow + "' and leftHandColumn='" + leftHandColumn + "')"); ex.printStackTrace(); } } }); } @Override public void scrollViewToRowIn(final AlignFrame alf, final String topRow) { // TODO test java.awt.EventQueue.invokeLater(new Runnable() { @Override public void run() { try { (alf == null ? Jalview.getCurrentAlignFrame() : alf) .scrollToRow(Integer.valueOf(topRow).intValue()); } catch (Exception ex) { System.err.println("Couldn't parse integer arguments (topRow='" + topRow + "')"); ex.printStackTrace(); } } }); } @Override public void select(String sequenceIds, String columns) { selectIn(Jalview.getCurrentAlignFrame(), sequenceIds, columns, null); } @Override public void select(String sequenceIds, String columns, String sep) { selectIn(null, sequenceIds, columns, sep); } // @Override // public AlignFrame newView() // { // return newViewFrom(null, null); // } // // @Override // public AlignFrame newView(String name) // { // return newViewFrom(null, name); // } // // @Override // public AlignFrame newViewFrom(AlignFrame alf) // { // return newViewFrom(alf, null); // } // // @Override // public AlignFrame newViewFrom(AlignFrame alf, String name) // { // if (alf == null) // { // alf = Jalview.getCurrentAlignFrame(); // } // return appLoader.newViewFrom(alf, name); // } @Override public void selectIn(AlignFrame alf, String sequenceIds, String columns) { selectIn(alf, sequenceIds, columns, null); } @Override public void selectIn(AlignFrame af, String sequenceIds, String columns, String sep) { AlignFrame alf = (af == null ? Jalview.getCurrentAlignFrame() : af); if (sep == null || sep.length() == 0) { sep = separator; } else { if (debug) { System.err.println("Selecting region using separator string '" + separator + "'"); } } // deparse fields String[] ids = separatorListToArray(sequenceIds, sep); String[] cols = separatorListToArray(columns, sep); final SequenceGroup sel = new SequenceGroup(); final ColumnSelection csel = new ColumnSelection(); AlignmentI al = alf.getViewport().getAlignment(); jalview.analysis.SequenceIdMatcher matcher = new jalview.analysis.SequenceIdMatcher( 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 = Integer.valueOf(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 = Integer.valueOf(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 = Integer.valueOf(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() { alf.select(sel, csel, alf.getCurrentView().getAlignment().getHiddenColumns()); } }); } } // public AlignFrame newViewFrom(AlignFrame alf, String name) // { // return (AlignFrame) alf.newView(name, true); // } // @Override public String[] separatorListToArray(String list) { return separatorListToArray(list, separator); } @Override public void setFeatureGroupState(String groups, boolean state) { // JalviewLite API setFeatureGroupStateOn(null, groups, state); } @Override public void setFeatureGroupStateOn(final AlignFrame alf, final String groups, boolean state) { java.awt.EventQueue.invokeLater(new Runnable() { @Override public void run() { (alf == null ? Jalview.getCurrentAlignFrame() : alf) .setFeatureGroupState( separatorListToArray(groups, separator), state); } }); } @Override public void setSelectionListener(AlignFrame af, String listener) { Desktop.getStructureSelectionManager() .addSelectionListener(new JsSelectionListener(af, listener)); } @Override public void setSelectionListener(String listener) { Desktop.getStructureSelectionManager() .addSelectionListener(new JsSelectionListener(null, listener)); } @Override public void setSeparator(String separator) { this.separator = separator; } @Override public void showOverview() { Jalview.getCurrentAlignFrame().overviewMenuItem_actionPerformed(null); } /** * Allowing for a JavaScript function here. */ public void callInitCallback() { Object initjscallback = getAppletParameter("oninit", false); if (initjscallback != null) { try { doSendCallback(initjscallback, new Object[0]); } catch (Exception e) { System.err.println("Exception when executing _oninit callback '" + initjscallback + "'."); e.printStackTrace(); } } } /** * Pass the provided array prepended with Jalview.this * * Appropriated from org.jmol.appletjs.Jmol * * @param callback * a window function or "alert" * @param data * @return String return from the callback method. */ public String doSendCallback(Object callback, Object[] data) { Jalview me = Jalview.getInstance(); if (me != null && callback != null) { /** * @j2sNative * * try{ * * if (callback == "alert") { alert(data[0]); return ""; } var * o; if (typeof callback == "function") { o = callback; } else * { if (!callback)return; var tokens = callback.split("."); o * = window[tokens[0]]; for (var i = 1; i < tokens.length; i++) * o = o[tokens[i]]; } var a = [me]; for (var i = 0; i < * data.length; i++) a.push(data[i] ? data[i].booleanValue && * (data[i] = data[i].booleanValue()) : data[i]); return * o.apply(null,a) } catch (e) { System.out.println(callback + * " failed " + e); } */ } return ""; } private DataSourceType resolveFileProtocol(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 = 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 = 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(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); return rtn; } catch (Exception ex) { System.out.println("Exception checking resources: " + f + " " + ex); return false; } } /** * 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(); return v; } return null; } public class JsSelectionListener implements jalview.structure.SelectionListener { AlignFrame _af; String _listener; public JsSelectionListener(AlignFrame af, String listener) { _af = af; _listener = listener; } @Override public void selection(SequenceGroup seqsel, ColumnSelection colsel, HiddenColumns hidden, SelectionSource source) { // System.err.println("Testing selection event relay to // jsfunction:"+_listener); String setid = ""; AlignFrame src = _af; if (source != null) { if (source instanceof AlignViewport && Jalview.getCurrentAlignFrame().getViewport() == source) { src = Jalview.getCurrentAlignFrame(); if (src != _af) return; } } 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); } ; } Jalview jalview = Jalview.getInstance(); jalview.doSendCallback(_listener, new Object[] { src, setid, jalview.arrayToSeparatorList(seqs), jalview.arrayToSeparatorList(cols) }); } public boolean isFor(AlignFrame af, String listener) { return _af == af && _listener.contentEquals(listener); } } @Override public AlignViewportI getViewport() { return Jalview.getCurrentAlignFrame().getViewport(); } }