JAL-3048 EditNameDialog modified for JalviewJS (layout, i18n)
[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     if (defaultResponse != null)
66     {
67       defaultResponse.reset();
68     }
69     firstRunWasCalled = false;
70   }
71
72   @Override
73   public T response(RunResponse action)
74   {
75     return addResponse(false, action);
76   }
77
78   /**
79    * insert a response at the beginning of the chain for the action. Useful to add
80    * pre-action validations local to the Dialog class
81    * 
82    * @param action
83    * @return
84    */
85   public T firstResponse(RunResponse action)
86   {
87     return addResponse(true, action);
88   }
89
90   protected T addResponse(boolean prePend, RunResponse action)
91   {
92     List<RunResponse> laction = callbacks.get(action.ourTrigger);
93     if (laction == null)
94     {
95       laction = new ArrayList<>();
96       callbacks.put(action.ourTrigger, laction);
97     }
98     if (prePend)
99     {
100       laction.add(0,action);
101     } else {
102       laction.add(action);
103     }
104     return dialog;
105   }
106
107   /**
108    * 
109    * @param action
110    * @return true if action is a registered callback
111    */
112   public boolean isRegistered(RunResponse action)
113   {
114     List<RunResponse> resp = callbacks.get(action.ourTrigger);
115     if (resp != null)
116     {
117       for (RunResponse r : resp)
118       {
119         if (r == action)
120         {
121           return true;
122         }
123       }
124     }
125     return false;
126   }
127   /**
128    * handle a response
129    * 
130    * @param responseCode
131    */
132   public void run(int responseCode)
133   {
134     run(new Response(responseCode));
135   }
136
137   public void run(String responseString)
138   {
139     run(new Response(responseString));
140   }
141
142   public void run(Object responseObj)
143   {
144     run(new Response(responseObj));
145   }
146
147   /**
148    * start of response handling.
149    * 
150    * @param responseCode
151    */
152   public void firstRun(int responseCode)
153   {
154     doFirstRun(new Response(responseCode));
155   }
156
157   public void firstRun(String responseString)
158   {
159     doFirstRun(new Response(responseString));
160   }
161
162   public void firstRun(Object responseObj)
163   {
164     if (responseObj != null && !responseObj.equals(responseObj))
165     {
166       // NaN is an object in Chrome - catch this weirdness
167       // this so we don't cause issues later
168       return;
169     }
170     doFirstRun(new Response(responseObj));
171   }
172
173
174   boolean firstRunWasCalled = false;
175
176   private void doFirstRun(Response response)
177   {
178     if (firstRunWasCalled)
179     {
180       return;
181     }
182     firstRunWasCalled = true;
183     run(response);
184   }
185
186   private void run(Response response)
187   {
188     if (response.objresp != null
189             && !response.objresp.equals(response.objresp))
190     {
191       // NaN is an object in Chrome - catch this weirdness
192       // this so we don't cause issues later
193       return;
194     }
195     responses.add(response);
196     
197     List<RunResponse> laction = response.isNull() ? null : callbacks.get(response);
198
199     if (laction == null)
200     {
201       if (defaultResponse != null)
202       {
203         defaultResponse.ourTrigger = response;
204         defaultResponse.wasRun = true;
205         defaultResponse.run();
206       }
207       else
208       {
209         System.err.println("Doing nothing for " + response);
210       }
211       return;
212     }
213     boolean wasRun = false;
214     int num = 0;
215     for (RunResponse action : laction)
216     {
217       num++;
218       // find next action to execute
219       if (!action.wasRun)
220       {
221         System.err
222                 .println("Executing action (" + num + ") for " + response);
223         wasRun = true;
224         action.wasRun = true;
225         action.run();
226         if (action.returned != null)
227         {
228           run(action.returned);
229         }
230         break;
231       }
232     }
233     if (!wasRun)
234     {
235       System.err.println("Did nothing for " + response);
236     }
237   }
238
239   List<Response> responses = new ArrayList<>();
240
241   RunResponse defaultResponse = null;
242
243   /**
244    * Convenience wrapper for setting default response to a runnable
245    * 
246    * @param runnable
247    */
248   public void setDefaultResponse(Runnable runnable)
249   {
250     defaultResponse = new RunResponse(runnable)
251     {
252       @Override
253       public void run()
254       {
255         runnable.run();
256       }
257     };
258   }
259
260   /**
261    * Default responses are called once, with ourTrigger set to the unHandled
262    * response received
263    * 
264    * @param runnable
265    */
266   public void setDefaultResponse(RunResponse runnable)
267   {
268     defaultResponse = runnable;
269   }
270 }