d52ff892684ee6d454747ea364952963385eda83
[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 java.awt.BorderLayout;
25 import java.awt.CardLayout;
26 import java.awt.Dimension;
27 import java.awt.Font;
28 import java.awt.event.ActionEvent;
29 import java.awt.event.ActionListener;
30 import java.awt.event.FocusAdapter;
31 import java.awt.event.FocusEvent;
32 import java.awt.event.FocusListener;
33 import java.awt.event.ItemEvent;
34 import java.awt.event.ItemListener;
35 import java.awt.event.KeyAdapter;
36 import java.awt.event.KeyEvent;
37 import java.awt.event.MouseAdapter;
38 import java.awt.event.MouseEvent;
39 import java.text.DecimalFormat;
40 import java.util.ArrayList;
41 import java.util.Arrays;
42 import java.util.Collection;
43 import java.util.Collections;
44 import java.util.Comparator;
45 import java.util.HashSet;
46 import java.util.List;
47
48 import javax.swing.ImageIcon;
49 import javax.swing.JButton;
50 import javax.swing.JCheckBox;
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.Timer;
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.event.InternalFrameEvent;
65 import javax.swing.table.DefaultTableModel;
66 import javax.swing.table.TableColumn;
67
68 import jalview.bin.Cache;
69 import jalview.fts.api.FTSDataColumnI;
70 import jalview.fts.api.GFTSPanelI;
71 import jalview.fts.core.FTSDataColumnPreferences.PreferenceSource;
72 import jalview.gui.Desktop;
73 import jalview.gui.IProgressIndicator;
74 import jalview.gui.JvSwingUtils;
75 import jalview.gui.SequenceFetcher;
76 import jalview.io.cache.JvCacheableInputBox;
77 import jalview.util.MessageManager;
78 import jalview.util.Platform;
79
80 /**
81  * This class provides the swing GUI layout for FTS Panel and implements most of
82  * the contracts defined in GFSPanelI
83  * 
84  * @author tcnofoegbu
85  *
86  */
87
88 @SuppressWarnings("serial")
89 public abstract class GFTSPanel extends JPanel implements GFTSPanelI
90 {
91   private static final Font VERDANA_12 = new Font("Verdana", 0, 12);
92
93   protected JInternalFrame mainFrame = new JInternalFrame(
94           getFTSFrameTitle());
95
96   protected JTabbedPane tabs = new JTabbedPane();
97
98   protected IProgressIndicator progressIndicator;
99
100   protected JComboBox<FTSDataColumnI> cmb_searchTarget = new JComboBox<>();
101
102   protected JButton btn_ok = new JButton();
103
104   protected JButton btn_back = new JButton();
105
106   protected JButton btn_cancel = new JButton();
107
108   protected JCheckBox btn_autosearch = new JCheckBox();
109
110   protected JvCacheableInputBox<String> txt_search;
111
112   protected SequenceFetcher seqFetcher;
113
114   protected Collection<FTSDataColumnI> wantedFields;
115
116   private String lastSearchTerm = "";
117
118   protected JButton btn_next_page = new JButton();
119
120   protected JButton btn_prev_page = new JButton();
121
122   protected StringBuilder errorWarning = new StringBuilder();
123
124   protected ImageIcon warningImage = new ImageIcon(
125           getClass().getResource("/images/warning.gif"));
126
127   protected ImageIcon loadingImage = new ImageIcon(
128           getClass().getResource("/images/loading.gif"));
129
130   protected ImageIcon balnkPlaceholderImage = new ImageIcon(
131           getClass().getResource("/images/blank_16x16_placeholder.png"));
132
133   protected JLabel lbl_warning = new JLabel(warningImage);
134
135   protected JLabel lbl_loading = new JLabel(loadingImage);
136
137   protected JLabel lbl_blank = new JLabel(balnkPlaceholderImage);
138
139   JTabbedPane tabbedPane = new JTabbedPane();
140
141   private JPanel pnl_actions = new JPanel();
142
143   private JPanel pnl_results = new JPanel(new CardLayout());
144
145   private JPanel pnl_inputs = new JPanel();
146
147   private BorderLayout mainLayout = new BorderLayout();
148
149   protected Object[] previousWantedFields;
150
151   protected int resultSetCount;
152
153   protected int totalResultSetCount;
154
155   protected int offSet;
156
157   protected int pageLimit;
158
159   protected HashSet<String> paginatorCart = new HashSet<>();
160
161   private static final int MIN_WIDTH = 670;
162
163   private static final int MIN_HEIGHT = 300;
164
165   protected static final DecimalFormat totalNumberformatter = new DecimalFormat(
166           "###,###");
167
168   private JTable tbl_summary = new JTable()
169   {
170     private boolean inLayout;
171
172     @Override
173     public boolean getScrollableTracksViewportWidth()
174     {
175       return hasExcessWidth();
176
177     }
178
179     @Override
180     public void doLayout()
181     {
182       if (hasExcessWidth())
183       {
184         autoResizeMode = AUTO_RESIZE_SUBSEQUENT_COLUMNS;
185       }
186       inLayout = true;
187       super.doLayout();
188       inLayout = false;
189       autoResizeMode = AUTO_RESIZE_OFF;
190     }
191
192     protected boolean hasExcessWidth()
193     {
194       return getPreferredSize().width < getParent().getWidth();
195     }
196
197     @Override
198     public void columnMarginChanged(ChangeEvent e)
199     {
200       if (isEditing())
201       {
202         removeEditor();
203       }
204       TableColumn resizingColumn = getTableHeader().getResizingColumn();
205       // Need to do this here, before the parent's
206       // layout manager calls getPreferredSize().
207       if (resizingColumn != null && autoResizeMode == AUTO_RESIZE_OFF
208               && !inLayout)
209       {
210         resizingColumn.setPreferredWidth(resizingColumn.getWidth());
211         String colHeader = resizingColumn.getHeaderValue().toString();
212         getTempUserPrefs().put(colHeader, resizingColumn.getWidth());
213       }
214       resizeAndRepaint();
215     }
216
217     @Override
218     public String getToolTipText(MouseEvent evt)
219     {
220       String toolTipText = null;
221       java.awt.Point pnt = evt.getPoint();
222       int rowIndex = rowAtPoint(pnt);
223       int colIndex = columnAtPoint(pnt);
224
225       try
226       {
227         if (getValueAt(rowIndex, colIndex) == null)
228         {
229           return null;
230         }
231         toolTipText = getValueAt(rowIndex, colIndex).toString();
232
233       } catch (Exception e)
234       {
235         e.printStackTrace();
236       }
237       toolTipText = (toolTipText == null ? null
238               : (toolTipText.length() > 500
239                       ? JvSwingUtils.wrapTooltip(true,
240                               toolTipText.subSequence(0, 500) + "...")
241                       : JvSwingUtils.wrapTooltip(true, toolTipText)));
242
243       return toolTipText;
244     }
245   };
246
247   protected JScrollPane scrl_searchResult = new JScrollPane(tbl_summary);
248
249   public GFTSPanel()
250   {
251     this(null);
252   }
253
254   public GFTSPanel(SequenceFetcher fetcher)
255   {
256     try
257     {
258       if (fetcher == null)
259       {
260         tabs = null;
261       }
262       jbInit();
263       if (fetcher != null)
264       {
265         tabs.addTab(MessageManager.getString("label.retrieve_ids"),
266                 fetcher);
267         fetcher.embedIn(this);
268       }
269       mainFrame.setMinimumSize(new Dimension(MIN_WIDTH, MIN_HEIGHT));
270       final JPanel ftsPanel = this;
271       mainFrame.addFocusListener(new FocusAdapter()
272       {
273         @Override
274         public void focusGained(FocusEvent e)
275         {
276           // TODO: make selected tab gain focus in correct widget
277           if (tabs != null && tabs.getSelectedComponent() == ftsPanel)
278           {
279             txt_search.getComponent().requestFocusInWindow();
280           }
281         }
282       });
283       mainFrame.invalidate();
284       mainFrame.pack();
285     } catch (Exception e)
286     {
287       e.printStackTrace();
288     }
289   }
290
291   /**
292    * Initializes the GUI default properties
293    * 
294    * @throws Exception
295    */
296   private void jbInit() throws Exception
297   {
298
299     txt_search = new JvCacheableInputBox<>(getCacheKey(), 45);
300     populateCmbSearchTargetOptions();
301     Integer width = getTempUserPrefs().get("FTSPanel.width") == null ? 800
302             : getTempUserPrefs().get("FTSPanel.width");
303     Integer height = getTempUserPrefs().get("FTSPanel.height") == null ? 400
304             : getTempUserPrefs().get("FTSPanel.height");
305     lbl_warning.setVisible(false);
306     lbl_warning.setFont(VERDANA_12);
307     lbl_loading.setVisible(false);
308     lbl_loading.setFont(VERDANA_12);
309     lbl_blank.setVisible(true);
310     lbl_blank.setFont(VERDANA_12);
311
312     tbl_summary.setAutoCreateRowSorter(true);
313     tbl_summary.getTableHeader().setReorderingAllowed(false);
314     tbl_summary.addMouseListener(new MouseAdapter()
315     {
316       @Override
317       public void mouseClicked(MouseEvent e)
318       {
319         validateSelection();
320       }
321
322       @Override
323       public void mouseReleased(MouseEvent e)
324       {
325         validateSelection();
326       }
327     });
328     tbl_summary.addKeyListener(new KeyAdapter()
329     {
330       @Override
331       public void keyPressed(KeyEvent evt)
332       {
333         validateSelection();
334         switch (evt.getKeyCode())
335         {
336         case KeyEvent.VK_ESCAPE: // escape key
337           btn_back_ActionPerformed();
338           break;
339         case KeyEvent.VK_ENTER: // enter key
340           if (btn_ok.isEnabled())
341           {
342             okAction();
343           }
344           evt.consume();
345           break;
346         case KeyEvent.VK_TAB: // tab key
347           if (evt.isShiftDown())
348           {
349             tabbedPane.requestFocus();
350           }
351           else
352           {
353             btn_back.requestFocus();
354           }
355           evt.consume();
356           break;
357         default:
358           return;
359         }
360       }
361     });
362
363     JButton txt_help = new JButton("?");
364     txt_help.setFont(VERDANA_12);
365     txt_help.setPreferredSize(new Dimension(15, 15));
366     txt_help.setToolTipText(MessageManager.getString("action.help"));
367     txt_help.addActionListener(new ActionListener()
368     {
369       @Override
370       public void actionPerformed(ActionEvent e)
371       {
372         showHelp();
373       }
374     });
375
376     btn_autosearch.setText(MessageManager.getString("option.autosearch"));
377     btn_autosearch.setToolTipText(
378             MessageManager.getString("option.enable_disable_autosearch"));
379     // disable autosearch by default
380     btn_autosearch.setSelected(!Platform.isJS()
381             && Cache.getDefault(getAutosearchPreference(), false));
382     btn_autosearch.addActionListener(new java.awt.event.ActionListener()
383     {
384       @Override
385       public void actionPerformed(ActionEvent e)
386       {
387         Cache.setProperty(getAutosearchPreference(),
388                 Boolean.toString(btn_autosearch.isSelected()));
389       }
390     });
391     btn_back.setFont(VERDANA_12);
392     btn_back.setText(MessageManager.getString("action.back"));
393     btn_back.addActionListener(new java.awt.event.ActionListener()
394     {
395       @Override
396       public void actionPerformed(ActionEvent e)
397       {
398         btn_back_ActionPerformed();
399       }
400     });
401     btn_back.addKeyListener(new KeyAdapter()
402     {
403       @Override
404       public void keyPressed(KeyEvent evt)
405       {
406         if (evt.getKeyCode() == KeyEvent.VK_ENTER)
407         {
408           btn_back_ActionPerformed();
409         }
410       }
411     });
412
413     btn_ok.setEnabled(false);
414     btn_ok.setFont(VERDANA_12);
415     btn_ok.setText(MessageManager.getString("action.ok"));
416     btn_ok.addActionListener(new java.awt.event.ActionListener()
417     {
418       @Override
419       public void actionPerformed(ActionEvent e)
420       {
421         okAction();
422       }
423     });
424     btn_ok.addKeyListener(new KeyAdapter()
425     {
426       @Override
427       public void keyPressed(KeyEvent evt)
428       {
429         if (evt.getKeyCode() == KeyEvent.VK_ENTER)
430         {
431           okAction();
432         }
433       }
434     });
435     btn_next_page.setEnabled(false);
436     btn_next_page.setToolTipText(
437             MessageManager.getString("label.next_page_tooltip"));
438     btn_next_page.setFont(VERDANA_12);
439     btn_next_page.setText(MessageManager.getString("action.next_page"));
440     btn_next_page.addActionListener(new java.awt.event.ActionListener()
441     {
442       @Override
443       public void actionPerformed(ActionEvent e)
444       {
445         nextPageAction();
446       }
447     });
448     btn_next_page.addKeyListener(new KeyAdapter()
449     {
450       @Override
451       public void keyPressed(KeyEvent evt)
452       {
453         if (evt.getKeyCode() == KeyEvent.VK_ENTER)
454         {
455           nextPageAction();
456         }
457       }
458     });
459
460     btn_prev_page.setEnabled(false);
461     btn_prev_page.setToolTipText(
462             MessageManager.getString("label.prev_page_tooltip"));
463     btn_prev_page.setFont(VERDANA_12);
464     btn_prev_page.setText(MessageManager.getString("action.prev_page"));
465     btn_prev_page.addActionListener(new java.awt.event.ActionListener()
466     {
467       @Override
468       public void actionPerformed(ActionEvent e)
469       {
470         prevPageAction();
471       }
472     });
473     btn_prev_page.addKeyListener(new KeyAdapter()
474     {
475       @Override
476       public void keyPressed(KeyEvent evt)
477       {
478         if (evt.getKeyCode() == KeyEvent.VK_ENTER)
479         {
480           prevPageAction();
481         }
482       }
483     });
484
485     if (isPaginationEnabled())
486     {
487       btn_prev_page.setVisible(true);
488       btn_next_page.setVisible(true);
489     }
490     else
491     {
492       btn_prev_page.setVisible(false);
493       btn_next_page.setVisible(false);
494     }
495
496     btn_cancel.setFont(VERDANA_12);
497     btn_cancel.setText(MessageManager.getString("action.cancel"));
498     btn_cancel.addActionListener(new java.awt.event.ActionListener()
499     {
500       @Override
501       public void actionPerformed(ActionEvent e)
502       {
503         btn_cancel_ActionPerformed();
504       }
505     });
506     btn_cancel.addKeyListener(new KeyAdapter()
507     {
508       @Override
509       public void keyPressed(KeyEvent evt)
510       {
511         if (evt.getKeyCode() == KeyEvent.VK_ENTER)
512         {
513           btn_cancel_ActionPerformed();
514         }
515       }
516     });
517     scrl_searchResult.setPreferredSize(new Dimension(width, height));
518
519     cmb_searchTarget.setFont(VERDANA_12);
520     cmb_searchTarget.addItemListener(new ItemListener()
521     {
522       @Override
523       public void itemStateChanged(ItemEvent e)
524       {
525         if (e.getStateChange() == ItemEvent.SELECTED)
526         {
527           String tooltipText;
528           if ("all".equalsIgnoreCase(
529                   getCmbSearchTarget().getSelectedItem().toString()))
530           {
531             tooltipText = MessageManager.getString("label.search_all");
532           }
533           else if ("pdb id".equalsIgnoreCase(
534                   getCmbSearchTarget().getSelectedItem().toString()))
535           {
536             tooltipText = MessageManager
537                     .getString("label.separate_multiple_accession_ids");
538           }
539           else
540           {
541             tooltipText = MessageManager.formatMessage(
542                     "label.separate_multiple_query_values", new Object[]
543                     { getCmbSearchTarget().getSelectedItem().toString() });
544           }
545           txt_search.getComponent().setToolTipText(
546                   JvSwingUtils.wrapTooltip(true, tooltipText));
547           // if (btn_autosearch.isSelected())
548           searchAction(true);
549
550           setCmbSearchTargetTooltip();
551         }
552       }
553     });
554
555     txt_search.getComponent().setFont(VERDANA_12);
556
557     txt_search.addKeyListener(new KeyAdapter()
558     {
559       @Override
560       public void keyPressed(KeyEvent e)
561       {
562         if (e.getKeyCode() == KeyEvent.VK_ENTER)
563         {
564           if (getTypedText() == null || getTypedText().isEmpty())
565           {
566             return;
567           }
568           String primaryKeyName = getFTSRestClient().getPrimaryKeyColumn()
569                   .getName();
570           if (primaryKeyName.equalsIgnoreCase(
571                   getCmbSearchTarget().getSelectedItem().toString()))
572           {
573             // TODO: nicer to show the list in the result set before
574             // viewing in Jalview perhaps ?
575             transferToSequenceFetcher(getTypedText());
576           }
577           else
578           {
579             performSearchAction();
580           }
581         }
582       }
583     });
584     final DeferredTextInputListener listener = new DeferredTextInputListener(
585             1500, new ActionListener()
586             {
587               @Override
588               public void actionPerformed(ActionEvent e)
589               {
590                 if (btn_autosearch.isSelected()
591                         || txt_search.wasEnterPressed())
592                 {
593                   performSearchAction();
594                 }
595               }
596             }, false);
597     txt_search.addDocumentListener(listener);
598
599     txt_search.addFocusListener(new FocusListener()
600     {
601       @Override
602       public void focusGained(FocusEvent e)
603       {
604         listener.start();
605       }
606
607       @Override
608       public void focusLost(FocusEvent e)
609       {
610         // listener.stop();
611       }
612     });
613
614     txt_search.addActionListener(new ActionListener()
615     {
616       @Override
617       public void actionPerformed(ActionEvent e)
618       {
619         performSearchAction();
620       }
621     });
622     final String searchTabTitle = MessageManager
623             .getString("label.search_result");
624     final String configureCols = MessageManager
625             .getString("label.configure_displayed_columns");
626     ChangeListener changeListener = new ChangeListener()
627     {
628       @Override
629       public void stateChanged(ChangeEvent changeEvent)
630       {
631         JTabbedPane sourceTabbedPane = (JTabbedPane) changeEvent
632                 .getSource();
633         int index = sourceTabbedPane.getSelectedIndex();
634
635         btn_back.setVisible(true);
636         btn_cancel.setVisible(true);
637         btn_ok.setVisible(true);
638         if (sourceTabbedPane.getTitleAt(index).equals(configureCols))
639         {
640           btn_back.setVisible(false);
641           btn_cancel.setVisible(false);
642           btn_ok.setVisible(false);
643           btn_back.setEnabled(false);
644           btn_cancel.setEnabled(false);
645           btn_ok.setEnabled(false);
646           btn_next_page.setEnabled(false);
647           btn_prev_page.setEnabled(false);
648           txt_search.getComponent().setEnabled(false);
649           cmb_searchTarget.setEnabled(false);
650           previousWantedFields = getFTSRestClient()
651                   .getAllDefaultDisplayedFTSDataColumns()
652                   .toArray(new Object[0]);
653         }
654         if (sourceTabbedPane.getTitleAt(index).equals(searchTabTitle))
655         {
656           btn_back.setEnabled(true);
657           btn_cancel.setEnabled(true);
658           refreshPaginatorState();
659           txt_search.getComponent().setEnabled(true);
660           cmb_searchTarget.setEnabled(true);
661           if (wantedFieldsUpdated())
662           {
663             searchAction(true);
664             paginatorCart.clear();
665           }
666           else
667           {
668             validateSelection();
669           }
670         }
671       }
672     };
673     tabbedPane.addChangeListener(changeListener);
674     tabbedPane.setPreferredSize(new Dimension(width, height));
675     tabbedPane.add(searchTabTitle, scrl_searchResult);
676     tabbedPane.add(configureCols, new FTSDataColumnPreferences(
677             PreferenceSource.SEARCH_SUMMARY, getFTSRestClient()));
678
679     pnl_actions.add(btn_back);
680     pnl_actions.add(btn_ok);
681     pnl_actions.add(btn_cancel);
682
683     pnl_results.add(tabbedPane);
684     setCmbSearchTargetTooltip();
685     pnl_inputs.add(cmb_searchTarget);
686     pnl_inputs.add(txt_search.getComponent());
687     pnl_inputs.add(txt_help);
688     pnl_inputs.add(btn_autosearch);
689     pnl_inputs.add(lbl_loading);
690     pnl_inputs.add(lbl_warning);
691     pnl_inputs.add(lbl_blank);
692     pnl_inputs.add(btn_prev_page);
693     pnl_inputs.add(btn_next_page);
694
695     this.setLayout(mainLayout);
696     this.add(pnl_inputs, java.awt.BorderLayout.NORTH);
697     this.add(pnl_results, java.awt.BorderLayout.CENTER);
698     this.add(pnl_actions, java.awt.BorderLayout.SOUTH);
699     mainFrame.setVisible(true);
700     if (tabs != null)
701     {
702       tabs.setOpaque(true);
703       tabs.insertTab(MessageManager.getString("label.free_text_search"),
704               null, this, "", 0);
705       mainFrame.setContentPane(tabs);
706       tabs.setVisible(true);
707     }
708     else
709     {
710       mainFrame.setContentPane(this);
711     }
712     mainFrame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
713     mainFrame.addInternalFrameListener(
714             new javax.swing.event.InternalFrameAdapter()
715             {
716               @Override
717               public void internalFrameClosing(InternalFrameEvent e)
718               {
719                 closeAction();
720               }
721             });
722     mainFrame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
723     Integer x = getTempUserPrefs().get("FTSPanel.x");
724     Integer y = getTempUserPrefs().get("FTSPanel.y");
725     if (x != null && y != null)
726     {
727       mainFrame.setLocation(x, y);
728     }
729     Desktop.addInternalFrame(mainFrame, getFTSFrameTitle(), width, height);
730   }
731
732   abstract protected void showHelp();
733
734   protected void closeAction()
735   {
736     getTempUserPrefs().put("FTSPanel.width", this.getWidth());
737     getTempUserPrefs().put("FTSPanel.height", pnl_results.getHeight());
738     getTempUserPrefs().put("FTSPanel.x", mainFrame.getX());
739     getTempUserPrefs().put("FTSPanel.y", mainFrame.getY());
740     mainFrame.dispose();
741     txt_search.persistCache();
742   }
743
744   public class DeferredTextInputListener implements DocumentListener
745   {
746     private final Timer swingTimer;
747
748     public DeferredTextInputListener(int timeOut, ActionListener listener,
749             boolean repeats)
750     {
751       swingTimer = new Timer(timeOut, listener);
752       swingTimer.setRepeats(repeats);
753     }
754
755     public void start()
756     {
757       swingTimer.start();
758     }
759
760     public void stop()
761     {
762       swingTimer.stop();
763     }
764
765     @Override
766     public void insertUpdate(DocumentEvent e)
767     {
768       swingTimer.restart();
769     }
770
771     @Override
772     public void removeUpdate(DocumentEvent e)
773     {
774       swingTimer.restart();
775     }
776
777     @Override
778     public void changedUpdate(DocumentEvent e)
779     {
780       swingTimer.restart();
781     }
782
783   }
784
785   void performSearchAction()
786   {
787     String typed = getTypedText();
788     if (typed != null && typed.length() > 0
789             && !typed.equalsIgnoreCase(lastSearchTerm))
790     {
791       searchAction(true);
792       paginatorCart.clear();
793       lastSearchTerm = typed;
794     }
795   }
796
797   public boolean wantedFieldsUpdated()
798   {
799     if (previousWantedFields == null)
800     {
801       return false;
802     }
803
804     return Arrays.equals(getFTSRestClient()
805             .getAllDefaultDisplayedFTSDataColumns().toArray(new Object[0]),
806             previousWantedFields) ? false : true;
807
808   }
809
810   public void validateSelection()
811   {
812     if (tbl_summary.getSelectedRows().length > 0
813             || !paginatorCart.isEmpty())
814     {
815       btn_ok.setEnabled(true);
816     }
817     else
818     {
819       btn_ok.setEnabled(false);
820     }
821   }
822
823   public JComboBox<FTSDataColumnI> getCmbSearchTarget()
824   {
825     return cmb_searchTarget;
826   }
827
828   public JInternalFrame getMainFrame()
829   {
830     return mainFrame;
831   }
832
833   protected void delayAndEnableActionButtons()
834   {
835     new Thread()
836     {
837       @Override
838       public void run()
839       {
840         try
841         {
842           Thread.sleep(1500);
843         } catch (InterruptedException e)
844         {
845           e.printStackTrace();
846         }
847         btn_ok.setEnabled(true);
848         btn_back.setEnabled(true);
849         btn_cancel.setEnabled(true);
850       }
851     }.start();
852   }
853
854   protected void checkForErrors()
855   {
856     lbl_warning.setVisible(false);
857     lbl_blank.setVisible(true);
858     if (errorWarning.length() > 0)
859     {
860       lbl_loading.setVisible(false);
861       lbl_blank.setVisible(false);
862       lbl_warning.setToolTipText(
863               JvSwingUtils.wrapTooltip(true, errorWarning.toString()));
864       lbl_warning.setVisible(true);
865     }
866   }
867
868   /**
869    * Action on Back button is to close this panel and open a new Sequence
870    * Fetcher panel
871    */
872   public void btn_back_ActionPerformed()
873   {
874     closeAction();
875     new SequenceFetcher(progressIndicator);
876   }
877
878   protected void disableActionButtons()
879   {
880     btn_ok.setEnabled(false);
881     btn_back.setEnabled(false);
882     btn_cancel.setEnabled(false);
883   }
884
885   public void btn_cancel_ActionPerformed()
886   {
887     closeAction();
888   }
889
890   /**
891    * Populates search target combo-box options
892    */
893   public void populateCmbSearchTargetOptions()
894   {
895     List<FTSDataColumnI> searchableTargets = new ArrayList<>();
896     try
897     {
898       Collection<FTSDataColumnI> foundFTSTargets = getFTSRestClient()
899               .getSearchableDataColumns();
900       searchableTargets.addAll(foundFTSTargets);
901     } catch (Exception e)
902     {
903       e.printStackTrace();
904     }
905
906     Collections.sort(searchableTargets, new Comparator<FTSDataColumnI>()
907     {
908       @Override
909       public int compare(FTSDataColumnI o1, FTSDataColumnI o2)
910       {
911         return o1.getName().compareTo(o2.getName());
912       }
913     });
914
915     for (FTSDataColumnI searchTarget : searchableTargets)
916     {
917       cmb_searchTarget.addItem(searchTarget);
918     }
919   }
920
921   public void transferToSequenceFetcher(String ids)
922   {
923     seqFetcher.setQuery(ids);
924     Thread worker = new Thread(seqFetcher);
925     worker.start();
926   }
927
928   @Override
929   public String getTypedText()
930   {
931     return txt_search.getUserInput();
932   }
933
934   @Override
935   public JTable getResultTable()
936   {
937     return tbl_summary;
938   }
939
940   public void reset()
941   {
942     lbl_loading.setVisible(false);
943     errorWarning.setLength(0);
944     lbl_warning.setVisible(false);
945     lbl_blank.setVisible(true);
946     btn_ok.setEnabled(false);
947     mainFrame.setTitle(getFTSFrameTitle());
948     refresh();
949     tbl_summary.setModel(new DefaultTableModel());
950     tbl_summary.setVisible(false);
951   }
952
953   @Override
954   public void setPrevPageButtonEnabled(boolean isEnabled)
955   {
956     btn_prev_page.setEnabled(isEnabled);
957   }
958
959   @Override
960   public void setNextPageButtonEnabled(boolean isEnabled)
961   {
962     btn_next_page.setEnabled(isEnabled);
963   }
964
965   @Override
966   public void setErrorMessage(String message)
967   {
968     errorWarning.append(message);
969   }
970
971   @Override
972   public void updateSearchFrameTitle(String title)
973   {
974     mainFrame.setTitle(title);
975   }
976
977   @Override
978   public void setSearchInProgress(Boolean isSearchInProgress)
979   {
980     lbl_blank.setVisible(!isSearchInProgress);
981     lbl_loading.setVisible(isSearchInProgress);
982     txt_search.setEditable(!isSearchInProgress);
983   }
984
985   @Override
986   public void prevPageAction()
987   {
988     updatePaginatorCart();
989     if (offSet >= pageLimit)
990     {
991       offSet = offSet - pageLimit;
992       searchAction(false);
993     }
994     else
995     {
996       refreshPaginatorState();
997     }
998   }
999
1000   @Override
1001   public void nextPageAction()
1002   {
1003     updatePaginatorCart();
1004     offSet = offSet + pageLimit;
1005     searchAction(false);
1006   }
1007
1008   public void updatePaginatorCart()
1009   {
1010     int primaryKeyColIndex = 0;
1011     JTable resultTable = getResultTable();
1012     int totalRows = resultTable.getRowCount();
1013     try
1014     {
1015       primaryKeyColIndex = getFTSRestClient()
1016               .getPrimaryKeyColumIndex(wantedFields, false);
1017     } catch (Exception e)
1018     {
1019       e.printStackTrace();
1020     }
1021
1022     for (int row = 0; row < totalRows; row++)
1023     {
1024       String id = (String) resultTable.getValueAt(row, primaryKeyColIndex);
1025       if (paginatorCart.contains(id))
1026       {
1027         paginatorCart.remove(id);
1028       }
1029     }
1030     int[] selectedRows = resultTable.getSelectedRows();
1031     for (int summaryRow : selectedRows)
1032     {
1033       String idStr = resultTable.getValueAt(summaryRow, primaryKeyColIndex)
1034               .toString();
1035       paginatorCart.add(idStr);
1036     }
1037   }
1038
1039   public void updateSummaryTableSelections()
1040   {
1041     JTable resultTable = getResultTable();
1042     if (paginatorCart.isEmpty())
1043     {
1044       return;
1045     }
1046     int primaryKeyColIndex = 0;
1047     try
1048     {
1049       primaryKeyColIndex = getFTSRestClient()
1050               .getPrimaryKeyColumIndex(wantedFields, false);
1051     } catch (Exception e)
1052     {
1053       e.printStackTrace();
1054     }
1055     int totalRows = resultTable.getRowCount();
1056     for (int row = 0; row < totalRows; row++)
1057     {
1058       String id = (String) resultTable.getValueAt(row, primaryKeyColIndex);
1059       if (paginatorCart.contains(id))
1060       {
1061         resultTable.addRowSelectionInterval(row, row);
1062       }
1063     }
1064     validateSelection();
1065   }
1066
1067   public void refreshPaginatorState()
1068   {
1069     setPrevPageButtonEnabled(false);
1070     setNextPageButtonEnabled(false);
1071     if (resultSetCount == 0 && pageLimit == 0)
1072     {
1073       return;
1074     }
1075     if (resultSetCount >= pageLimit)
1076     {
1077       setNextPageButtonEnabled(true);
1078     }
1079     if (offSet >= pageLimit)
1080     {
1081       setPrevPageButtonEnabled(true);
1082     }
1083   }
1084
1085   public void refresh()
1086   {
1087     mainFrame.setTitle(getFTSFrameTitle());
1088   }
1089
1090   @Override
1091   public abstract void okAction();
1092
1093   private void setCmbSearchTargetTooltip()
1094   {
1095     JComboBox<FTSDataColumnI> cmb = getCmbSearchTarget();
1096     if (cmb.isEnabled())
1097     {
1098       boolean isAll = "all"
1099               .equalsIgnoreCase(cmb.getSelectedItem().toString());
1100       FTSDataColumnI index = (FTSDataColumnI) cmb.getSelectedItem();
1101       String indexCode = index.getAltCode();
1102       String dbName = getDbName();
1103       String message = isAll ? MessageManager
1104               .formatMessage("label.search_db_all", new Object[]
1105               { dbName })
1106               : MessageManager.formatMessage("label.search_db_index",
1107                       new Object[]
1108                       { dbName, indexCode });
1109       cmb.setToolTipText(message);
1110     }
1111     else
1112     {
1113       cmb.setToolTipText("");
1114     }
1115   }
1116 }