From: Ben Soares Date: Wed, 8 Sep 2021 17:05:52 +0000 (+0100) Subject: JAL-3851 some changes. HighlightSequenceEndpoint and SelectSequenceEndpoint X-Git-Url: http://source.jalview.org/gitweb/?a=commitdiff_plain;h=ee0790004c3d3760e7d4a85117a17e388b6c9c87;p=jalview.git JAL-3851 some changes. HighlightSequenceEndpoint and SelectSequenceEndpoint --- diff --git a/src/jalview/gui/AlignFrame.java b/src/jalview/gui/AlignFrame.java index 5370437..6cfe42e 100644 --- a/src/jalview/gui/AlignFrame.java +++ b/src/jalview/gui/AlignFrame.java @@ -55,8 +55,10 @@ import java.util.ArrayList; import java.util.Arrays; import java.util.Deque; import java.util.Enumeration; +import java.util.HashMap; import java.util.Hashtable; import java.util.List; +import java.util.Map; import java.util.Vector; import javax.swing.ButtonGroup; @@ -5876,6 +5878,27 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener, { return lastFeatureSettingsBounds; } + + /* + * Caching hashmaps for jalview.rest.API + */ + private static Map alignFrameMap = null; + + public static AlignFrame getAlignFrameFromRestId(String id) + { + if (id == null || alignFrameMap == null) + return null; + return alignFrameMap.get(id); + } + + public void cacheAlignFrameFromRestId(String id) + { + if (id == null) + return; + if (alignFrameMap == null) + alignFrameMap = new HashMap<>(); + alignFrameMap.put(id, this); + } } class PrintThread extends Thread diff --git a/src/jalview/gui/SequenceFetcher.java b/src/jalview/gui/SequenceFetcher.java index b57fa46..1fc56d8 100755 --- a/src/jalview/gui/SequenceFetcher.java +++ b/src/jalview/gui/SequenceFetcher.java @@ -128,10 +128,18 @@ public class SequenceFetcher extends JPanel implements Runnable * @param guiIndic * @param selectedDb * @param queryString + * @param interactive */ public SequenceFetcher(IProgressIndicator guiIndic, final String selectedDb, final String queryString) { + this(guiIndic, selectedDb, queryString, true); + } + + public SequenceFetcher(IProgressIndicator guiIndic, + final String selectedDb, final String queryString, + boolean interactive) + { this.progressIndicator = guiIndic; getSequenceFetcherSingleton(); this.guiWindow = progressIndicator; @@ -141,7 +149,7 @@ public class SequenceFetcher extends JPanel implements Runnable alignFrame = (AlignFrame) progressIndicator; } - jbInit(selectedDb); + jbInit(selectedDb, interactive); textArea.setText(queryString); frame = new JInternalFrame(); @@ -158,7 +166,7 @@ public class SequenceFetcher extends JPanel implements Runnable .getString("label.additional_sequence_fetcher")); } - private void jbInit(String selectedDb) + private void jbInit(String selectedDb, boolean interactive) { this.setLayout(new BorderLayout()); @@ -300,9 +308,22 @@ public class SequenceFetcher extends JPanel implements Runnable jScrollPane1.getViewport().add(textArea); idsPanel.add(jScrollPane1, BorderLayout.CENTER); + // En/disable or show/hide interactive elements + database.setEnabled(interactive); + exampleAccession.setVisible(interactive); + replacePunctuation.setVisible(interactive); + okBtn.setVisible(interactive); + exampleBtn.setVisible(interactive); + closeBtn.setVisible(interactive); + backBtn.setVisible(interactive); + jLabel1.setVisible(interactive); + clear.setVisible(interactive); + textArea.setEnabled(interactive); + this.add(actionPanel, BorderLayout.SOUTH); this.add(idsPanel, BorderLayout.CENTER); this.add(databasePanel, BorderLayout.NORTH); + } /** @@ -415,10 +436,11 @@ public class SequenceFetcher extends JPanel implements Runnable */ public void ok_actionPerformed() { - ok_actionPerformed(false); + ok_actionPerformed(false, null); } - public CompletableFuture ok_actionPerformed(boolean returnFuture) + public CompletableFuture ok_actionPerformed(boolean returnFuture, + String id) { /* * tidy inputs and check there is something to search for @@ -457,11 +479,18 @@ public class SequenceFetcher extends JPanel implements Runnable backBtn.setEnabled(false); CompletableFuture worker = CompletableFuture - .runAsync(new Thread(this)); + .runAsync(() -> runAndCacheAlignFrame(returnFuture, id)); return returnFuture ? worker : null; } + private void runAndCacheAlignFrame(boolean cacheAlignFrame, String id) + { + AlignFrame af = this.run(cacheAlignFrame); + if (cacheAlignFrame && id != null && af != null) + af.cacheAlignFrameFromRestId(id); + } + private void resetDialog() { exampleBtn.setEnabled(true); @@ -474,6 +503,11 @@ public class SequenceFetcher extends JPanel implements Runnable @Override public void run() { + run(false); + } + + public AlignFrame run(boolean returnAlignFrame) + { boolean addToLast = false; List aresultq = new ArrayList<>(); List presultTitle = new ArrayList<>(); @@ -611,9 +645,10 @@ public class SequenceFetcher extends JPanel implements Runnable : MessageManager.getString("status.processing"), Thread.currentThread().hashCode()); // process results + AlignFrame af = null; while (presult.size() > 0) { - parseResult(presult.remove(0), presultTitle.remove(0), null, + af = parseResult(presult.remove(0), presultTitle.remove(0), null, preferredFeatureColours); } // only remove visual delay after we finished parsing. @@ -641,6 +676,7 @@ public class SequenceFetcher extends JPanel implements Runnable showErrorMessage(sb.toString()); } resetDialog(); + return returnAlignFrame ? af : null; } /** @@ -806,20 +842,21 @@ public class SequenceFetcher extends JPanel implements Runnable return "Retrieved from " + database.getSelectedItem(); } - AlignmentI parseResult(AlignmentI al, String title, + AlignFrame parseResult(AlignmentI al, String title, FileFormatI currentFileFormat, FeatureSettingsModelI preferredFeatureColours) { + AlignFrame af = alignFrame; if (al != null && al.getHeight() > 0) { if (title == null) { title = getDefaultRetrievalTitle(); } - if (alignFrame == null) + if (af == null) { - AlignFrame af = new AlignFrame(al, AlignFrame.DEFAULT_WIDTH, + af = new AlignFrame(al, AlignFrame.DEFAULT_WIDTH, AlignFrame.DEFAULT_HEIGHT); if (currentFileFormat != null) { @@ -862,10 +899,10 @@ public class SequenceFetcher extends JPanel implements Runnable } else { - alignFrame.viewport.addAlignment(al, title); + af.viewport.addAlignment(al, title); } } - return al; + return af; } void showErrorMessage(final String error) diff --git a/src/jalview/rest/API.java b/src/jalview/rest/API.java index 0bd3caa..7d87120 100644 --- a/src/jalview/rest/API.java +++ b/src/jalview/rest/API.java @@ -48,6 +48,7 @@ public class API extends RestHandler addEndpoint(new FetchSequencesEndpoint(this)); addEndpoint(new InputAlignmentEndpoint(this)); addEndpoint(new HighlightSequenceEndpoint(this)); + addEndpoint(new SelectSequencesEndpoint(this)); setPath(MY_PATH); this.registerHandler(); diff --git a/src/jalview/rest/AbstractEndpoint.java b/src/jalview/rest/AbstractEndpoint.java index 2db0366..77c3bb8 100644 --- a/src/jalview/rest/AbstractEndpoint.java +++ b/src/jalview/rest/AbstractEndpoint.java @@ -125,4 +125,32 @@ public abstract class AbstractEndpoint implements EndpointI return true; } + public int[][] parseIntRanges(String rangesString) + { + String[] rangeStrings = rangesString.split(","); + int[][] ranges = new int[2][rangeStrings.length]; + for (int i = 0; i < rangeStrings.length; i++) + { + String range = rangeStrings[i]; + try + { + int hyphenpos = range.indexOf('-'); + if (hyphenpos < 0) + { + ranges[0][i] = Integer.parseInt(range); + ranges[1][i] = ranges[0][i]; + } + else + { + ranges[0][i] = Integer.parseInt(range.substring(0, hyphenpos)); + ranges[1][i] = Integer.parseInt(range.substring(hyphenpos + 1)); + } + } catch (NumberFormatException nfe) + { + return null; + } + } + return ranges; + } + } \ No newline at end of file diff --git a/src/jalview/rest/AbstractEndpointAsync.java b/src/jalview/rest/AbstractEndpointAsync.java index eb8280f..90122bf 100644 --- a/src/jalview/rest/AbstractEndpointAsync.java +++ b/src/jalview/rest/AbstractEndpointAsync.java @@ -91,19 +91,24 @@ public abstract class AbstractEndpointAsync extends AbstractEndpoint if (checkStatus(request, response, Status.STARTED)) { - returnStatus(response); + String finishedString = null; + if (getStatus() == Status.FINISHED) + { + finishedString = finished(request, response); + } + returnStatus(request, response, finishedString); return; } if (getCompletableFuture() == null) { - final Map finalMap = stringsPassedToProcessAsync; + final Map finalStringMap = stringsPassedToProcessAsync; setCompletableFuture(CompletableFuture.runAsync(() -> { // subclass method - this.processAsync(request, response, finalMap); + this.processAsync(request, response, finalStringMap); })); } - finaliseCompletableFuture(); + addWhenCompleteCompletableFuture(); // subclass method finalise(request, response); @@ -116,6 +121,12 @@ public abstract class AbstractEndpointAsync extends AbstractEndpoint { } + protected String finished(HttpServletRequest request, + HttpServletResponse response) + { + return null; + } + /* * Shared methods below here */ @@ -140,16 +151,23 @@ public abstract class AbstractEndpointAsync extends AbstractEndpoint // don't change a job's status if it has finished or died if (getStatus() == Status.FINISHED || getStatus() == Status.ERROR) return; - getAPI().getStatusMap().put(id, status); + API.getStatusMap().put(id, status); } protected Status getStatus() { - return getAPI().getStatusMap().get(getId()); + getAPI(); + return API.getStatusMap().get(getId()); } protected void returnStatus(HttpServletResponse response) { + returnStatus(null, response, null); + } + + protected void returnStatus(HttpServletRequest request, + HttpServletResponse response, String message) + { String id = getId(); try { @@ -158,10 +176,12 @@ public abstract class AbstractEndpointAsync extends AbstractEndpoint { writer.write("id=" + id + "\n"); } - if (getAPI().getRequestMap().get(id) != null) + getAPI(); + if (API.getRequestMap().get(id) != null) { - writer.write("request=" - + getAPI().getRequestMap().get(id).toString() + "\n"); + getAPI(); + writer.write( + "request=" + API.getRequestMap().get(id).toString() + "\n"); } if (getStatus() != null) { @@ -171,6 +191,10 @@ public abstract class AbstractEndpointAsync extends AbstractEndpoint } writer.write("status=" + getStatus().toString() + "\n"); } + if (message != null) + { + writer.write(message); + } } catch (IOException e) { Cache.debug(e); @@ -192,7 +216,7 @@ public abstract class AbstractEndpointAsync extends AbstractEndpoint { if (set != null) changeStatus(set); - getAPI().getRequestMap().put(id, request.getRequestURI()); + API.getRequestMap().put(id, request.getRequestURI()); return false; } else @@ -201,7 +225,7 @@ public abstract class AbstractEndpointAsync extends AbstractEndpoint } } - protected void finaliseCompletableFuture() + protected void addWhenCompleteCompletableFuture() { String id = getId(); cf.whenComplete((Void, e) -> { diff --git a/src/jalview/rest/FetchSequencesEndpoint.java b/src/jalview/rest/FetchSequencesEndpoint.java index 71734c6..ac01d8a 100644 --- a/src/jalview/rest/FetchSequencesEndpoint.java +++ b/src/jalview/rest/FetchSequencesEndpoint.java @@ -1,13 +1,19 @@ package jalview.rest; +import java.util.List; import java.util.Map; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; +import jalview.api.AlignmentViewPanel; import jalview.bin.Cache; +import jalview.datamodel.AlignmentI; +import jalview.datamodel.SequenceI; +import jalview.gui.AlignFrame; import jalview.gui.Desktop; import jalview.gui.SequenceFetcher; +import jalview.structure.StructureSelectionManager; import jalview.util.DBRefUtils; public class FetchSequencesEndpoint extends AbstractEndpointAsync @@ -46,8 +52,8 @@ public class FetchSequencesEndpoint extends AbstractEndpointAsync String db = DBRefUtils.getCanonicalName(dbName); Desktop desktop = Desktop.instance; - sf = new SequenceFetcher(desktop, db, dbId); - setCompletableFuture(sf.ok_actionPerformed(true)); + sf = new SequenceFetcher(desktop, db, dbId, false); + setCompletableFuture(sf.ok_actionPerformed(true, getId())); } protected void processAsync(HttpServletRequest request, @@ -61,4 +67,34 @@ public class FetchSequencesEndpoint extends AbstractEndpointAsync { sf.close_actionPerformed(null); } + + protected String finished(HttpServletRequest request, + HttpServletResponse response) + { + AlignFrame af = AlignFrame.getAlignFrameFromRestId(getId()); + if (af == null) + { + return null; + } + List aps = (List) af + .getAlignPanels(); + StringBuilder sb = new StringBuilder(); + for (AlignmentViewPanel ap : aps) + { + StructureSelectionManager ssm = ap.getStructureSelectionManager(); + // ap.getAlignViewport().getSequenceSetId() + AlignmentI al = ap.getAlignment(); + List seqs = (List) al.getSequences(); + for (SequenceI seq : seqs) + { + if (sb.length() > 0) + sb.append(","); + sb.append(seq.getName()); + } + } + sb.insert(0, "sequences="); + sb.append("\n"); + return sb.toString(); + } + } diff --git a/src/jalview/rest/HighlightSequenceEndpoint.java b/src/jalview/rest/HighlightSequenceEndpoint.java index 3f63ebb..5aa6943 100644 --- a/src/jalview/rest/HighlightSequenceEndpoint.java +++ b/src/jalview/rest/HighlightSequenceEndpoint.java @@ -1,8 +1,20 @@ package jalview.rest; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; +import jalview.api.AlignmentViewPanel; +import jalview.bin.Cache; +import jalview.datamodel.AlignmentI; +import jalview.datamodel.SequenceI; +import jalview.gui.AlignFrame; +import jalview.gui.Desktop; +import jalview.structure.StructureSelectionManager; + public class HighlightSequenceEndpoint extends AbstractEndpoint { public HighlightSequenceEndpoint(API api) @@ -10,13 +22,13 @@ public class HighlightSequenceEndpoint extends AbstractEndpoint super(api, path, name, parameters, description); } - protected static final String path = "highlight"; + protected static final String path = "highlightsequence"; - private static final String name = "Highlight positions"; + private static final String name = "Highlight sequence positions"; private static final String parameters = ","; - private static final String description = "Highlight the specified sequences with the specified range(s)"; + private static final String description = "Highlight the specified sequences at the specified position"; public void processEndpoint(HttpServletRequest request, HttpServletResponse response) @@ -27,31 +39,73 @@ public class HighlightSequenceEndpoint extends AbstractEndpoint } String[] parameters = getEndpointPathParameters(request); - String rangesString = parameters[0]; - String[] rangeStrings = rangesString.split(","); - int[][] ranges = new int[rangeStrings.length][2]; - for (int i = 0; i < rangeStrings.length; i++) + String posString = parameters[1]; + int pos = -1; + try + { + pos = Integer.parseInt(posString); + } catch (NumberFormatException e) + { + returnError(request, response, + "Could not parse postition integer " + posString); + } + + String sequenceNames = parameters[0]; + String fromIdString = request.getParameter("fromId"); + + Map ssmMap = new HashMap<>(); + AlignFrame[] alignFrames; + if (fromIdString != null) { - String range = rangeStrings[i]; - try + AlignFrame af = AlignFrame.getAlignFrameFromRestId(fromIdString); + if (af == null) { - int hyphenpos = range.indexOf('-'); - if (hyphenpos < 0) - { - ranges[i][0] = Integer.parseInt(range); - ranges[i][1] = ranges[i][0]; - } - else + returnError(request, response, + "fromId value '" + fromIdString + "' results not found"); + return; + } + alignFrames = new AlignFrame[] { af }; + } + else + { + alignFrames = Desktop.getAlignFrames(); + } + if (alignFrames == null) + return; + for (int i = 0; i < alignFrames.length; i++) + { + AlignFrame af = alignFrames[i]; + List aps = (List) af + .getAlignPanels(); + for (AlignmentViewPanel ap : aps) + { + StructureSelectionManager ssm = ap.getStructureSelectionManager(); + // ap.getAlignViewport().getSequenceSetId() + AlignmentI al = ap.getAlignment(); + List seqs = (List) al.getSequences(); + for (SequenceI seq : seqs) { - ranges[i][0] = Integer.parseInt(range.substring(0, hyphenpos)); - ranges[i][1] = Integer.parseInt(range.substring(hyphenpos)); + Cache.info("REMOVEME sequence name=" + seq.getName()); + if (sequenceNames.equals(seq.getName())) + { + Cache.info("REMOVEME MATCHED " + seq.getName()); + ssmMap.put(seq, ssm); + } } - } catch (NumberFormatException nfe) + } + } + // highlight + for (SequenceI seq : ssmMap.keySet()) + { + StructureSelectionManager ssm = ssmMap.get(seq); + if (ssm == null) { - returnError(request, response, - "couldn't parse ranges component '" + range + "'"); - return; + Cache.info("REMOVEME skipping sequence " + seq.getName()); + continue; } + Cache.info("REMOVEME Attempting to highlight sequence " + + seq.getName() + " at postition " + pos); + ssm.mouseOverSequence(seq, pos, -1, null); } } diff --git a/src/jalview/rest/SelectSequencesEndpoint.java b/src/jalview/rest/SelectSequencesEndpoint.java new file mode 100644 index 0000000..1a8c441 --- /dev/null +++ b/src/jalview/rest/SelectSequencesEndpoint.java @@ -0,0 +1,108 @@ +package jalview.rest; + +import java.util.Arrays; +import java.util.List; + +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +import jalview.api.AlignViewportI; +import jalview.api.AlignmentViewPanel; +import jalview.datamodel.AlignmentI; +import jalview.datamodel.SequenceGroup; +import jalview.datamodel.SequenceI; +import jalview.gui.AlignFrame; +import jalview.gui.Desktop; + +public class SelectSequencesEndpoint extends AbstractEndpoint +{ + public SelectSequencesEndpoint(API api) + { + super(api, path, name, parameters, description); + } + + protected static final String path = "selectsequences"; + + private static final String name = "Select sequence(s) positions"; + + private static final String parameters = ","; + + private static final String description = "Select the specified sequence(s) with the specified range"; + + public void processEndpoint(HttpServletRequest request, + HttpServletResponse response) + { + if (!checkParameters(request, response, 2)) + { + return; + } + String[] parameters = getEndpointPathParameters(request); + + String rangesString = parameters[1]; + int[][] ranges = parseIntRanges(rangesString); + if (ranges == null || ranges.length < 2 || ranges[0].length < 1) + { + returnError(request, response, + "couldn't parse range '" + rangesString + "'"); + return; + } + if (ranges[0].length > 1) + { + returnError(request, response, + "only provide 1 range '" + rangesString + "'"); + return; + } + int start = ranges[0][0]; + int end = ranges[1][0]; + + String sequenceNamesString = parameters[0]; + List sequenceNames = Arrays + .asList(sequenceNamesString.split(",")); + String fromIdString = request.getParameter("fromId"); + + AlignFrame[] alignFrames; + if (fromIdString != null) + { + AlignFrame af = AlignFrame.getAlignFrameFromRestId(fromIdString); + if (af == null) + { + returnError(request, response, + "fromId value '" + fromIdString + "' results not found"); + return; + } + alignFrames = new AlignFrame[] { af }; + } + else + { + alignFrames = Desktop.getAlignFrames(); + } + if (alignFrames == null) + return; + for (int i = 0; i < alignFrames.length; i++) + { + AlignFrame af = alignFrames[i]; + List aps = (List) af + .getAlignPanels(); + for (AlignmentViewPanel ap : aps) + { + AlignViewportI avp = ap.getAlignViewport(); + // ap.getAlignViewport().getSequenceSetId() + AlignmentI al = ap.getAlignment(); + List seqs = (List) al.getSequences(); + SequenceGroup stretchGroup = new SequenceGroup(); + for (SequenceI seq : seqs) + { + if (sequenceNames.contains(seq.getName())) + { + stretchGroup.addSequence(seq, false); + } + } + stretchGroup.setStartRes(start); + stretchGroup.setEndRes(end); + avp.setSelectionGroup(stretchGroup); + ap.paintAlignment(false, false); + avp.sendSelection(); + } + } + } +} \ No newline at end of file