JAL-1355 (basic i18n support)
[jalview.git] / src / jalview / gui / RestServiceEditorPane.java
1 /*
2  * Jalview - A Sequence Alignment Editor and Viewer (Version 2.8)
3  * Copyright (C) 2012 J Procter, AM Waterhouse, LM Lui, J Engelhardt, G Barton, M Clamp, S Searle
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 of the License, or (at your option) any later version.
10  *  
11  * Jalview is distributed in the hope that it will be useful, but 
12  * WITHOUT ANY WARRANTY; without even the implied warranty 
13  * of MERCHANTABILITY or FITNESS FOR A PARTICULAR 
14  * PURPOSE.  See the GNU General Public License for more details.
15  * 
16  * You should have received a copy of the GNU General Public License along with Jalview.  If not, see <http://www.gnu.org/licenses/>.
17  */
18 package jalview.gui;
19
20 import jalview.io.packed.DataProvider.JvDataType;
21 import jalview.jbgui.GRestServiceEditorPane;
22 import jalview.util.MessageManager;
23 import jalview.ws.rest.InputType;
24 import jalview.ws.rest.RestServiceDescription;
25
26 import java.awt.BorderLayout;
27 import java.awt.FlowLayout;
28 import java.awt.event.ActionEvent;
29 import java.awt.event.ActionListener;
30 import java.awt.event.ComponentEvent;
31 import java.awt.event.ComponentListener;
32 import java.awt.event.KeyEvent;
33 import java.awt.event.KeyListener;
34 import java.awt.event.MouseEvent;
35 import java.util.HashMap;
36 import java.util.List;
37 import java.util.Map;
38 import java.util.Vector;
39 import java.util.regex.Matcher;
40 import java.util.regex.Pattern;
41
42 import javax.swing.JFrame;
43 import javax.swing.JMenuItem;
44 import javax.swing.JPanel;
45 import javax.swing.JPopupMenu;
46 import javax.swing.event.ChangeEvent;
47 import javax.swing.event.ChangeListener;
48
49 public class RestServiceEditorPane extends GRestServiceEditorPane
50 {
51   /**
52    * the latest version of the service definition.
53    */
54   jalview.ws.rest.RestServiceDescription currentservice = null;
55
56   /**
57    * original service passed to editor if we are modifying an existing service
58    * definition
59    */
60   jalview.ws.rest.RestServiceDescription oldservice = null;
61
62   public RestServiceEditorPane()
63   {
64     super();
65     // begin with initial text description box enabled.
66     urldesc.addKeyListener(new KeyListener()
67     {
68       @Override
69       public void keyTyped(KeyEvent e)
70       {
71       }
72
73       @Override
74       public void keyReleased(KeyEvent e)
75       {
76         refreshCutnPaste(true);
77       }
78
79       @Override
80       public void keyPressed(KeyEvent e)
81       {
82
83       }
84     });
85     panels.addChangeListener(new ChangeListener()
86     {
87
88       /**
89        * last panel selected - used to decide whether the service or the GUI has
90        * the latest info
91        */
92       Object lastComp;
93
94       @Override
95       public void stateChanged(ChangeEvent e)
96       {
97         if (lastComp != paste)
98         {
99           updateServiceFromGui();
100           refreshCutnPaste(false);
101         }
102         else
103         {
104           refreshCutnPaste(true);
105         }
106         lastComp = panels.getSelectedComponent();
107
108       }
109     });
110     currentservice = new RestServiceDescription("Analysis",
111             "service description", "service name", "http://localhost/", "",
112             null, false, false, '-');
113     initGuiWith(currentservice);
114     refreshCutnPaste(false);
115     updateButtons();
116   }
117
118   public RestServiceEditorPane(RestServiceDescription toedit)
119   {
120     this();
121     oldservice = toedit;
122     if (oldservice != null)
123     {
124       currentservice = new RestServiceDescription(toedit);
125     }
126     else
127     {
128       currentservice = new RestServiceDescription("Analysis",
129               "service description", "service name", "http://localhost/",
130               "", null, false, false, '-');
131     }
132     initGuiWith(currentservice);
133     refreshCutnPaste(false);
134     updateButtons();
135   }
136
137   /**
138    * refresh the buttons based on model state
139    */
140   public void updateButtons()
141   {
142     cancelButton.setEnabled(true);
143     okButton.setEnabled(currentservice != null && currentservice.isValid());
144
145   }
146
147   Vector<String> _iparam = new Vector<String>();
148
149   Vector<String> _rparam = new Vector<String>();
150
151   /**
152    * generate an editable URL service string and parameter list using the
153    * service
154    * 
155    * @param currentservice2
156    */
157   private void initGuiWith(RestServiceDescription currentservice)
158   {
159     _iparam.clear();
160     _rparam.clear();
161     action.removeAllItems();
162     action.addItem("Alignment");
163     action.addItem("Analysis");
164     gapChar.removeAllItems();
165     gapChar.addItem(".");
166     gapChar.addItem(" ");
167     gapChar.addItem("-");
168     if (currentservice == null)
169     {
170       name.setText("");
171       descr.setText("");
172       url.setText("");
173       urlsuff.setText("");
174       action.setSelectedItem("Analysis");
175       gapChar.setSelectedItem("-");
176     }
177     else
178     {
179       name.setText(currentservice.getName());
180       descr.setText(currentservice.getDescription());
181       url.setText(currentservice.getPostUrl());
182       urlsuff.setText(currentservice.getUrlSuffix());
183       for (Map.Entry<String, InputType> inparam : currentservice
184               .getInputParams().entrySet())
185       {
186         _iparam.add(inparam.getKey() + " "
187                 + inparam.getValue().getURLtokenPrefix() + ":"
188                 + inparam.getValue().getURLEncodedParameter().toString());
189       }
190
191       for (JvDataType oparam : currentservice.getResultDataTypes())
192       {
193         _rparam.add(oparam.name());
194       }
195       iprms.setListData(_iparam);
196       rdata.setListData(_rparam);
197
198       action.setSelectedItem(currentservice.getAction());
199
200       gapChar.setSelectedItem("" + currentservice.getGapCharacter());
201     }
202     revalidate();
203   }
204
205   private String getSelectedInputToken()
206   {
207     if (iprms.getSelectedIndex() > -1)
208     {
209       String toktoedit = (String) iprms.getSelectedValue();
210       toktoedit = toktoedit.substring(0, toktoedit.indexOf(" "));
211       return toktoedit;
212     }
213     return null;
214   }
215
216   @Override
217   protected void iprmListSelection_doubleClicked()
218   {
219     String toktoedit = getSelectedInputToken();
220     if (toktoedit != null)
221     {
222       InputType toedit = currentservice.getInputParams().get(toktoedit);
223       String oldParam = toktoedit;
224       RestInputParamEditDialog dialog = new RestInputParamEditDialog(this,
225               currentservice, toedit);
226       if (dialog.wasUpdated())
227       {
228         currentservice.getInputParams().remove(oldParam);
229         currentservice.getInputParams().put(dialog.current.token,
230                 dialog.current);
231         initGuiWith(currentservice);
232       }
233
234     }
235   }
236
237   @Override
238   protected void iprmsAdd_actionPerformed(ActionEvent e)
239   {
240     RestInputParamEditDialog dialog = new RestInputParamEditDialog(this,
241             currentservice, "param"
242                     + (1 + currentservice.getInputParams().size()));
243     if (dialog.wasUpdated())
244     {
245       currentservice.getInputParams().put(dialog.current.token,
246               dialog.current);
247       initGuiWith(currentservice);
248     }
249
250   }
251
252   @Override
253   protected void iprmsRem_actionPerformed(ActionEvent e)
254   {
255     String toktoedit = getSelectedInputToken();
256     if (toktoedit != null)
257     {
258       currentservice.getInputParams().remove(toktoedit);
259       initGuiWith(currentservice);
260
261     }
262   }
263
264   @Override
265   protected void rdata_rightClicked(MouseEvent mouse)
266   {
267     final int rdatasel = rdata.getSelectedIndex();
268     if (rdatasel > -1)
269     {
270       JPopupMenu popup = new JPopupMenu(MessageManager.getString("label.select_return_type"));
271       for (final JvDataType type : JvDataType.values())
272       {
273         popup.add(new JMenuItem(type.name())).addActionListener(
274                 new ActionListener()
275                 {
276
277                   @Override
278                   public void actionPerformed(ActionEvent e)
279                   {
280                     currentservice.getResultDataTypes().set(rdatasel, type);
281                     initGuiWith(currentservice);
282                     rdata.setSelectedIndex(rdatasel);
283                   }
284                 });
285       }
286       popup.show(rdata, mouse.getX(), mouse.getY());
287     }
288   }
289
290   @Override
291   protected void rdataAdd_actionPerformed(ActionEvent e)
292   {
293     int p;
294     if ((p = rdata.getSelectedIndex()) > -1)
295     {
296       currentservice.getResultDataTypes().add(p + 1, JvDataType.ANNOTATION);
297     }
298     else
299     {
300       currentservice.addResultDatatype(JvDataType.ANNOTATION);
301     }
302     initGuiWith(currentservice);
303     rdata.setSelectedIndex(p == -1 ? currentservice.getResultDataTypes()
304             .size() - 1 : p + 1);
305   }
306
307   @Override
308   protected void rdataNdown_actionPerformed(ActionEvent e)
309   {
310     int p;
311     if ((p = rdata.getSelectedIndex()) > -1 && p < _rparam.size() - 1)
312     {
313       List<JvDataType> rtypes = currentservice.getResultDataTypes();
314       JvDataType below = rtypes.get(p + 1);
315       rtypes.set(p + 1, rtypes.get(p));
316       rtypes.set(p, below);
317       initGuiWith(currentservice);
318       rdata.setSelectedIndex(p + 1);
319     }
320   }
321
322   @Override
323   protected void rdataNup_actionPerformed(ActionEvent e)
324   {
325     int p;
326     if ((p = rdata.getSelectedIndex()) > 0)
327     {
328       List<JvDataType> rtypes = currentservice.getResultDataTypes();
329       JvDataType above = rtypes.get(p - 1);
330       rtypes.set(p - 1, rtypes.get(p));
331       rtypes.set(p, above);
332       initGuiWith(currentservice);
333       rdata.setSelectedIndex(p - 1);
334     }
335   }
336
337   @Override
338   protected void rdataRem_actionPerformed(ActionEvent e)
339   {
340     if (rdata.getSelectedIndex() > -1)
341     {
342       currentservice.getResultDataTypes().remove(rdata.getSelectedIndex());
343       initGuiWith(currentservice);
344     }
345   }
346
347   private boolean updateServiceFromGui()
348   {
349     Map<String, InputType> inputTypes = new HashMap<String, InputType>();
350     StringBuffer warnings = new StringBuffer();
351     for (String its : _iparam)
352     {
353       Matcher mtch = Pattern.compile("(\\S+)\\s(\\S+):\\[(.+)]").matcher(
354               its);
355       if (mtch.find())
356       {
357         if (!RestServiceDescription.parseTypeString(mtch.group(2) + ":"
358                 + mtch.group(3), mtch.group(1), mtch.group(2),
359                 mtch.group(3), inputTypes, warnings))
360         {
361           System.err
362                   .println("IMPLEMENTATION PROBLEM: Cannot parse RestService input parameter string '"
363                           + its + "'" + "\n" + warnings);
364         }
365       }
366     }
367     char gc = gapChar.getSelectedItem() == null ? ' ' : ((String) gapChar
368             .getSelectedItem()).charAt(0);
369     RestServiceDescription newService = new RestServiceDescription(
370             (String) action.getSelectedItem(), descr.getText().trim(), name
371                     .getText().trim(), url.getText().trim(), urlsuff
372                     .getText().trim(), inputTypes, hSeparable.isSelected(),
373             vSeparable.isSelected(), gc);
374
375     if (newService.isValid())
376     {
377       for (String its : _rparam)
378       {
379         JvDataType dtype;
380         try
381         {
382           dtype = JvDataType.valueOf(its);
383           newService.addResultDatatype(dtype);
384         } catch (Throwable x)
385         {
386
387           System.err
388                   .println("IMPLEMENTATION PROBLEM: Cannot parse RestService output parameter string '"
389                           + its + "'" + "\n" + warnings);
390         }
391       }
392       currentservice = newService;
393       return true;
394     }
395     else
396     {
397       System.err
398               .println("IMPLEMENTATION PROBLEM: Restservice generated from GUI is invalid\n"
399                       + warnings);
400
401     }
402     return false;
403   }
404
405   protected void refreshCutnPaste(boolean reparse)
406   {
407     if (!reparse && currentservice.isValid())
408     {
409       urldesc.setText(currentservice.toString());
410       parseWarnings.setVisible(false);
411     }
412     else
413     {
414       if (reparse)
415       {
416         String txt = urldesc.getText().trim();
417         if (txt.length() > 0)
418         {
419           RestServiceDescription rsd = null;
420           try
421           {
422             rsd = new RestServiceDescription(txt);
423             if (rsd.isValid())
424             {
425               parseWarnings.setVisible(false);
426               parseRes.setText("");
427               initGuiWith(currentservice = rsd);
428             }
429             else
430             {
431               parseRes.setText(MessageManager.formatMessage("label.parsing_failed_syntax_errors_shown_below_param", new String[]{rsd.getInvalidMessage()}));
432               parseWarnings.setVisible(true);
433             }
434           } catch (Throwable e)
435           {
436             e.printStackTrace();
437             parseRes.setText(MessageManager.formatMessage("label.parsing_failed_unrecoverable_exception_thrown_param", new String[]{e.toString()}));
438             parseWarnings.setVisible(true);
439           }
440         }
441         paste.revalidate();
442       }
443     }
444
445   }
446
447   public static void main(String[] args)
448   {
449     if (args.length == 0)
450     {
451       new Thread(new Runnable()
452       {
453         boolean visible = true;
454
455         public void run()
456         {
457           boolean nulserv = true;
458           while (visible)
459           {
460             final Thread runner = Thread.currentThread();
461             JFrame df = new JFrame();
462             df.getContentPane().setLayout(new BorderLayout());
463             df.getContentPane().add(
464                     (nulserv = !nulserv) ? new RestServiceEditorPane(
465                             jalview.ws.rest.RestClient
466                                     .makeShmmrRestClient()
467                                     .getRestDescription())
468                             : new RestServiceEditorPane(),
469                     BorderLayout.CENTER);
470             df.setBounds(100, 100, 600, 400);
471             df.addComponentListener(new ComponentListener()
472             {
473
474               @Override
475               public void componentShown(ComponentEvent e)
476               {
477
478               }
479
480               @Override
481               public void componentResized(ComponentEvent e)
482               {
483
484               }
485
486               @Override
487               public void componentMoved(ComponentEvent e)
488               {
489
490               }
491
492               @Override
493               public void componentHidden(ComponentEvent e)
494               {
495                 visible = false;
496                 runner.interrupt();
497
498               }
499             });
500             df.setVisible(true);
501             while (visible)
502             {
503               try
504               {
505                 Thread.sleep(10000);
506               } catch (Exception x)
507               {
508               }
509               ;
510             }
511             visible = true;
512           }
513         }
514       }).start();
515
516     }
517   }
518
519   String finalService = null;
520
521   public void showDialog(String title)
522   {
523     if (oldservice != null)
524     {
525       finalService = oldservice.toString();
526     }
527     JalviewDialog jvd = new JalviewDialog()
528     {
529
530       @Override
531       protected void raiseClosed()
532       {
533         // TODO Auto-generated method stub
534
535       }
536
537       @Override
538       protected void okPressed()
539       {
540         updateServiceFromGui();
541         finalService = currentservice.toString();
542       }
543
544       @Override
545       protected void cancelPressed()
546       {
547
548       }
549     };
550     JPanel pane = new JPanel(new BorderLayout()), okcancel = new JPanel(
551             new FlowLayout());
552     pane.add(this, BorderLayout.CENTER);
553     okcancel.add(jvd.ok);
554     okcancel.add(jvd.cancel);
555     pane.add(okcancel, BorderLayout.SOUTH);
556     jvd.initDialogFrame(pane, true, true, title, 600, 350);
557     jvd.waitForInput();
558   }
559
560   public String getEditedRestService()
561   {
562     return finalService;
563   }
564 }