X-Git-Url: http://source.jalview.org/gitweb/?a=blobdiff_plain;f=src%2Fjalview%2Fbin%2FJalviewJSApp.java;fp=src%2Fjalview%2Fbin%2FJalviewJSApp.java;h=feab4ae6da5efcbc671eb63cffe8f638a5da582d;hb=586ade46bdcd05ff028a1cff82c3c527326d28ec;hp=0000000000000000000000000000000000000000;hpb=adcef27f5747b4e70e89a56c3735bc3afb8ce9bf;p=jalview.git diff --git a/src/jalview/bin/JalviewJSApp.java b/src/jalview/bin/JalviewJSApp.java new file mode 100644 index 0000000..feab4ae --- /dev/null +++ b/src/jalview/bin/JalviewJSApp.java @@ -0,0 +1,1691 @@ +package jalview.bin; + +import java.awt.EventQueue; +//import java.applet.AppletContext; +import java.io.IOException; +import java.net.URL; +import java.util.ArrayList; +import java.util.List; +import java.util.StringTokenizer; +import java.util.Vector; + +import javax.swing.SwingUtilities; + +import jalview.api.JalviewJSApi; +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.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.structure.SelectionListener; +import jalview.structure.SelectionSource; +import jalview.structure.StructureSelectionManager; +import jalview.util.HttpUtils; +import jalview.util.Platform; + +/** + * Basically the JalviewLite application, but without JalviewLite + * + * Processing all "applet parameters" and also all "applet interface" methods. + * + * @author hansonr + * + */ +public class JalviewJSApp implements JalviewJSApi +{ + private ArgsParser aparser; + + private String[] ret = new String[1]; + + // private boolean alignPDBStructures; From JalviewLite; not implemented + + private String separator = "\u00AC"; // JalviewLite note: the default used to + // be '|', but many sequence IDS include + // pipes. + + /** + * We maintain a pointer to the jalview instance here, because only with that + * do we have a direct connection from the JavaScript "applet" object to the + * proper instance of Jalview in case there are multiple applets on a page. + */ + private Jalview jalview; + + public class JsSelectionListener + implements jalview.structure.SelectionListener + { + + AlignFrame _alf; + + String _listener; + + public JsSelectionListener(AlignFrame alf, String listener) + { + _alf = alf; + _listener = listener; + } + + public boolean isFor(AlignFrame alf, String listener) + { + return (_alf == null || _alf == alf) && _listener.equals(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 srcFrame = (_alf == null ? getCurrentAlignFrame() : _alf); + if (source != null) + { + if (source instanceof AlignViewport + && srcFrame.getViewport() != source) + { + return; + } + } + String[] seqs = new String[] {}; + String[] cols = new String[] {}; + int strt = 0, end = (srcFrame == null) ? -1 + : srcFrame.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[1]; + cols[0] = "" + (1 + strt) + "-" + (1 + end); + } + } + doSendCallback(_listener, + new Object[] + { Jalview.getInstance().j2sAppletID, srcFrame, source, setid, + seqs, cols }); + } + + } + + public JalviewJSApp(Jalview jalview, ArgsParser aparser) + { + Platform.setAppClass(this); + this.jalview = jalview; + this.aparser = aparser; + } + + @Override + public boolean addPdbFile(String sequenceId, String pdbId, String pdbFile, + AlignFrame alf) + { + if (alf == null) + { + alf = getCurrentAlignFrame(); + } + SequenceI seq = alf.getViewport().getAlignment().findName(sequenceId); + if (seq != null) + { + Vector pdbe = seq.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(pdbId) + || pdbFile != null && !pdbentry.getFile().equals(pdbFile)) + { + pdbentry = null; + } + } + } + if (pdbentry == null) + { + pdbentry = new PDBEntry(pdbId, null, pdbFile); + if (pdbFile != null) + { + DataSourceType protocol = AppletFormatAdapter + .resolveProtocol(pdbFile, FileFormat.PDB); + if (protocol == null) + return false; + pdbentry.setProperty("protocol", protocol); + } + seq.addPDBId(pdbentry); + alf.alignPanel.getStructureSelectionManager() + .registerPDBEntry(pdbentry); + } + } + return true; + } + + @Override + public String getAlignment(String format, boolean addSuffix, + AlignFrame alf) + { + try + { + if (alf == null) + { + alf = getCurrentAlignFrame(); + } + + FileFormatI theFormat = FileFormats.getInstance().forName(format); + String reply = new AppletFormatAdapter().formatSequences(theFormat, + alf.getViewport().getAlignment(), addSuffix); + return reply; + } catch (IllegalArgumentException ex) + { + ex.printStackTrace(); + return "Error retrieving alignment, possibly invalid format specifier: " + + format; + } + } + + @Override + public String[] getAlignmentOrder(AlignFrame alf) + { + if (alf == null) + { + alf = 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 order;// arrayToSeparatorList(order, sep); + } + + @Override + public String getAnnotation(AlignFrame alf) + { + if (alf == null) + { + alf = getCurrentAlignFrame(); + } + String annotation = new AnnotationFile() + .printAnnotationsForView(alf.getViewport()); + return annotation; + } + + /** + * Get the applet-like code base even though this is an application. + */ + + @Override + public URL getCodeBase() + { + return Platform.getCodeBase(); + } + + @Override + public AlignFrame getCurrentAlignFrame() + { + // if (jalview != Jalview.getInstance() || jalview.currentAlignFrame != + // Jalview.getCurrentAlignFrame()) { + // /** @j2sNative debugger */ + // } + return jalview.currentAlignFrame; + } + + /** + * Get the applet-like document base even though this is an application. + */ + + @Override + public URL getDocumentBase() + { + return Platform.getDocumentBase(); + } + + @Override + public String[] getFeatureGroups(AlignFrame alf) + { + if (alf == null) + { + alf = getCurrentAlignFrame(); + } + return alf.getFeatureGroups(); + } + + @Override + public String[] getFeatureGroupsOfState(boolean visible, AlignFrame alf) + { + if (alf == null) + { + alf = getCurrentAlignFrame(); + } + return alf.getFeatureGroupsOfState(visible); + } + + /** + * JavaScript interface to print the alignment frame + * + * @param format + * "jalview" or "gff" with or without ";includeComplement" or + * ";includeNonpositional"; default with no ";" is + * ";includeNonpositional" + * @param alf + * + * @return + */ + @Override + public String getFeatures(String format, AlignFrame alf) + { + if (alf == null) + { + alf = 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; + + } + + /** + * Get an applet parameter as a string. + * + */ + @Override + public String getParameter(String name) + { + return (String) aparser.getAppletValue(name, null, true); + } + + /** + * Get an applet parameter as an Object. + */ + + @Override + public Object getParameterAsObject(String name) + { + return aparser.getAppletValue(name, null, false); + } + + /** + * 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 = getParameter("sequence" + i)) != null) + { + data.append(file.toString() + "\n"); + i++; + } + if (data.length() > 5) + { + file = data.toString(); + } + return file; + } + + /** + * @j2sAlias getSelectedSequences + * + * @see jalview.appletgui.js.JalviewLiteJsApi#getSelectedSequencesFrom(jalview.appletgui + * .AlignFrame) + */ + @Override + public SequenceI[] getSelectedSequences(AlignFrame alf) + { + // return getSelectedSequencesFrom(alf, null); + // } + // + // @Override + // public SequenceI[] getSelectedSequencesFrom(AlignFrame alf, String sep) + // { + if (alf == null) + { + alf = getCurrentAlignFrame(); + } + AlignViewport v = alf.getViewport(); + if (v.getSelectionGroup() != null) + { + return v.getSelectionGroup().getSequencesInOrder(v.getAlignment()); + } + return null; + } + // /** + // * + // * @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); + // } + + /** + * @j2sAlias getSelectedSequencesAsAlignment + */ + @Override + public String getSelectedSequencesAsAlignment(String format, + boolean addSuffix, AlignFrame alf) + { + + if (alf == null) + { + alf = getCurrentAlignFrame(); + } + 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()), addSuffix); + return reply; + } + } catch (IllegalArgumentException ex) + { + ex.printStackTrace(); + return "Error retrieving alignment, possibly invalid format specifier: " + + format; + } + return ""; + } + + @Override + public void highlight(String sequenceId, String position, + String alignedPosition, AlignFrame alf) + { + if (alf == null) + { + alf = 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); + } + }); + } + } + } + + @Override + public AlignFrame loadAlignment(String text, String title, int width, + int height) + { + 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 > 0 ? width : AlignFrame.DEFAULT_WIDTH, + height > 0 ? height : AlignFrame.DEFAULT_HEIGHT, title); + } + } catch (IOException ex) + { + ex.printStackTrace(); + } + return null; + } + + @Override + public void loadAnnotation(String annotation, AlignFrame alf) + { + if (alf == null) + { + alf = getCurrentAlignFrame(); + } + if (new AnnotationFile().annotateAlignmentView(alf.getViewport(), + annotation, DataSourceType.PASTE)) + { + alf.alignPanel.fontChanged(); + alf.alignPanel.setScrollValues(0, 0); + } + else + { + alf.parseFeaturesFile(annotation, DataSourceType.PASTE); + } + } + + @Override + public boolean loadFeatures(String features, boolean autoenabledisplay, + AlignFrame alf) + { + if (alf == null) + { + alf = 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; + } + + @Override + public boolean loadScoreFile(String fileName, AlignFrame alf) + { + try + { + (alf == null ? getCurrentAlignFrame() : alf) + .loadJalviewDataFile(fileName, null, null, null); + return true; + } catch (Throwable t) + { + return false; + } + } + + /** + * @j2sAlias openPcaPanel + * + * public static method for JalviewJS API to open a PCAPanel without + * necessarily using a dialog. + * @param modelName + * @param alf + * + * @return the PCAPanel, or the string "label.you_need_at_least_n_sequences" + * if number of sequences selected is inappropriate + */ + @Override + public Object openPcaPanel(String modelName, AlignFrame alf) + { + if (alf == null) + { + alf = getCurrentAlignFrame(); + } + return CalculationChooser.openPcaPanel(alf, modelName, null); + } + + /** + * @j2sAlias openTreePanel + * + * Open a new Tree panel on the desktop statically. Params are + * standard (not set by Groovy). No dialog is opened. + * @param treeType + * @param modelName + * @param alf + * + * @return null, or the string "label.you_need_at_least_n_sequences" if number + * of sequences selected is inappropriate + */ + @Override + public Object openTreePanel(String treeType, String modelName, + AlignFrame alf) + { + if (alf == null) + { + alf = getCurrentAlignFrame(); + } + return CalculationChooser.openTreePanel(alf, treeType, modelName, null); + } + + @Override + public boolean orderAlignment(String[] ids, String undoName, + AlignFrame alf) + { + if (alf == null) + alf = getCurrentAlignFrame(); + SequenceI[] sqs = null; + if (ids != null && ids.length > 0) + { + 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 false; + } + ; + 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 + // alfter + // this has returned. + return alf.sortBy(aorder, _undoName); + } + + /** + * 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.parseArguments(new ArgsParser(args), false); + return null; + } catch (Throwable t) + { + return t; + } + } + + /** + * @j2sAlias parseFeatureFile + * + * @param filename + * @param alf + * @return + */ + @Override + public boolean parseFeaturesFile(String filename, AlignFrame alf) + { + ret[0] = filename; + DataSourceType protocol = resolveFileProtocol(ret); + if (protocol == null) + return false; + return (alf == null ? getCurrentAlignFrame() : alf) + .parseFeaturesFile(ret[0], protocol); + } + + @Override + public void removeSelectionListener(String listener, AlignFrame alf) + { + + List listeners = Desktop + .getStructureSelectionManager().getListeners(); + for (int i = listeners.size(); --i >= 0;) + { + SelectionListener l = listeners.get(i); + if (l instanceof JsSelectionListener + && ((JsSelectionListener) l).isFor(alf, listener)) + { + listeners.remove(i); + break; + } + } + } + + 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; + } + + @Override + public void scrollViewTo(int topRow, int leftHandColumn, AlignFrame alf) + { + // TODO test + java.awt.EventQueue.invokeLater(new Runnable() + { + @Override + public void run() + { + try + { + (alf == null ? getCurrentAlignFrame() : alf).scrollTo(topRow, + leftHandColumn); + } catch (Exception ex) + { + System.err.println("Couldn't parse integer arguments (topRow='" + + topRow + "' and leftHandColumn='" + leftHandColumn + + "')"); + ex.printStackTrace(); + } + } + }); + } + + @Override + public void select(String ids[], String cols[], AlignFrame alf) + { + if (alf == null) + alf = getCurrentAlignFrame(); + 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); + } + } + } + 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); + } + 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); + AlignFrame af = alf; + EventQueue.invokeLater(new Runnable() + { + @Override + public void run() + { + af.select(sel, csel, + af.getCurrentView().getAlignment().getHiddenColumns()); + } + }); + } + } + + // + // @Override + // public void setFeatureGroupState(String[] groups, boolean state) + // { + // setFeatureGroupState(null, groups, state); + // } + // + // @Override + // public void setFeatureGroupState(String[] groups, boolean state) + // { // JalviewLite API + // setFeatureGroupStateOn(null, groups, state); + // } + // + @Override + public void setFeatureGroupState(final String[] groups, + boolean state, AlignFrame alf) + { + // setFeatureGroupState(alf, groups, state); + // java.awt.EventQueue.invokeLater(new Runnable() + // { + // @Override + // public void run() + // { + // (alf == null ? getCurrentAlignFrame() : alf) + // .setFeatureGroupState( + // separatorListToArray(groups, separator), state); + // } + // }); + // } + // + // public void setFeatureGroupState(AlignFrame alf, String[] groups, boolean + // state) { + (alf == null ? getCurrentAlignFrame() : alf) + .setFeatureGroupState(groups, state); + } + + @Override + public void setSelectionListener(String listener, AlignFrame alf) + { + Desktop.getStructureSelectionManager() + .addSelectionListener(new JsSelectionListener(alf, listener)); + } + + @Override + public void showOverview() + { + getCurrentAlignFrame().overviewMenuItem_actionPerformed(null); + } + + /** + * @j2sAlias showStructure + */ + @Override + public void showStructure(String pdbID, String fileType, AlignFrame alf) + { + if (alf == null) + alf = getCurrentAlignFrame(); + PDBEntry pe = null; + SequenceI[] seqs = null; + if (pdbID == null) + { + seqs = alf.getViewport().getSequenceSelection(); + if (seqs.length == 0) + seqs = alf.getViewport().getAlignment().getSequencesArray(); + for (int i = 0; i < seqs.length; i++) + { + Vector list = seqs[i].getAllPDBEntries(); + if (list.size() > 0) + { + pe = list.get(0); + break; + } + } + } + if (pe == null) + { + if (pdbID == null) + return; + pe = new PDBEntry(pdbID, null, fileType); + List list = alf.getViewport().getAlignment() + .getSequences(); + List tmp = new ArrayList(); + for (int i = 0; i < list.size(); i++) + { + SequenceI seq = list.get(i); + if (seq.getPDBEntry(pdbID) != null) + { + tmp.add(seq); + } + } + seqs = tmp.toArray(new SequenceI[tmp.size()]); + alf.alignPanel.selectSequences(tmp); + } + StructureViewer.launchStructureViewer(alf.alignPanel, pe, seqs); + } + + // private or package-private methods + + /** + * 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 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 + */ + private 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; + } + + /** + * 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; + } + } + + /** + * Allowing for a JavaScript function here. + */ + void callInitCallback() + { + Object initjscallback = getParameterAsObject("oninit"); + if (initjscallback != null) + { + SwingUtilities.invokeLater(new Runnable() { + + @Override + public void run() + { + try + { + doSendCallback(initjscallback, new Object[] {this}); + } 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. + */ + String doSendCallback(Object callback, Object[] data) + { + Jalview me = jalview; + + 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 ""; + } + + /** + * Initialize from Info.key/value pairs that match the old JalviewLite applet + * parameters. + * + * See http://www.jalview.org/old/v2_8/examples/appletParameters.html + * + * Note that some of these parameters are handled as command-line arguments, + * as determined in ArgsParser. + * + * @param alf + */ + void initFromParams(AlignFrame alf) + { + String sep = getParameter("separator"); + if (sep != null && sep.length() > 0) + { + separator = sep; + } + initTree(alf); + initScoreFile(alf); + initFeatures(alf); + initAnnotations(alf); + initJnetFile(alf); + initPdbFiles(alf); + } + + /** + * Load annotations if specified by parameter. Returns true if loaded, else + * false. + * + * + * @param alignFrame + * @return + */ + private boolean initAnnotations(AlignFrame alf) + { + + String param = getParameter("annotations"); + if (param == null) + return false; + ret[0] = param; + DataSourceType protocol = resolveFileProtocol(ret); + param = ret[0]; + if (!new AnnotationFile().annotateAlignmentView(alf.getViewport(), + param, protocol)) + { + System.err.println("Annotations were not added from annotation file '" + + param + "'"); + return false; + } + updateForAnnotations(); + return true; + } + + /** + * Load features file and view settings as specified by parameters. Returns + * true if features were loaded, else false. + * + * @param + * + * @param alignFrame + * @return + */ + private boolean initFeatures(AlignFrame alf) + { + + // /////////////////////////// + // 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 = getParameter("hidefeaturegroups"); + if (param != null) + { + setFeatureGroupState(separatorListToArray(param, separator), + false, alf); + // setFeatureGroupStateOn(newAlignFrame, param, false); + } + // show specific groups + param = getParameter("showfeaturegroups"); + if (param != null) + { + setFeatureGroupState(separatorListToArray(param, separator), + true, alf); + // setFeatureGroupStateOn(newAlignFrame, param, true); + } + // and now load features + param = getParameter("features"); + if (param == null) + { + return false; + } + if (!parseFeaturesFile(param, alf)) + return false; + param = getParameter("showFeatureSettings"); + if (param != null && param.equalsIgnoreCase("true")) + { + alf.showFeatureSettingsUI(); + } + return true; + } + + /** + * Load in a Jnetfile if specified by parameter. Returns true if loaded, else + * false. + * + * @param alignFrame + * @return + */ + private boolean initJnetFile(AlignFrame alf) + { + + String param = getParameter("jnetfile"); + if (param == null) + { + // jnet became jpred around 2016 + param = getParameter("jpredfile"); + } + if (param != null) + { + try + { + ret[0] = param; + DataSourceType protocol = resolveFileProtocol(ret); + JPredFile predictions = new JPredFile(ret[0], protocol); + JnetAnnotationMaker.add_annotation(predictions, + alf.getViewport().getAlignment(), 0, false); + // false == do not add sequence profile from concise output + alf.getViewport().getAlignment().setupJPredAlignment(); + updateForAnnotations(); + } catch (Exception ex) + { + ex.printStackTrace(); + return false; + } + } + return true; + } + + /** + * Load PDBFiles if any specified by parameter(s). Returns true if loaded, + * else false. + * + * @param loaderFrame + * @return + */ + private boolean initPdbFiles(AlignFrame alf) + { + + /* + * 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<>(); + // init a lazy matcher if we're asked to + boolean relaxed = "true" + .equalsIgnoreCase(getParameter("relaxedidmatch")); + jalview.analysis.SequenceIdMatcher matcher = relaxed + ? new jalview.analysis.SequenceIdMatcher( + alf.getViewport().getAlignment().getSequencesArray()) + : null; + + String param = getParameter("PDBFILE"); + int plast = (param == null ? 9 : 1); + if (param == null && (param = getParameter("PDBFILE1")) == null) + { + return false; + } + for (int p = 1; p <= plast; p++) + { + if (p > 1) + { + param = getParameter("PDBFILE" + p); + if (param == null) + break; + } + PDBEntry pdb = new PDBEntry(); + + String seqstring; + SequenceI[] seqs = null; + String[] chains = null; + + StringTokenizer st = new StringTokenizer(param, " "); + + if (st.countTokens() < 2) + { + String sequence = getParameter("PDBSEQ"); + if (sequence != null) + { + seqs = new SequenceI[] { matcher == null + ? (Sequence) alf.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) alf.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); + } + } + + // if (doAlign) + // { + // pdbs.add(new Object[] { pdb, seqs, chains, protocol }); + // } + // else + { + StructureViewer.launchStructureViewer( + (alf == null ? getCurrentAlignFrame() : alf).alignPanel, + pdb, seqs); + } + } + } + // + // 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 true; + } + + /** + * Load a score file if specified by parameter. Returns true if file was + * loaded, else false. + * + * @param loaderFrame + */ + private boolean initScoreFile(AlignFrame alf) + { + + String sScoreFile = getParameter("scoreFile"); + if (sScoreFile != null && !"".equals(sScoreFile)) + { + try + { + if (loadScoreFile(sScoreFile, alf)) + { + return true; + } + 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 false; + } + + /** + * Load a tree for the alignment if specified by parameter. Returns true if a + * tree was loaded, else false. + * + * @return + */ + private boolean initTree(AlignFrame alf) + { + String treeFile; + if ((treeFile = getParameter("tree")) == null + && (treeFile = getParameter("treefile")) == null) + return false; + if (alf == null) + alf = getCurrentAlignFrame(); + try + { + ret[0] = treeFile; + NewickFile nf = new NewickFile(treeFile, resolveFileProtocol(ret)); + nf.parse(); + if (nf.getTree() != null) + { + treeFile = ret[0]; + alf.getViewport() + .setCurrentTree(alf.showNewickTree(nf, treeFile).getTree()); + return true; + } + } catch (Exception ex) + { + ex.printStackTrace(); + } + return false; + } + + private void updateForAnnotations() + { + getCurrentAlignFrame().updateForAnnotations(); + } +}