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