fc99b2d537db83940fa0da9c3b92673b6371bdb0
[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     if (responseObj != null && !responseObj.equals(responseObj))
161     {
162       // NaN is an object in Chrome - catch this weirdness
163       // this so we don't cause issues later
164       return;
165     }
166     doFirstRun(new Response(responseObj));
167   }
168
169
170   boolean firstRunWasCalled = false;
171
172   private void doFirstRun(Response response)
173   {
174     if (firstRunWasCalled)
175     {
176       return;
177     }
178     firstRunWasCalled = true;
179     run(response);
180   }
181
182   private void run(Response response)
183   {
184     if (response.objresp != null
185             && !response.objresp.equals(response.objresp))
186     {
187       // NaN is an object in Chrome - catch this weirdness
188       // this so we don't cause issues later
189       return;
190     }
191     responses.add(response);
192     List<RunResponse> laction = callbacks.get(response);
193
194     if (laction == null)
195     {
196       System.err.println("Doing nothing for " + response);
197       return;
198     }
199     boolean wasRun = false;
200     int num = 0;
201     for (RunResponse action : laction)
202     {
203       num++;
204       // find next action to execute
205       if (!action.wasRun)
206       {
207         System.err
208                 .println("Executing action (" + num + ") for " + response);
209         wasRun = true;
210         action.wasRun = true;
211         action.run();
212         if (action.returned != null)
213         {
214           run(action.returned);
215         }
216         break;
217       }
218     }
219     if (!wasRun)
220     {
221       System.err.println("Did nothing for " + response);
222     }
223   }
224
225   List<Response> responses = new ArrayList<>();
226
227 }