JAL-2071 further refactoring, optimisation, and house keeping for the generic Free...
[jalview.git] / src / jalview / fts / core / GFTSPanel.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
22 package jalview.fts.core;
23
24 import jalview.fts.api.FTSDataColumnI;
25 import jalview.fts.api.GFTSPanelI;
26 import jalview.fts.core.FTSDataColumnPreferences.PreferenceSource;
27 import jalview.gui.Desktop;
28 import jalview.gui.IProgressIndicator;
29 import jalview.gui.JvSwingUtils;
30 import jalview.gui.SequenceFetcher;
31 import jalview.util.MessageManager;
32
33 import java.awt.BorderLayout;
34 import java.awt.CardLayout;
35 import java.awt.Dimension;
36 import java.awt.event.ActionEvent;
37 import java.awt.event.ActionListener;
38 import java.awt.event.KeyAdapter;
39 import java.awt.event.KeyEvent;
40 import java.awt.event.MouseAdapter;
41 import java.awt.event.MouseEvent;
42 import java.util.ArrayList;
43 import java.util.Arrays;
44 import java.util.Collection;
45 import java.util.Collections;
46 import java.util.Comparator;
47 import java.util.List;
48
49 import javax.swing.ImageIcon;
50 import javax.swing.JButton;
51 import javax.swing.JComboBox;
52 import javax.swing.JFrame;
53 import javax.swing.JInternalFrame;
54 import javax.swing.JLabel;
55 import javax.swing.JPanel;
56 import javax.swing.JScrollPane;
57 import javax.swing.JTabbedPane;
58 import javax.swing.JTable;
59 import javax.swing.JTextField;
60 import javax.swing.event.ChangeEvent;
61 import javax.swing.event.ChangeListener;
62 import javax.swing.event.DocumentEvent;
63 import javax.swing.event.DocumentListener;
64 import javax.swing.table.DefaultTableModel;
65
66 /**
67  * This class provides the swing GUI layout for FTS Panel and implements most of
68  * the contracts defined in GFSPanelI
69  * 
70  * @author tcnofoegbu
71  *
72  */
73
74 @SuppressWarnings("serial")
75 public abstract class GFTSPanel extends JPanel implements GFTSPanelI
76 {
77   protected JInternalFrame mainFrame = new JInternalFrame(
78           getFTSFrameTitle());
79
80   protected IProgressIndicator progressIdicator;
81
82   protected JComboBox<FTSDataColumnI> cmb_searchTarget = new JComboBox<FTSDataColumnI>();
83
84   protected JButton btn_ok = new JButton();
85
86   protected JButton btn_back = new JButton();
87
88   protected JButton btn_cancel = new JButton();
89
90   protected JTextField txt_search = new JTextField(20);
91
92   protected SequenceFetcher seqFetcher;
93
94   protected Collection<FTSDataColumnI> wantedFields;
95
96   private JTable tbl_summary = new JTable()
97   {
98     @Override
99     public String getToolTipText(MouseEvent evt)
100     {
101       String toolTipText = null;
102       java.awt.Point pnt = evt.getPoint();
103       int rowIndex = rowAtPoint(pnt);
104       int colIndex = columnAtPoint(pnt);
105
106       try
107       {
108         if (getValueAt(rowIndex, colIndex) == null)
109         {
110           return null;
111         }
112         toolTipText = getValueAt(rowIndex, colIndex).toString();
113
114       } catch (Exception e)
115       {
116         e.printStackTrace();
117       }
118       toolTipText = (toolTipText == null ? null
119               : (toolTipText.length() > 500 ? JvSwingUtils.wrapTooltip(
120                       true, toolTipText.subSequence(0, 500) + "...")
121                       : JvSwingUtils.wrapTooltip(true, toolTipText)));
122
123       return toolTipText;
124     }
125   };
126
127   protected StringBuilder errorWarning = new StringBuilder();
128
129   protected JScrollPane scrl_searchResult = new JScrollPane(tbl_summary);
130
131   protected ImageIcon warningImage = new ImageIcon(getClass().getResource(
132           "/images/warning.gif"));
133
134   protected ImageIcon loadingImage = new ImageIcon(getClass().getResource(
135           "/images/loading.gif"));
136
137   protected JLabel lbl_warning = new JLabel(warningImage);
138
139   protected JLabel lbl_loading = new JLabel(loadingImage);
140
141   private JTabbedPane tabbedPane = new JTabbedPane();
142
143   private JPanel pnl_actions = new JPanel();
144
145   private JPanel pnl_results = new JPanel(new CardLayout());
146
147   private JPanel pnl_inputs = new JPanel();
148
149   private BorderLayout mainLayout = new BorderLayout();
150
151   protected Object[] previousWantedFields;
152
153   public GFTSPanel()
154   {
155     try
156     {
157       jbInit();
158       mainFrame.invalidate();
159       mainFrame.pack();
160     } catch (Exception e)
161     {
162       e.printStackTrace();
163     }
164   }
165
166   /**
167    * Initializes the GUI default properties
168    * 
169    * @throws Exception
170    */
171   private void jbInit() throws Exception
172   {
173     lbl_warning.setVisible(false);
174     lbl_warning.setFont(new java.awt.Font("Verdana", 0, 12));
175     lbl_loading.setVisible(false);
176     lbl_loading.setFont(new java.awt.Font("Verdana", 0, 12));
177
178     tbl_summary.setAutoResizeMode(JTable.AUTO_RESIZE_ALL_COLUMNS);
179     tbl_summary.setAutoCreateRowSorter(true);
180     tbl_summary.getTableHeader().setReorderingAllowed(false);
181     tbl_summary.addMouseListener(new MouseAdapter()
182     {
183       @Override
184       public void mouseClicked(MouseEvent e)
185       {
186         validateSelection();
187       }
188
189       @Override
190       public void mouseReleased(MouseEvent e)
191       {
192         validateSelection();
193       }
194     });
195     tbl_summary.addKeyListener(new KeyAdapter()
196     {
197       @Override
198       public void keyPressed(KeyEvent evt)
199       {
200         validateSelection();
201         switch (evt.getKeyCode())
202         {
203         case KeyEvent.VK_ESCAPE: // escape key
204           btn_back_ActionPerformed();
205           break;
206         case KeyEvent.VK_ENTER: // enter key
207           if (btn_ok.isEnabled())
208           {
209             okAction();
210           }
211           evt.consume();
212           break;
213         case KeyEvent.VK_TAB: // tab key
214           if (evt.isShiftDown())
215           {
216             tabbedPane.requestFocus();
217           }
218           else
219           {
220             btn_back.requestFocus();
221           }
222           evt.consume();
223           break;
224         default:
225           return;
226         }
227       }
228     });
229
230     btn_back.setFont(new java.awt.Font("Verdana", 0, 12));
231     btn_back.setText(MessageManager.getString("action.back"));
232     btn_back.addActionListener(new java.awt.event.ActionListener()
233     {
234       @Override
235       public void actionPerformed(ActionEvent e)
236       {
237         btn_back_ActionPerformed();
238       }
239     });
240     btn_back.addKeyListener(new KeyAdapter()
241     {
242       @Override
243       public void keyPressed(KeyEvent evt)
244       {
245         if (evt.getKeyCode() == KeyEvent.VK_ENTER)
246         {
247           btn_back_ActionPerformed();
248         }
249       }
250     });
251
252     btn_ok.setEnabled(false);
253     btn_ok.setFont(new java.awt.Font("Verdana", 0, 12));
254     btn_ok.setText(MessageManager.getString("action.ok"));
255     btn_ok.addActionListener(new java.awt.event.ActionListener()
256     {
257       @Override
258       public void actionPerformed(ActionEvent e)
259       {
260         okAction();
261       }
262     });
263     btn_ok.addKeyListener(new KeyAdapter()
264     {
265       @Override
266       public void keyPressed(KeyEvent evt)
267       {
268         if (evt.getKeyCode() == KeyEvent.VK_ENTER)
269         {
270           okAction();
271         }
272       }
273     });
274
275     btn_cancel.setFont(new java.awt.Font("Verdana", 0, 12));
276     btn_cancel.setText(MessageManager.getString("action.cancel"));
277     btn_cancel.addActionListener(new java.awt.event.ActionListener()
278     {
279       @Override
280       public void actionPerformed(ActionEvent e)
281       {
282         btn_cancel_ActionPerformed();
283       }
284     });
285     btn_cancel.addKeyListener(new KeyAdapter()
286     {
287       @Override
288       public void keyPressed(KeyEvent evt)
289       {
290         if (evt.getKeyCode() == KeyEvent.VK_ENTER)
291         {
292           btn_cancel_ActionPerformed();
293         }
294       }
295     });
296
297     scrl_searchResult.setPreferredSize(new Dimension(500, 300));
298     scrl_searchResult
299             .setHorizontalScrollBarPolicy(JScrollPane.HORIZONTAL_SCROLLBAR_NEVER);
300
301     cmb_searchTarget.setFont(new java.awt.Font("Verdana", 0, 12));
302     cmb_searchTarget.addActionListener(new ActionListener()
303     {
304       @Override
305       public void actionPerformed(ActionEvent e)
306       {
307         String tooltipText;
308         if ("all".equalsIgnoreCase(getCmbSearchTarget().getSelectedItem()
309                 .toString()))
310         {
311           tooltipText = MessageManager.getString("label.search_all");
312         }
313         else if ("pdb id".equalsIgnoreCase(getCmbSearchTarget()
314                 .getSelectedItem().toString()))
315         {
316           tooltipText = MessageManager
317                   .getString("label.separate_multiple_accession_ids");
318         }
319         else
320         {
321           tooltipText = MessageManager.formatMessage(
322                   "label.separate_multiple_query_values",
323                   new Object[] { getCmbSearchTarget().getSelectedItem()
324                           .toString() });
325         }
326         txt_search.setToolTipText(JvSwingUtils.wrapTooltip(true,
327                 tooltipText));
328         searchAction();
329       }
330     });
331
332     populateCmbSearchTargetOptions();
333
334     txt_search.setFont(new java.awt.Font("Verdana", 0, 12));
335
336     txt_search.addKeyListener(new KeyAdapter()
337     {
338       @Override
339       public void keyPressed(KeyEvent e)
340       {
341         if (e.getKeyCode() == KeyEvent.VK_ENTER)
342         {
343           if (txt_search.getText() == null
344                   || txt_search.getText().isEmpty())
345           {
346             return;
347           }
348           if ("pdb id".equalsIgnoreCase(getCmbSearchTarget()
349                   .getSelectedItem().toString()))
350           {
351             transferToSequenceFetcher(txt_search.getText());
352           }
353         }
354       }
355     });
356
357     txt_search.getDocument().addDocumentListener(new DocumentListener()
358     {
359       @Override
360       public void insertUpdate(DocumentEvent e)
361       {
362         searchAction();
363       }
364
365       @Override
366       public void removeUpdate(DocumentEvent e)
367       {
368         searchAction();
369       }
370
371       @Override
372       public void changedUpdate(DocumentEvent e)
373       {
374         searchAction();
375       }
376     });
377
378     final String searchTabTitle = MessageManager
379             .getString("label.search_result");
380     final String configureCols = MessageManager
381             .getString("label.configure_displayed_columns");
382     ChangeListener changeListener = new ChangeListener()
383     {
384       @Override
385       public void stateChanged(ChangeEvent changeEvent)
386       {
387         JTabbedPane sourceTabbedPane = (JTabbedPane) changeEvent
388                 .getSource();
389         int index = sourceTabbedPane.getSelectedIndex();
390
391         btn_back.setVisible(true);
392         btn_cancel.setVisible(true);
393         btn_ok.setVisible(true);
394         if (sourceTabbedPane.getTitleAt(index).equals(configureCols))
395         {
396           btn_back.setVisible(false);
397           btn_cancel.setVisible(false);
398           btn_ok.setVisible(false);
399           btn_back.setEnabled(false);
400           btn_cancel.setEnabled(false);
401           btn_ok.setEnabled(false);
402           previousWantedFields = getFTSRestClient()
403                   .getAllDefaulDisplayedDataColumns()
404                   .toArray(new Object[0]);
405         }
406         if (sourceTabbedPane.getTitleAt(index).equals(searchTabTitle))
407         {
408           btn_back.setEnabled(true);
409           btn_cancel.setEnabled(true);
410           if (wantedFieldsUpdated())
411           {
412             searchAction();
413           }
414           else
415           {
416             validateSelection();
417           }
418         }
419       }
420     };
421     tabbedPane.addChangeListener(changeListener);
422     tabbedPane.setPreferredSize(new Dimension(500, 300));
423     tabbedPane.add(searchTabTitle, scrl_searchResult);
424     tabbedPane.add(configureCols, new FTSDataColumnPreferences(
425             PreferenceSource.SEARCH_SUMMARY, getFTSRestClient()));
426
427     pnl_actions.add(btn_back);
428     pnl_actions.add(btn_ok);
429     pnl_actions.add(btn_cancel);
430
431     pnl_results.add(tabbedPane);
432     pnl_inputs.add(cmb_searchTarget);
433     pnl_inputs.add(txt_search);
434     pnl_inputs.add(lbl_loading);
435     pnl_inputs.add(lbl_warning);
436
437     this.setLayout(mainLayout);
438     this.add(pnl_inputs, java.awt.BorderLayout.NORTH);
439     this.add(pnl_results, java.awt.BorderLayout.CENTER);
440     this.add(pnl_actions, java.awt.BorderLayout.SOUTH);
441     mainFrame.setVisible(true);
442     mainFrame.setContentPane(this);
443     mainFrame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
444     Desktop.addInternalFrame(mainFrame, getFTSFrameTitle(), 800, 400);
445   }
446
447   public boolean wantedFieldsUpdated()
448   {
449     if (previousWantedFields == null)
450     {
451       return true;
452     }
453
454     return Arrays.equals(getFTSRestClient()
455             .getAllDefaulDisplayedDataColumns()
456             .toArray(new Object[0]), previousWantedFields) ? false
457             : true;
458
459   }
460
461   public void validateSelection()
462   {
463     if (tbl_summary.getSelectedRows().length > 0)
464     {
465       btn_ok.setEnabled(true);
466     }
467     else
468     {
469       btn_ok.setEnabled(false);
470     }
471   }
472
473   public JComboBox<FTSDataColumnI> getCmbSearchTarget()
474   {
475     return cmb_searchTarget;
476   }
477
478   public JTextField getTxtSearch()
479   {
480     return txt_search;
481   }
482
483   public JInternalFrame getMainFrame()
484   {
485     return mainFrame;
486   }
487
488   protected void delayAndEnableActionButtons()
489   {
490     new Thread()
491     {
492       @Override
493       public void run()
494       {
495         try
496         {
497           Thread.sleep(1500);
498         } catch (InterruptedException e)
499         {
500           e.printStackTrace();
501         }
502         btn_ok.setEnabled(true);
503         btn_back.setEnabled(true);
504         btn_cancel.setEnabled(true);
505       }
506     }.start();
507   }
508
509   protected void checkForErrors()
510   {
511     lbl_warning.setVisible(false);
512     if (errorWarning.length() > 0)
513     {
514       lbl_loading.setVisible(false);
515       lbl_warning.setToolTipText(JvSwingUtils.wrapTooltip(true,
516               errorWarning.toString()));
517       lbl_warning.setVisible(true);
518     }
519   }
520
521   protected void btn_back_ActionPerformed()
522   {
523     mainFrame.dispose();
524     new SequenceFetcher(progressIdicator);
525   }
526
527   protected void disableActionButtons()
528   {
529     btn_ok.setEnabled(false);
530     btn_back.setEnabled(false);
531     btn_cancel.setEnabled(false);
532   }
533
534   protected void btn_cancel_ActionPerformed()
535   {
536     mainFrame.dispose();
537   }
538
539   /**
540    * Populates search target combo-box options
541    */
542   public void populateCmbSearchTargetOptions()
543   {
544     List<FTSDataColumnI> searchableTargets = new ArrayList<FTSDataColumnI>();
545     try
546     {
547       Collection<FTSDataColumnI> foundFTSTargets = getFTSRestClient()
548               .getSearchableDataColumns();
549       searchableTargets.addAll(foundFTSTargets);
550     } catch (Exception e)
551     {
552       e.printStackTrace();
553     }
554
555     Collections.sort(searchableTargets, new Comparator<FTSDataColumnI>()
556     {
557       @Override
558       public int compare(FTSDataColumnI o1, FTSDataColumnI o2)
559       {
560         return o1.getName().compareTo(o2.getName());
561       }
562     });
563
564     for (FTSDataColumnI searchTarget : searchableTargets)
565     {
566       cmb_searchTarget.addItem(searchTarget);
567     }
568   }
569
570
571   public void transferToSequenceFetcher(String ids)
572   {
573     // mainFrame.dispose();
574     seqFetcher.getTextArea().setText(ids);
575     Thread worker = new Thread(seqFetcher);
576     worker.start();
577   }
578
579   @Override
580   public String getTypedText()
581   {
582     return txt_search.getText().trim();
583   }
584
585   @Override
586   public JTable getResultTable()
587   {
588     return tbl_summary;
589   }
590
591   public void reset()
592   {
593     lbl_loading.setVisible(false);
594     errorWarning.setLength(0);
595     lbl_warning.setVisible(false);
596     btn_ok.setEnabled(false);
597     mainFrame.setTitle(getFTSFrameTitle());
598     referesh();
599     tbl_summary.setModel(new DefaultTableModel());
600     tbl_summary.setVisible(false);
601   }
602
603   @Override
604   public void setErrorMessage(String message)
605   {
606     errorWarning.append(message);
607   }
608
609   @Override
610   public void updateSearchFrameTitle(String title)
611   {
612     mainFrame.setTitle(title);
613   }
614
615   @Override
616   public void setSearchInProgress(Boolean isSearchInProgress)
617   {
618     lbl_loading.setVisible(isSearchInProgress);
619   }
620   public void referesh()
621   {
622     mainFrame.setTitle(getFTSFrameTitle());
623   }
624
625 }