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