JAL-2418 source formatting
[jalview.git] / src / jalview / gui / RestServiceEditorPane.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.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,
245             "param" + (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(
274               MessageManager.getString("label.select_return_type"));
275       for (final JvDataType type : JvDataType.values())
276       {
277         popup.add(new JMenuItem(type.name()))
278                 .addActionListener(new ActionListener()
279                 {
280
281                   @Override
282                   public void actionPerformed(ActionEvent e)
283                   {
284                     currentservice.getResultDataTypes().set(rdatasel, type);
285                     initGuiWith(currentservice);
286                     rdata.setSelectedIndex(rdatasel);
287                   }
288                 });
289       }
290       popup.show(rdata, mouse.getX(), mouse.getY());
291     }
292   }
293
294   @Override
295   protected void rdataAdd_actionPerformed(ActionEvent e)
296   {
297     int p;
298     if ((p = rdata.getSelectedIndex()) > -1)
299     {
300       currentservice.getResultDataTypes().add(p + 1, JvDataType.ANNOTATION);
301     }
302     else
303     {
304       currentservice.addResultDatatype(JvDataType.ANNOTATION);
305     }
306     initGuiWith(currentservice);
307     rdata.setSelectedIndex(
308             p == -1 ? currentservice.getResultDataTypes().size() - 1
309                     : p + 1);
310   }
311
312   @Override
313   protected void rdataNdown_actionPerformed(ActionEvent e)
314   {
315     int p;
316     if ((p = rdata.getSelectedIndex()) > -1 && p < _rparam.size() - 1)
317     {
318       List<JvDataType> rtypes = currentservice.getResultDataTypes();
319       JvDataType below = rtypes.get(p + 1);
320       rtypes.set(p + 1, rtypes.get(p));
321       rtypes.set(p, below);
322       initGuiWith(currentservice);
323       rdata.setSelectedIndex(p + 1);
324     }
325   }
326
327   @Override
328   protected void rdataNup_actionPerformed(ActionEvent e)
329   {
330     int p;
331     if ((p = rdata.getSelectedIndex()) > 0)
332     {
333       List<JvDataType> rtypes = currentservice.getResultDataTypes();
334       JvDataType above = rtypes.get(p - 1);
335       rtypes.set(p - 1, rtypes.get(p));
336       rtypes.set(p, above);
337       initGuiWith(currentservice);
338       rdata.setSelectedIndex(p - 1);
339     }
340   }
341
342   @Override
343   protected void rdataRem_actionPerformed(ActionEvent e)
344   {
345     if (rdata.getSelectedIndex() > -1)
346     {
347       currentservice.getResultDataTypes().remove(rdata.getSelectedIndex());
348       initGuiWith(currentservice);
349     }
350   }
351
352   private boolean updateServiceFromGui()
353   {
354     Map<String, InputType> inputTypes = new HashMap<String, InputType>();
355     StringBuffer warnings = new StringBuffer();
356     for (String its : _iparam)
357     {
358       Matcher mtch = Pattern.compile("(\\S+)\\s(\\S+):\\[(.+)]")
359               .matcher(its);
360       if (mtch.find())
361       {
362         if (!RestServiceDescription.parseTypeString(
363                 mtch.group(2) + ":" + mtch.group(3), mtch.group(1),
364                 mtch.group(2), mtch.group(3), inputTypes, warnings))
365         {
366           System.err.println(
367                   "IMPLEMENTATION PROBLEM: Cannot parse RestService input parameter string '"
368                           + its + "'" + "\n" + warnings);
369         }
370       }
371     }
372     char gc = gapChar.getSelectedItem() == null ? ' '
373             : ((String) gapChar.getSelectedItem()).charAt(0);
374     RestServiceDescription newService = new RestServiceDescription(
375             (String) action.getSelectedItem(), descr.getText().trim(),
376             name.getText().trim(), url.getText().trim(),
377             urlsuff.getText().trim(), inputTypes, hSeparable.isSelected(),
378             vSeparable.isSelected(), gc);
379
380     if (newService.isValid())
381     {
382       for (String its : _rparam)
383       {
384         JvDataType dtype;
385         try
386         {
387           dtype = JvDataType.valueOf(its);
388           newService.addResultDatatype(dtype);
389         } catch (Throwable x)
390         {
391
392           System.err.println(
393                   "IMPLEMENTATION PROBLEM: Cannot parse RestService output parameter string '"
394                           + its + "'" + "\n" + warnings);
395         }
396       }
397       currentservice = newService;
398       return true;
399     }
400     else
401     {
402       System.err.println(
403               "IMPLEMENTATION PROBLEM: Restservice generated from GUI is invalid\n"
404                       + warnings);
405
406     }
407     return false;
408   }
409
410   protected void refreshCutnPaste(boolean reparse)
411   {
412     if (!reparse && currentservice.isValid())
413     {
414       urldesc.setText(currentservice.toString());
415       parseWarnings.setVisible(false);
416     }
417     else
418     {
419       if (reparse)
420       {
421         String txt = urldesc.getText().trim();
422         if (txt.length() > 0)
423         {
424           RestServiceDescription rsd = null;
425           try
426           {
427             rsd = new RestServiceDescription(txt);
428             if (rsd.isValid())
429             {
430               parseWarnings.setVisible(false);
431               parseRes.setText("");
432               initGuiWith(currentservice = rsd);
433             }
434             else
435             {
436               parseRes.setText(MessageManager.formatMessage(
437                       "label.parsing_failed_syntax_errors_shown_below_param",
438                       new String[]
439                       { rsd.getInvalidMessage() }));
440               parseWarnings.setVisible(true);
441             }
442           } catch (Throwable e)
443           {
444             e.printStackTrace();
445             parseRes.setText(MessageManager.formatMessage(
446                     "label.parsing_failed_unrecoverable_exception_thrown_param",
447                     new String[]
448                     { e.toString() }));
449             parseWarnings.setVisible(true);
450           }
451         }
452         paste.revalidate();
453       }
454     }
455
456   }
457
458   public static void main(String[] args)
459   {
460     if (args.length == 0)
461     {
462       new Thread(new Runnable()
463       {
464         boolean visible = true;
465
466         public void run()
467         {
468           boolean nulserv = true;
469           while (visible)
470           {
471             final Thread runner = Thread.currentThread();
472             JFrame df = new JFrame();
473             df.getContentPane().setLayout(new BorderLayout());
474             df.getContentPane().add((nulserv = !nulserv)
475                     ? new RestServiceEditorPane(jalview.ws.rest.RestClient
476                             .makeShmmrRestClient().getRestDescription())
477                     : new RestServiceEditorPane(), BorderLayout.CENTER);
478             df.setBounds(100, 100, 600, 400);
479             df.addComponentListener(new ComponentListener()
480             {
481
482               @Override
483               public void componentShown(ComponentEvent e)
484               {
485
486               }
487
488               @Override
489               public void componentResized(ComponentEvent e)
490               {
491
492               }
493
494               @Override
495               public void componentMoved(ComponentEvent e)
496               {
497
498               }
499
500               @Override
501               public void componentHidden(ComponentEvent e)
502               {
503                 visible = false;
504                 runner.interrupt();
505
506               }
507             });
508             df.setVisible(true);
509             while (visible)
510             {
511               try
512               {
513                 Thread.sleep(10000);
514               } catch (Exception x)
515               {
516               }
517               ;
518             }
519             visible = true;
520           }
521         }
522       }).start();
523
524     }
525   }
526
527   String finalService = null;
528
529   public void showDialog(String title)
530   {
531     if (oldservice != null)
532     {
533       finalService = oldservice.toString();
534     }
535     JalviewDialog jvd = new JalviewDialog()
536     {
537
538       @Override
539       protected void raiseClosed()
540       {
541         // TODO Auto-generated method stub
542
543       }
544
545       @Override
546       protected void okPressed()
547       {
548         updateServiceFromGui();
549         finalService = currentservice.toString();
550       }
551
552       @Override
553       protected void cancelPressed()
554       {
555
556       }
557     };
558     JPanel pane = new JPanel(new BorderLayout()),
559             okcancel = new JPanel(new FlowLayout());
560     pane.add(this, BorderLayout.CENTER);
561     okcancel.add(jvd.ok);
562     okcancel.add(jvd.cancel);
563     pane.add(okcancel, BorderLayout.SOUTH);
564     jvd.initDialogFrame(pane, true, true, title, 600, 350);
565     jvd.waitForInput();
566   }
567
568   public String getEditedRestService()
569   {
570     return finalService;
571   }
572 }