JAL-3048 allow a chain of responses for a particular response code (needed when inter...
[jalview.git] / src / jalview / util / dialogrunner / DialogRunner.java
1 /*
2  * Jalview - A Sequence Alignment Editor and Viewer ($$Version-Rel$$)
3  * Copyright (C) $$Year-Rel$$ The Jalview Authors
4  *
5  * This file is part of Jalview.
6  *
7  * Jalview is free software: you can redistribute it and/or
8  * modify it under the terms of the GNU General Public License
9  * as published by the Free Software Foundation, either version 3
10  * of the License, or (at your option) any later version.
11  *
12  * Jalview is distributed in the hope that it will be useful, but
13  * WITHOUT ANY WARRANTY; without even the implied warranty
14  * of MERCHANTABILITY or FITNESS FOR A PARTICULAR
15  * PURPOSE.  See the GNU General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License
18  * along with Jalview.  If not, see <http://www.gnu.org/licenses/>.
19  * The Jalview Authors are detailed in the 'AUTHORS' file.
20  */
21 package jalview.util.dialogrunner;
22
23 import java.util.ArrayList;
24 import java.util.List;
25 import java.util.Map;
26
27 /**
28  * daft gymnastics to allow Dialogs to extend from a Swing class and use this
29  * class to implement chained Response run() definition and execution.
30  * 
31  * There is probably a better way of doing this.
32  * 
33  * @author jprocter
34  *
35  * @param <T>
36  *          the actual dialog that will be shown - which will also initiate the
37  *          response chain.
38  */
39 public class DialogRunner<T extends DialogRunnerI> implements DialogRunnerI
40 {
41
42   private Map<Response, List<RunResponse>> callbacks = new java.util.HashMap<>();
43
44   public T dialog;
45
46   public DialogRunner(T ourDialog)
47   {
48     dialog = ourDialog;
49   }
50
51   /**
52    * clear all 'was ran' flags so responses can be called again, and firstRun will
53    * trigger response execution
54    */
55   public void resetResponses()
56   {
57     for (List<RunResponse> lr : callbacks.values())
58     {
59       for (RunResponse response : lr)
60       {
61         response.reset();
62       }
63     }
64     responses.clear();
65     firstRunWasCalled = false;
66   }
67
68   @Override
69   public T response(RunResponse action)
70   {
71     return addResponse(false, action);
72   }
73
74   /**
75    * insert a response at the beginning of the chain for the action. Useful to add
76    * pre-action validations local to the Dialog class
77    * 
78    * @param action
79    * @return
80    */
81   public T firstResponse(RunResponse action)
82   {
83     return addResponse(true, action);
84   }
85
86   protected T addResponse(boolean prePend, RunResponse action)
87   {
88     List<RunResponse> laction = callbacks.get(action.ourTrigger);
89     if (laction == null)
90     {
91       laction = new ArrayList<>();
92       callbacks.put(action.ourTrigger, laction);
93     }
94     if (prePend)
95     {
96       laction.add(0,action);
97     } else {
98       laction.add(action);
99     }
100     return dialog;
101   }
102
103   /**
104    * 
105    * @param action
106    * @return true if action is a registered callback
107    */
108   public boolean isRegistered(RunResponse action)
109   {
110     List<RunResponse> resp = callbacks.get(action.ourTrigger);
111     if (resp != null)
112     {
113       for (RunResponse r : resp)
114       {
115         if (r == action)
116         {
117           return true;
118         }
119       }
120     }
121     return false;
122   }
123   /**
124    * handle a response
125    * 
126    * @param responseCode
127    */
128   public void run(int responseCode)
129   {
130     run(new Response(responseCode));
131   }
132
133   public void run(String responseString)
134   {
135     run(new Response(responseString));
136   }
137
138   public void run(Object responseObj)
139   {
140     run(new Response(responseObj));
141   }
142
143   /**
144    * start of response handling.
145    * 
146    * @param responseCode
147    */
148   public void firstRun(int responseCode)
149   {
150     doFirstRun(new Response(responseCode));
151   }
152
153   public void firstRun(String responseString)
154   {
155     doFirstRun(new Response(responseString));
156   }
157
158   public void firstRun(Object responseObj)
159   {
160     doFirstRun(new Response(responseObj));
161   }
162
163
164   boolean firstRunWasCalled = false;
165
166   private void doFirstRun(Response response)
167   {
168     if (firstRunWasCalled)
169     {
170       return;
171     }
172     firstRunWasCalled = true;
173     run(response);
174   }
175
176   private void run(Response response)
177   {
178     responses.add(response);
179     List<RunResponse> laction = callbacks.get(response);
180
181     if (laction == null)
182     {
183       System.err.println("Doing nothing for " + response);
184       return;
185     }
186     boolean wasRun = false;
187     int num = 0;
188     for (RunResponse action : laction)
189     {
190       num++;
191       // find next action to execute
192       if (!action.wasRun)
193       {
194         System.err
195                 .println("Executing action (" + num + ") for " + response);
196         wasRun = true;
197         action.wasRun = true;
198         action.run();
199         if (action.returned != null)
200         {
201           run(action.returned);
202         }
203         break;
204       }
205     }
206     if (!wasRun)
207     {
208       System.err.println("Did nothing for " + response);
209     }
210   }
211
212   List<Response> responses = new ArrayList<>();
213
214 }