--- /dev/null
+/*
+ * 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 <http://www.gnu.org/licenses/>.
+ * 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 <T>
+ * the actual dialog that will be shown - which will also initiate the
+ * response chain.
+ */
+public class DialogRunner<T extends DialogRunnerI> implements DialogRunnerI
+{
+
+ private Map<Response, RunResponse> 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<Response> responses = new ArrayList<>();
+
+}
--- /dev/null
+/*
+ * 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 <http://www.gnu.org/licenses/>.
+ * 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<T extends 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);
+
+}
--- /dev/null
+/*
+ * 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 <http://www.gnu.org/licenses/>.
+ * 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
--- /dev/null
+/*
+ * 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 <http://www.gnu.org/licenses/>.
+ * 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;
+ }
+}
--- /dev/null
+package jalview.util.dialogrunner;
+
+import org.testng.Assert;
+import org.testng.annotations.Test;
+
+public class DialogRunnerTest
+{
+ public class MockDialog implements DialogRunnerI
+ {
+ DialogRunner<MockDialog> 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);
+ }
+}
--- /dev/null
+/*
+ * 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 <http://www.gnu.org/licenses/>.
+ * 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");
+ }
+}
--- /dev/null
+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)));
+}
+}