4f9c13e1cf9b048090bd2db9a37aba7f3a82f8bc
[jalview.git] / src / jalview / gui / RestServiceEditorPane.java
1 package jalview.gui;
2
3 import jalview.io.packed.DataProvider.JvDataType;
4 import jalview.jbgui.GRestServiceEditorPane;
5 import jalview.ws.rest.InputType;
6 import jalview.ws.rest.RestServiceDescription;
7
8 import java.awt.BorderLayout;
9 import java.awt.event.ActionEvent;
10 import java.awt.event.ActionListener;
11 import java.awt.event.ComponentEvent;
12 import java.awt.event.ComponentListener;
13 import java.awt.event.KeyEvent;
14 import java.awt.event.KeyListener;
15 import java.awt.event.MouseEvent;
16 import java.util.HashMap;
17 import java.util.List;
18 import java.util.Map;
19 import java.util.Vector;
20 import java.util.regex.Matcher;
21 import java.util.regex.Pattern;
22
23 import javax.swing.JFrame;
24 import javax.swing.JMenuItem;
25 import javax.swing.JPopupMenu;
26 import javax.swing.event.ChangeEvent;
27 import javax.swing.event.ChangeListener;
28
29 public class RestServiceEditorPane extends GRestServiceEditorPane
30 {
31   /**
32    * the latest version of the service definition.
33    */
34   jalview.ws.rest.RestServiceDescription currentservice = null;
35
36   /**
37    * original service passed to editor if we are modifying an existing service
38    * definition
39    */
40   jalview.ws.rest.RestServiceDescription oldservice = null;
41
42   public RestServiceEditorPane()
43   {
44     super();
45     // begin with initial text description box enabled.
46     urldesc.addKeyListener(new KeyListener()
47     {
48       @Override
49       public void keyTyped(KeyEvent e)
50       {
51       }
52       
53       @Override
54       public void keyReleased(KeyEvent e)
55       {
56         refreshCutnPaste(true);        
57       }
58       
59       @Override
60       public void keyPressed(KeyEvent e)
61       {
62         
63       }
64     });
65     panels.addChangeListener(new ChangeListener()
66     {
67       Object lastComp;
68       @Override
69       public void stateChanged(ChangeEvent e)
70       {
71         if (lastComp!=paste) {
72           updateServiceFromGui();
73           refreshCutnPaste(false);
74         } else {
75           refreshCutnPaste(true);
76         }
77         lastComp = panels.getSelectedComponent();
78         
79       }
80       });
81     currentservice = new RestServiceDescription("Analysis", "service description", "service name", "http://localhost/", "", null, false, false, '-');
82     initGuiWith(currentservice);
83     refreshCutnPaste(false);
84     updateButtons();
85   }
86
87   public RestServiceEditorPane(RestServiceDescription toedit)
88   {
89     super();
90     oldservice = toedit;
91     if (oldservice!=null)
92     {    currentservice = new RestServiceDescription(toedit);
93     } else {
94       currentservice = new RestServiceDescription("Analysis", "service description", "service name", "http://localhost/", "", null, false, false, '-');
95     }
96     initGuiWith(currentservice);
97     refreshCutnPaste(false);
98     updateButtons();
99   }
100
101   /**
102    * refresh the buttons based on model state
103    */
104   public void updateButtons()
105   {
106     cancelButton.setEnabled(true);
107     okButton.setEnabled(currentservice != null && currentservice.isValid());
108
109   }
110
111   Vector<String> _iparam = new Vector<String>();
112
113   Vector<String> _rparam = new Vector<String>();
114
115   /**
116    * generate an editable URL service string and parameter list using the
117    * service
118    * 
119    * @param currentservice2
120    */
121   private void initGuiWith(RestServiceDescription currentservice)
122   {
123     _iparam.clear();
124     _rparam.clear();
125     action.removeAllItems();
126     action.addItem("Alignment");
127     action.addItem("Analysis");
128     gapChar.removeAllItems();
129     gapChar.addItem(".");
130     gapChar.addItem(" ");
131     gapChar.addItem("-");
132     if (currentservice==null)
133     {
134       name.setText("");
135       descr.setText("");
136       url.setText("");
137       urlsuff.setText("");
138       action.setSelectedItem("Analysis");
139       gapChar.setSelectedItem("-");
140     } else {
141     name.setText(currentservice.getName());
142     descr.setText(currentservice.getDescription());
143     url.setText(currentservice.getPostUrl());
144     urlsuff.setText(currentservice.getUrlSuffix());
145     for (Map.Entry<String, InputType> inparam : currentservice
146             .getInputParams().entrySet())
147     {
148       _iparam.add(inparam.getKey() + " "
149               + inparam.getValue().getURLtokenPrefix() + ":"
150               + inparam.getValue().getURLEncodedParameter().toString());
151     }
152       
153     for (JvDataType oparam : currentservice.getResultDataTypes())
154     {
155       _rparam.add(oparam.name());
156     }
157     iprms.setListData(_iparam);
158     rdata.setListData(_rparam);
159
160     action.setSelectedItem(currentservice.getAction());
161
162     gapChar.setSelectedItem(""+currentservice.getGapCharacter());
163     }
164     revalidate();
165   }
166   private String getSelectedInputToken()
167   {
168     if (iprms.getSelectedIndex()>-1)
169     {
170     String toktoedit = (String) iprms.getSelectedValue();
171     toktoedit=toktoedit.substring(0, toktoedit.indexOf(" "));
172     return toktoedit;
173     }
174     return null;
175   }
176   @Override
177   protected void iprmListSelection_doubleClicked()
178   {
179     String toktoedit = getSelectedInputToken();
180     if (toktoedit!=null)
181     {
182       InputType toedit = currentservice.getInputParams().get(toktoedit);
183       String oldParam=toktoedit;
184       RestInputParamEditDialog dialog=new RestInputParamEditDialog(this, currentservice, toedit);
185       if (dialog.wasUpdated()) {
186         currentservice.getInputParams().remove(oldParam);
187         currentservice.getInputParams().put(dialog.current.token, dialog.current);
188         initGuiWith(currentservice);
189       }
190       
191     }
192   }
193   @Override
194   protected void iprmsAdd_actionPerformed(ActionEvent e)
195   {
196     RestInputParamEditDialog dialog=new RestInputParamEditDialog(this, currentservice, "param"+(1+currentservice.getInputParams().size()));
197     if (dialog.wasUpdated()) {
198       currentservice.getInputParams().put(dialog.current.token, dialog.current);
199       initGuiWith(currentservice);
200     }
201
202   }
203   @Override
204   protected void iprmsRem_actionPerformed(ActionEvent e)
205   {
206     String toktoedit = getSelectedInputToken();
207     if (toktoedit!=null)
208     {
209       currentservice.getInputParams().remove(toktoedit);
210       initGuiWith(currentservice);
211
212     }
213   }
214   @Override
215   protected void rdata_rightClicked(MouseEvent mouse)
216   {
217     final int rdatasel = rdata.getSelectedIndex();
218     if (rdatasel>-1)
219     {
220       JPopupMenu popup = new JPopupMenu("Select return type");
221       for (final JvDataType type:JvDataType.values()) {
222         popup.add(new JMenuItem(type.name())).addActionListener(new ActionListener()
223         {
224           
225           @Override
226           public void actionPerformed(ActionEvent e)
227           {
228             currentservice.getResultDataTypes().set(rdatasel, type);
229             initGuiWith(currentservice);   
230             rdata.setSelectedIndex(rdatasel);
231           }
232         });
233       }
234       popup.show(rdata, mouse.getX(), mouse.getY());
235     }
236   }
237   @Override
238   protected void rdataAdd_actionPerformed(ActionEvent e)
239   {
240     int p;
241     if ((p=rdata.getSelectedIndex())>-1)
242     {
243       currentservice.getResultDataTypes().add(p+1, JvDataType.ANNOTATION);
244     } else {
245       currentservice.addResultDatatype(JvDataType.ANNOTATION);
246     }
247     initGuiWith(currentservice);
248     rdata.setSelectedIndex(p==-1 ? currentservice.getResultDataTypes().size()-1 : p+1);
249   }
250   @Override
251   protected void rdataNdown_actionPerformed(ActionEvent e)
252   {
253     int p;
254     if ((p=rdata.getSelectedIndex())>-1 && p<_rparam.size()-1)
255     {
256       List<JvDataType> rtypes = currentservice.getResultDataTypes();
257       JvDataType below = rtypes.get(p+1);
258       rtypes.set(p+1, rtypes.get(p));
259       rtypes.set(p, below);
260       initGuiWith(currentservice);
261       rdata.setSelectedIndex(p+1);
262     }
263   }
264   @Override
265   protected void rdataNup_actionPerformed(ActionEvent e)
266   {
267     int p;
268     if ((p=rdata.getSelectedIndex())>0)
269     {
270       List<JvDataType> rtypes = currentservice.getResultDataTypes();
271       JvDataType above = rtypes.get(p-1);
272       rtypes.set(p-1, rtypes.get(p));
273       rtypes.set(p, above);
274       initGuiWith(currentservice);
275       rdata.setSelectedIndex(p-1);
276     }
277   }
278   @Override
279   protected void rdataRem_actionPerformed(ActionEvent e)
280   {
281     if (rdata.getSelectedIndex()>-1)
282     {
283       currentservice.getResultDataTypes().remove(rdata.getSelectedIndex());
284       initGuiWith(currentservice);
285     }
286   }
287
288   private boolean updateServiceFromGui() {
289     Map<String,InputType>inputTypes = new HashMap<String, InputType>();
290     StringBuffer warnings=new StringBuffer();
291     for (String its:_iparam)
292     {
293       Matcher mtch = Pattern.compile("(\\S+)\\s(\\S+):\\[(.+)]").matcher(its);
294       if (mtch.find()) {
295         if (!RestServiceDescription.parseTypeString(mtch.group(2)+":"+mtch.group(3), mtch.group(1), mtch.group(2),mtch.group(3), inputTypes, warnings))
296         {
297           System.err.println("IMPLEMENTATION PROBLEM: Cannot parse RestService input parameter string '"+its+"'"+"\n"+warnings);
298         }        
299       }
300     }
301     char gc = gapChar.getSelectedItem()==null ? ' ' : ((String)gapChar.getSelectedItem()).charAt(0);
302     RestServiceDescription newService = new RestServiceDescription((String) action.getSelectedItem(),
303           descr.getText().trim(), name.getText().trim(), url.getText().trim(), urlsuff.getText().trim(), inputTypes, hSeparable.isSelected(), vSeparable.isSelected(), gc);
304             
305     if (newService.isValid())
306     {
307       for (String its:_rparam)
308       {
309         JvDataType dtype;
310         try {
311           dtype = JvDataType.valueOf(its);
312           newService.addResultDatatype(dtype);
313         }
314         catch (Throwable x)
315         {
316
317           System.err.println("IMPLEMENTATION PROBLEM: Cannot parse RestService output parameter string '"+its+"'"+"\n"+warnings);
318         }
319       }
320       currentservice = newService;
321       return true;
322     } else {
323       System.err.println("IMPLEMENTATION PROBLEM: Restservice generated from GUI is invalid\n"+warnings);
324
325     }
326     return false;
327   }
328   protected void refreshCutnPaste(boolean reparse)
329   {
330     if (!reparse && currentservice.isValid())
331     {
332       urldesc.setText(currentservice.toString());
333       parseWarnings.setVisible(false);
334     }
335     else
336     {
337       if (reparse)
338       {
339         String txt = urldesc.getText().trim();
340         if (txt.length() > 0)
341         {
342           RestServiceDescription rsd = null;
343           try
344           {
345             rsd = new RestServiceDescription(txt);
346             if (rsd.isValid())
347             {
348               parseWarnings.setVisible(false);
349               parseRes.setText("");
350               initGuiWith(currentservice=rsd);
351             }
352             else
353             {
354               parseRes.setText("Parsing failed. Syntax errors shown below\n"
355                       + rsd.getInvalidMessage());
356               parseWarnings.setVisible(true);
357             }
358           } catch (Throwable e)
359           {
360             e.printStackTrace();
361             parseRes.setText("\nParsing failed. An unrecoverable exception was thrown:\n"
362                     + e.toString());
363             parseWarnings.setVisible(true);
364           }
365         }
366         paste.revalidate();
367       }
368     }
369     
370   }
371
372   public static void main(String[] args)
373   {
374     if (args.length == 0)
375     {
376       new Thread(new Runnable()
377       {
378         boolean visible = true;
379
380         public void run()
381         {
382           boolean nulserv=true;
383           while (visible)
384           {
385             final Thread runner = Thread.currentThread();
386             JFrame df = new JFrame();
387             df.getContentPane().setLayout(new BorderLayout());
388             df.getContentPane().add(
389                     (nulserv=!nulserv) ? new RestServiceEditorPane(jalview.ws.rest.RestClient
390                             .makeShmmrRestClient().getRestDescription()) : new RestServiceEditorPane(), 
391                     BorderLayout.CENTER);
392             df.setBounds(100, 100, 600, 400);
393             df.addComponentListener(new ComponentListener()
394             {
395
396               @Override
397               public void componentShown(ComponentEvent e)
398               {
399
400               }
401
402               @Override
403               public void componentResized(ComponentEvent e)
404               {
405
406               }
407
408               @Override
409               public void componentMoved(ComponentEvent e)
410               {
411
412               }
413
414               @Override
415               public void componentHidden(ComponentEvent e)
416               {
417                 visible = false;
418                 runner.interrupt();
419
420               }
421             });
422             df.setVisible(true);
423             while (visible)
424             {
425               try
426               {
427                 Thread.sleep(10000);
428               } catch (Exception x)
429               {
430               }
431               ;
432             }
433             visible = true;
434           }
435         }
436       }).start();
437
438     }
439   }
440 }