From: Jim Procter Date: Fri, 29 Jun 2018 15:18:27 +0000 (+0100) Subject: JAL-3048 jalview.utils.dialogrunner.DialogRunner allows sequences of runnable methods... X-Git-Tag: Release_2_11_4_0~45^2~18^2~603^2~12 X-Git-Url: http://source.jalview.org/gitweb/?a=commitdiff_plain;h=592c32d037225062c9a4d6caac19b4b556668d9c;p=jalview.git JAL-3048 jalview.utils.dialogrunner.DialogRunner allows sequences of runnable methods to be sequentially triggered according to response codes from a dialog. --- diff --git a/src/jalview/util/dialogrunner/DialogRunner.java b/src/jalview/util/dialogrunner/DialogRunner.java new file mode 100644 index 0000000..fc1a73d --- /dev/null +++ b/src/jalview/util/dialogrunner/DialogRunner.java @@ -0,0 +1,151 @@ +/* + * Jalview - A Sequence Alignment Editor and Viewer ($$Version-Rel$$) + * Copyright (C) $$Year-Rel$$ The Jalview Authors + * + * This file is part of Jalview. + * + * Jalview is free software: you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, either version 3 + * of the License, or (at your option) any later version. + * + * Jalview is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty + * of MERCHANTABILITY or FITNESS FOR A PARTICULAR + * PURPOSE. See the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Jalview. If not, see . + * The Jalview Authors are detailed in the 'AUTHORS' file. + */ +package jalview.util.dialogrunner; + +import java.util.ArrayList; +import java.util.List; +import java.util.Map; + +/** + * daft gymnastics to allow Dialogs to extend from a Swing class and use this + * class to implement chained Response run() definition and execution. + * + * There is probably a better way of doing this. + * + * @author jprocter + * + * @param + * the actual dialog that will be shown - which will also initiate the + * response chain. + */ +public class DialogRunner implements DialogRunnerI +{ + + private Map callbacks = new java.util.HashMap<>(); + + public T dialog; + + public DialogRunner(T ourDialog) + { + dialog = ourDialog; + } + + /** + * clear all 'was ran' flags so responses can be called again, and firstRun will + * trigger response execution + */ + public void resetResponses() + { + for (RunResponse response : callbacks.values()) + { + response.reset(); + } + responses.clear(); + firstRunWasCalled = false; + } + + @Override + public T response(RunResponse action) + { + callbacks.put(action.ourTrigger, action); + return dialog; + } + + /** + * handle a response + * + * @param responseCode + */ + public void run(int responseCode) + { + run(new Response(responseCode)); + } + + public void run(String responseString) + { + run(new Response(responseString)); + } + + public void run(Object responseObj) + { + run(new Response(responseObj)); + } + + /** + * start of response handling. + * + * @param responseCode + */ + public void firstRun(int responseCode) + { + doFirstRun(new Response(responseCode)); + } + + public void firstRun(String responseString) + { + doFirstRun(new Response(responseString)); + } + + public void firstRun(Object responseObj) + { + doFirstRun(new Response(responseObj)); + } + + + boolean firstRunWasCalled = false; + + private void doFirstRun(Response response) + { + if (firstRunWasCalled) + { + return; + } + firstRunWasCalled = true; + run(response); + } + + private void run(Response response) + { + responses.add(response); + RunResponse action = callbacks.get(response); + if (action == null) + { + System.err.println("Doing nothing for " + response); + return; + } + if (action.wasRun) + { + System.err + .println("IMPLEMENTATION ERROR: Cycle in DialogRunner ! for " + + action); + } + System.err.println("Executing action for " + response); + action.wasRun = true; + action.run(); + if (action.returned != null) + { + run(action.returned); + } + } + + List responses = new ArrayList<>(); + +} diff --git a/src/jalview/util/dialogrunner/DialogRunnerI.java b/src/jalview/util/dialogrunner/DialogRunnerI.java new file mode 100644 index 0000000..9df6d33 --- /dev/null +++ b/src/jalview/util/dialogrunner/DialogRunnerI.java @@ -0,0 +1,42 @@ +/* + * Jalview - A Sequence Alignment Editor and Viewer ($$Version-Rel$$) + * Copyright (C) $$Year-Rel$$ The Jalview Authors + * + * This file is part of Jalview. + * + * Jalview is free software: you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, either version 3 + * of the License, or (at your option) any later version. + * + * Jalview is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty + * of MERCHANTABILITY or FITNESS FOR A PARTICULAR + * PURPOSE. See the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Jalview. If not, see . + * The Jalview Authors are detailed in the 'AUTHORS' file. + */ +package jalview.util.dialogrunner; + +/** + * functional pattern for blocking dialog response handling + * + * @author jprocter + * + */ +public interface DialogRunnerI +{ + + /** + * define a new response for this dialog. eg. dialog.response(new + * RunResponse(OK_PRessed) { run()...}).response(new RunResponse(CANCEL_PRESSED) + * { ... }); + * + * @param action + * @return the dialog + */ + T response(RunResponse action); + +} diff --git a/src/jalview/util/dialogrunner/Response.java b/src/jalview/util/dialogrunner/Response.java new file mode 100644 index 0000000..15df8f8 --- /dev/null +++ b/src/jalview/util/dialogrunner/Response.java @@ -0,0 +1,115 @@ +/* + * Jalview - A Sequence Alignment Editor and Viewer ($$Version-Rel$$) + * Copyright (C) $$Year-Rel$$ The Jalview Authors + * + * This file is part of Jalview. + * + * Jalview is free software: you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, either version 3 + * of the License, or (at your option) any later version. + * + * Jalview is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty + * of MERCHANTABILITY or FITNESS FOR A PARTICULAR + * PURPOSE. See the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Jalview. If not, see . + * The Jalview Authors are detailed in the 'AUTHORS' file. + */ +package jalview.util.dialogrunner; + +public class Response +{ + int type = 0; // int = 0, String = 1, Object = 2; + + int intresp; + + String stringresp; + + Object objresp; + + public Response(int response) + { + type = 0; + intresp = response; + } + + public Response(String response) + { + type = 1; + stringresp = response; + } + + public Response(Object response) + { + if (response instanceof String) + { + type = 1; + stringresp = (String) response; + return; + } + if (response instanceof Integer) + { + type = 0; + intresp = ((Integer) response).intValue(); + return; + } + objresp = response; + type = 2; + } + + @Override + public boolean equals(Object obj) + { + if (obj == null || !(obj instanceof Response)) + { + return false; + } + ; + if (((Response) obj).type == type) + { + switch (type) + { + case 0: + return ((((Response) obj).intresp) == intresp); + case 1: + return (((Response) obj).stringresp.equals(stringresp)); + case 2: + return (((Response) obj).objresp).equals(objresp); + } + } + return false; + } + + @Override + public int hashCode() + { + switch (type) + { + case 0: + return Integer.valueOf(intresp).hashCode(); + case 1: + return stringresp.hashCode(); + case 2: + return objresp.hashCode(); + } + return super.hashCode(); + } + + @Override + public String toString() + { + switch (type) + { + case 0: + return "DialogRunner int: " + intresp; + case 1: + return "DialogRunner str: '" + stringresp + "'"; + case 2: + return "DialogRunner obj: " + objresp.toString(); + } + return "Unconfigured response."; + } +} \ No newline at end of file diff --git a/src/jalview/util/dialogrunner/RunResponse.java b/src/jalview/util/dialogrunner/RunResponse.java new file mode 100644 index 0000000..acc53f0 --- /dev/null +++ b/src/jalview/util/dialogrunner/RunResponse.java @@ -0,0 +1,79 @@ +/* + * Jalview - A Sequence Alignment Editor and Viewer ($$Version-Rel$$) + * Copyright (C) $$Year-Rel$$ The Jalview Authors + * + * This file is part of Jalview. + * + * Jalview is free software: you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, either version 3 + * of the License, or (at your option) any later version. + * + * Jalview is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty + * of MERCHANTABILITY or FITNESS FOR A PARTICULAR + * PURPOSE. See the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Jalview. If not, see . + * The Jalview Authors are detailed in the 'AUTHORS' file. + */ +package jalview.util.dialogrunner; + +/** + * A Runnable that is kind of like a future, that allows a sequence of Runabbles + * to be conditionally executed by DialogRunner + * + * @author jprocter + * + */ +public abstract class RunResponse implements Runnable +{ + /** + * Response that triggers the Run method + */ + public Response ourTrigger; + + /** + * set by run() on exit + */ + public Response returned = null; + + /** + * set by dialog runner + */ + public boolean wasRun = false; + + public RunResponse(int trigger) + { + ourTrigger = new Response(trigger); + } + + public RunResponse(Object trigger) + { + ourTrigger = new Response(trigger); + } + + public RunResponse(String trigger) + { + ourTrigger = new Response(trigger); + } + + public RunResponse(Response trigger) + { + ourTrigger = trigger; + } + + public void reset() + { + wasRun = false; + returned = null; + + } + + @Override + public String toString() + { + return "Runner for " + ourTrigger; + } +} diff --git a/test/jalview/util/dialogrunner/DialogRunnerTest.java b/test/jalview/util/dialogrunner/DialogRunnerTest.java new file mode 100644 index 0000000..e956124 --- /dev/null +++ b/test/jalview/util/dialogrunner/DialogRunnerTest.java @@ -0,0 +1,101 @@ +package jalview.util.dialogrunner; + +import org.testng.Assert; +import org.testng.annotations.Test; + +public class DialogRunnerTest +{ + public class MockDialog implements DialogRunnerI + { + DialogRunner runner = new DialogRunner<>(this); + + @Override + public MockDialog response(RunResponse action) + { + return runner.response(action); + } + + public void doDialog(String resp) + { + runner.firstRun(resp); + } + } + + MockDialog dialog = new MockDialog(); + + @Test + public void testDialogRunner() + { + RunResponse ok, cancel, help, ineed; + final Response ooh = new Response("OOOOoooOOOOH!"), + r_ok = new Response("OK"), r_cancel = new Response("CANCEL"), + r_done = new Response("DONE"), r_help = new Response("HELP"), + r_ddoit = new Response("DIDNT DOIT"), + r_needsb = new Response("I NEED SOMEBODY"); + + ok = new RunResponse("OK") + { + + @Override + public void run() + { + returned = new Response("DONE"); + } + }; + cancel = new RunResponse("CANCEL") + { + @Override + public void run() + { + returned = r_ddoit; + } + }; + help = new RunResponse("HELP") + { + @Override + public void run() + { + returned = r_needsb; + + } + }; + ineed = new RunResponse(r_needsb) + { + @Override + public void run() + { + returned = ooh; + } + }; + + dialog.response(ok).response(cancel).response(help).response(ineed); + + Assert.assertFalse(dialog.runner.firstRunWasCalled); + dialog.doDialog("OK"); + // OK called, nothing else. + Assert.assertTrue(dialog.runner.firstRunWasCalled); + Assert.assertTrue(ok.wasRun); + Assert.assertEquals(ok.returned, r_done); + Assert.assertFalse(cancel.wasRun); + Assert.assertEquals(dialog.runner.responses.size(), 2); + + // do it again - check it doesn't trigger again + ok.wasRun = false; + dialog.doDialog("OK"); + Assert.assertFalse(ok.wasRun); + + // reset - everything false/null + dialog.runner.resetResponses(); + Assert.assertFalse(dialog.runner.firstRunWasCalled); + Assert.assertFalse(ok.wasRun); + Assert.assertNull(ok.returned); + Assert.assertEquals(dialog.runner.responses.size(), 0); + + // cancel called .. + dialog.doDialog("HELP"); + Assert.assertTrue(dialog.runner.firstRunWasCalled); + Assert.assertFalse(ok.wasRun); + Assert.assertEquals(ineed.returned, ooh); + Assert.assertEquals(dialog.runner.responses.size(), 3); + } +} diff --git a/test/jalview/util/dialogrunner/ResponseTest.java b/test/jalview/util/dialogrunner/ResponseTest.java new file mode 100644 index 0000000..d722b1a --- /dev/null +++ b/test/jalview/util/dialogrunner/ResponseTest.java @@ -0,0 +1,42 @@ +/* + * Jalview - A Sequence Alignment Editor and Viewer ($$Version-Rel$$) + * Copyright (C) $$Year-Rel$$ The Jalview Authors + * + * This file is part of Jalview. + * + * Jalview is free software: you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, either version 3 + * of the License, or (at your option) any later version. + * + * Jalview is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty + * of MERCHANTABILITY or FITNESS FOR A PARTICULAR + * PURPOSE. See the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Jalview. If not, see . + * The Jalview Authors are detailed in the 'AUTHORS' file. + */ +package jalview.util.dialogrunner; + +import org.testng.Assert; +import org.testng.annotations.Test; + +public class ResponseTest +{ + @Test + public void testResonse() { + Response intr=new Response(1),intrCopy=new Response(1); + Response strr=new Response("1"),strrcopy=new Response("1"); + Response objr=new Response(Double.valueOf(1d)); + Assert.assertTrue(intr.equals(intrCopy)); + Assert.assertTrue(strr.equals(strrcopy)); + Assert.assertFalse(intr.equals(strr)); + Assert.assertFalse(intr.equals(objr)); + Assert.assertFalse(strr.equals(objr)); + Assert.assertEquals(intr.toString(), "DialogRunner int: 1"); + Assert.assertEquals(strr.toString(), "DialogRunner str: '1'"); + Assert.assertEquals(objr.toString(), "DialogRunner obj: 1.0"); + } +} diff --git a/test/jalview/util/dialogrunner/RunResponseTest.java b/test/jalview/util/dialogrunner/RunResponseTest.java new file mode 100644 index 0000000..ff86675 --- /dev/null +++ b/test/jalview/util/dialogrunner/RunResponseTest.java @@ -0,0 +1,57 @@ +package jalview.util.dialogrunner; + +import org.testng.Assert; +import org.testng.annotations.Test; + +public class RunResponseTest +{ + @Test + public void testRunResponse() + { + + RunResponse rr = new RunResponse("OK") + { + @Override + public void run() + { + returned = new Response("DONE"); + } + }; + Assert.assertEquals(rr.ourTrigger, new Response("OK")); + Assert.assertNotEquals(rr.ourTrigger, new Response("NOTOK")); + Assert.assertNull(rr.returned); + Assert.assertFalse(rr.wasRun); + // trivial .. + rr.wasRun = true; + rr.run(); + Assert.assertTrue(rr.wasRun); + + Assert.assertEquals(rr.returned, new Response("DONE")); + rr.reset(); + Assert.assertNull(rr.returned); + Assert.assertFalse(rr.wasRun); + + Assert.assertEquals(rr.toString(), "Runner for " + new Response("OK")); + + // just test the other constructors + RunResponse rr12 = new RunResponse(12) + { + @Override + public void run() + { + returned = new Response("DONE"); + } + }; + RunResponse rrpi = new RunResponse(new Double(3.142)) + { + @Override + public void run() + { + returned = new Response("DONE"); + } + }; + Assert.assertEquals(rr12.ourTrigger, new Response(12)); + Assert.assertEquals(rrpi.ourTrigger, + new Response(Double.valueOf(3.142))); +} +}