JAL-3926 disable autosearch by default
[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.bin.Cache;
25 import jalview.fts.api.FTSDataColumnI;
26 import jalview.fts.api.GFTSPanelI;
27 import jalview.fts.core.FTSDataColumnPreferences.PreferenceSource;
28 import jalview.gui.Desktop;
29 import jalview.gui.IProgressIndicator;
30 import jalview.gui.JvSwingUtils;
31 import jalview.gui.SequenceFetcher;
32 import jalview.io.cache.JvCacheableInputBox;
33 import jalview.util.MessageManager;
34 import jalview.util.Platform;
35
36 import java.awt.BorderLayout;
37 import java.awt.CardLayout;
38 import java.awt.Dimension;
39 import java.awt.Font;
40 import java.awt.event.ActionEvent;
41 import java.awt.event.ActionListener;
42 import java.awt.event.FocusAdapter;
43 import java.awt.event.FocusEvent;
44 import java.awt.event.FocusListener;
45 import java.awt.event.ItemEvent;
46 import java.awt.event.ItemListener;
47 import java.awt.event.KeyAdapter;
48 import java.awt.event.KeyEvent;
49 import java.awt.event.MouseAdapter;
50 import java.awt.event.MouseEvent;
51 import java.text.DecimalFormat;
52 import java.util.ArrayList;
53 import java.util.Arrays;
54 import java.util.Collection;
55 import java.util.Collections;
56 import java.util.Comparator;
57 import java.util.HashSet;
58 import java.util.List;
59
60 import javax.swing.ImageIcon;
61 import javax.swing.JButton;
62 import javax.swing.JCheckBox;
63 import javax.swing.JComboBox;
64 import javax.swing.JFrame;
65 import javax.swing.JInternalFrame;
66 import javax.swing.JLabel;
67 import javax.swing.JPanel;
68 import javax.swing.JScrollPane;
69 import javax.swing.JTabbedPane;
70 import javax.swing.JTable;
71 import javax.swing.Timer;
72 import javax.swing.event.ChangeEvent;
73 import javax.swing.event.ChangeListener;
74 import javax.swing.event.DocumentEvent;
75 import javax.swing.event.DocumentListener;
76 import javax.swing.event.InternalFrameEvent;
77 import javax.swing.table.DefaultTableModel;
78 import javax.swing.table.TableColumn;
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
278                   && tabs.getSelectedComponent() == ftsPanel)
279           {
280             txt_search.getComponent().requestFocusInWindow();
281           }
282         }
283       });
284       mainFrame.invalidate();
285       mainFrame.pack();
286     } catch (Exception e)
287     {
288       e.printStackTrace();
289     }
290   }
291
292   /**
293    * Initializes the GUI default properties
294    * 
295    * @throws Exception
296    */
297   private void jbInit() throws Exception
298   {
299
300     txt_search = new JvCacheableInputBox<>(getCacheKey(), 45);
301     populateCmbSearchTargetOptions();
302     Integer width = getTempUserPrefs().get("FTSPanel.width") == null ? 800
303             : getTempUserPrefs().get("FTSPanel.width");
304     Integer height = getTempUserPrefs().get("FTSPanel.height") == null ? 400
305             : getTempUserPrefs().get("FTSPanel.height");
306     lbl_warning.setVisible(false);
307     lbl_warning.setFont(VERDANA_12);
308     lbl_loading.setVisible(false);
309     lbl_loading.setFont(VERDANA_12);
310     lbl_blank.setVisible(true);
311     lbl_blank.setFont(VERDANA_12);
312
313     tbl_summary.setAutoCreateRowSorter(true);
314     tbl_summary.getTableHeader().setReorderingAllowed(false);
315     tbl_summary.addMouseListener(new MouseAdapter()
316     {
317       @Override
318       public void mouseClicked(MouseEvent e)
319       {
320         validateSelection();
321       }
322
323       @Override
324       public void mouseReleased(MouseEvent e)
325       {
326         validateSelection();
327       }
328     });
329     tbl_summary.addKeyListener(new KeyAdapter()
330     {
331       @Override
332       public void keyPressed(KeyEvent evt)
333       {
334         validateSelection();
335         switch (evt.getKeyCode())
336         {
337         case KeyEvent.VK_ESCAPE: // escape key
338           btn_back_ActionPerformed();
339           break;
340         case KeyEvent.VK_ENTER: // enter key
341           if (btn_ok.isEnabled())
342           {
343             okAction();
344           }
345           evt.consume();
346           break;
347         case KeyEvent.VK_TAB: // tab key
348           if (evt.isShiftDown())
349           {
350             tabbedPane.requestFocus();
351           }
352           else
353           {
354             btn_back.requestFocus();
355           }
356           evt.consume();
357           break;
358         default:
359           return;
360         }
361       }
362     });
363
364     JButton txt_help = new JButton("?");
365     txt_help.setFont(VERDANA_12);
366     txt_help.setPreferredSize(new Dimension(15, 15));
367     txt_help.setToolTipText(MessageManager.getString("action.help"));
368     txt_help.addActionListener(new ActionListener()
369     {
370       @Override
371       public void actionPerformed(ActionEvent e)
372       {
373         showHelp();
374       }
375     });
376
377     btn_autosearch.setText(MessageManager.getString("option.autosearch"));
378     btn_autosearch.setToolTipText(
379             MessageManager.getString("option.enable_disable_autosearch"));
380     // disable autosearch by default
381     btn_autosearch.setSelected(!Platform.isJS()
382             && Cache.getDefault(getAutosearchPreference(), false));
383     btn_autosearch.addActionListener(new java.awt.event.ActionListener()
384     {
385       @Override
386       public void actionPerformed(ActionEvent e)
387       {
388         jalview.bin.Cache.setProperty(getAutosearchPreference(),
389                 Boolean.toString(btn_autosearch.isSelected()));
390       }
391     });
392     btn_back.setFont(VERDANA_12);
393     btn_back.setText(MessageManager.getString("action.back"));
394     btn_back.addActionListener(new java.awt.event.ActionListener()
395     {
396       @Override
397       public void actionPerformed(ActionEvent e)
398       {
399         btn_back_ActionPerformed();
400       }
401     });
402     btn_back.addKeyListener(new KeyAdapter()
403     {
404       @Override
405       public void keyPressed(KeyEvent evt)
406       {
407         if (evt.getKeyCode() == KeyEvent.VK_ENTER)
408         {
409           btn_back_ActionPerformed();
410         }
411       }
412     });
413
414     btn_ok.setEnabled(false);
415     btn_ok.setFont(VERDANA_12);
416     btn_ok.setText(MessageManager.getString("action.ok"));
417     btn_ok.addActionListener(new java.awt.event.ActionListener()
418     {
419       @Override
420       public void actionPerformed(ActionEvent e)
421       {
422         okAction();
423       }
424     });
425     btn_ok.addKeyListener(new KeyAdapter()
426     {
427       @Override
428       public void keyPressed(KeyEvent evt)
429       {
430         if (evt.getKeyCode() == KeyEvent.VK_ENTER)
431         {
432           okAction();
433         }
434       }
435     });
436     btn_next_page.setEnabled(false);
437     btn_next_page.setToolTipText(
438             MessageManager.getString("label.next_page_tooltip"));
439     btn_next_page.setFont(VERDANA_12);
440     btn_next_page.setText(MessageManager.getString("action.next_page"));
441     btn_next_page.addActionListener(new java.awt.event.ActionListener()
442     {
443       @Override
444       public void actionPerformed(ActionEvent e)
445       {
446         nextPageAction();
447       }
448     });
449     btn_next_page.addKeyListener(new KeyAdapter()
450     {
451       @Override
452       public void keyPressed(KeyEvent evt)
453       {
454         if (evt.getKeyCode() == KeyEvent.VK_ENTER)
455         {
456           nextPageAction();
457         }
458       }
459     });
460
461     btn_prev_page.setEnabled(false);
462     btn_prev_page.setToolTipText(
463             MessageManager.getString("label.prev_page_tooltip"));
464     btn_prev_page.setFont(VERDANA_12);
465     btn_prev_page.setText(MessageManager.getString("action.prev_page"));
466     btn_prev_page.addActionListener(new java.awt.event.ActionListener()
467     {
468       @Override
469       public void actionPerformed(ActionEvent e)
470       {
471         prevPageAction();
472       }
473     });
474     btn_prev_page.addKeyListener(new KeyAdapter()
475     {
476       @Override
477       public void keyPressed(KeyEvent evt)
478       {
479         if (evt.getKeyCode() == KeyEvent.VK_ENTER)
480         {
481           prevPageAction();
482         }
483       }
484     });
485
486     if (isPaginationEnabled())
487     {
488       btn_prev_page.setVisible(true);
489       btn_next_page.setVisible(true);
490     }
491     else
492     {
493       btn_prev_page.setVisible(false);
494       btn_next_page.setVisible(false);
495     }
496
497     btn_cancel.setFont(VERDANA_12);
498     btn_cancel.setText(MessageManager.getString("action.cancel"));
499     btn_cancel.addActionListener(new java.awt.event.ActionListener()
500     {
501       @Override
502       public void actionPerformed(ActionEvent e)
503       {
504         btn_cancel_ActionPerformed();
505       }
506     });
507     btn_cancel.addKeyListener(new KeyAdapter()
508     {
509       @Override
510       public void keyPressed(KeyEvent evt)
511       {
512         if (evt.getKeyCode() == KeyEvent.VK_ENTER)
513         {
514           btn_cancel_ActionPerformed();
515         }
516       }
517     });
518     scrl_searchResult.setPreferredSize(new Dimension(width, height));
519
520     cmb_searchTarget.setFont(VERDANA_12);
521     cmb_searchTarget.addItemListener(new ItemListener()
522     {
523       @Override
524       public void itemStateChanged(ItemEvent e)
525       {
526         if (e.getStateChange() == ItemEvent.SELECTED)
527         {
528           String tooltipText;
529           if ("all".equalsIgnoreCase(
530                   getCmbSearchTarget().getSelectedItem().toString()))
531           {
532             tooltipText = MessageManager.getString("label.search_all");
533           }
534           else if ("pdb id".equalsIgnoreCase(
535                   getCmbSearchTarget().getSelectedItem().toString()))
536           {
537             tooltipText = MessageManager
538                     .getString("label.separate_multiple_accession_ids");
539           }
540           else
541           {
542             tooltipText = MessageManager.formatMessage(
543                     "label.separate_multiple_query_values", new Object[]
544                     { getCmbSearchTarget().getSelectedItem().toString() });
545           }
546           txt_search.getComponent().setToolTipText(
547                   JvSwingUtils.wrapTooltip(true, tooltipText));
548           searchAction(true);
549         }
550       }
551     });
552
553     txt_search.getComponent().setFont(VERDANA_12);
554
555     txt_search.addKeyListener(new KeyAdapter()
556             {
557               @Override
558               public void keyPressed(KeyEvent e)
559               {
560                 if (e.getKeyCode() == KeyEvent.VK_ENTER)
561                 {
562                   if (getTypedText() == null || getTypedText().isEmpty())
563                   {
564                     return;
565                   }
566                   String primaryKeyName = getFTSRestClient()
567                           .getPrimaryKeyColumn().getName();
568                   if (primaryKeyName.equalsIgnoreCase(getCmbSearchTarget()
569                           .getSelectedItem().toString()))
570                   {
571                     // TODO: nicer to show the list in the result set before
572                     // viewing in Jalview perhaps ?
573                     transferToSequenceFetcher(getTypedText());
574                   }
575                   else
576                   {
577                     performSearchAction();
578                   }
579                 }
580               }
581             });
582     final DeferredTextInputListener listener = new DeferredTextInputListener(
583             1500, new ActionListener()
584             {
585               @Override
586               public void actionPerformed(ActionEvent e)
587               {
588                 if (btn_autosearch.isSelected()
589                         || txt_search.wasEnterPressed())
590                 {
591                   performSearchAction();
592                 }
593               }
594             }, false);
595     txt_search.addDocumentListener(listener);
596
597     txt_search.addFocusListener(new FocusListener()
598     {
599       @Override
600       public void focusGained(FocusEvent e)
601       {
602         listener.start();
603       }
604
605       @Override
606       public void focusLost(FocusEvent e)
607       {
608         // listener.stop();
609       }
610     });
611
612     txt_search.addActionListener(new ActionListener()
613     {
614       @Override
615       public void actionPerformed(ActionEvent e)
616       {
617         performSearchAction();
618       }
619     });
620     final String searchTabTitle = MessageManager
621             .getString("label.search_result");
622     final String configureCols = MessageManager
623             .getString("label.configure_displayed_columns");
624     ChangeListener changeListener = new ChangeListener()
625     {
626       @Override
627       public void stateChanged(ChangeEvent changeEvent)
628       {
629         JTabbedPane sourceTabbedPane = (JTabbedPane) changeEvent
630                 .getSource();
631         int index = sourceTabbedPane.getSelectedIndex();
632
633         btn_back.setVisible(true);
634         btn_cancel.setVisible(true);
635         btn_ok.setVisible(true);
636         if (sourceTabbedPane.getTitleAt(index).equals(configureCols))
637         {
638           btn_back.setVisible(false);
639           btn_cancel.setVisible(false);
640           btn_ok.setVisible(false);
641           btn_back.setEnabled(false);
642           btn_cancel.setEnabled(false);
643           btn_ok.setEnabled(false);
644           btn_next_page.setEnabled(false);
645           btn_prev_page.setEnabled(false);
646           txt_search.getComponent().setEnabled(false);
647           cmb_searchTarget.setEnabled(false);
648           previousWantedFields = getFTSRestClient()
649                   .getAllDefaultDisplayedFTSDataColumns()
650                   .toArray(new Object[0]);
651         }
652         if (sourceTabbedPane.getTitleAt(index).equals(searchTabTitle))
653         {
654           btn_back.setEnabled(true);
655           btn_cancel.setEnabled(true);
656           refreshPaginatorState();
657           txt_search.getComponent().setEnabled(true);
658           cmb_searchTarget.setEnabled(true);
659           if (wantedFieldsUpdated())
660           {
661             searchAction(true);
662             paginatorCart.clear();
663           }
664           else
665           {
666             validateSelection();
667           }
668         }
669       }
670     };
671     tabbedPane.addChangeListener(changeListener);
672     tabbedPane.setPreferredSize(new Dimension(width, height));
673     tabbedPane.add(searchTabTitle, scrl_searchResult);
674     tabbedPane.add(configureCols, new FTSDataColumnPreferences(
675             PreferenceSource.SEARCH_SUMMARY, getFTSRestClient()));
676
677     pnl_actions.add(btn_back);
678     pnl_actions.add(btn_ok);
679     pnl_actions.add(btn_cancel);
680
681     pnl_results.add(tabbedPane);
682     pnl_inputs.add(cmb_searchTarget);
683     pnl_inputs.add(txt_search.getComponent());
684     pnl_inputs.add(txt_help);
685     pnl_inputs.add(btn_autosearch);
686     pnl_inputs.add(lbl_loading);
687     pnl_inputs.add(lbl_warning);
688     pnl_inputs.add(lbl_blank);
689     pnl_inputs.add(btn_prev_page);
690     pnl_inputs.add(btn_next_page);
691
692     this.setLayout(mainLayout);
693     this.add(pnl_inputs, java.awt.BorderLayout.NORTH);
694     this.add(pnl_results, java.awt.BorderLayout.CENTER);
695     this.add(pnl_actions, java.awt.BorderLayout.SOUTH);
696     mainFrame.setVisible(true);
697     if (tabs != null)
698     {
699       tabs.setOpaque(true);
700       tabs.insertTab(MessageManager.getString("label.free_text_search"),
701               null, this, "", 0);
702       mainFrame.setContentPane(tabs);
703       tabs.setVisible(true);
704     }
705     else
706     {
707       mainFrame.setContentPane(this);
708     }
709     mainFrame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
710     mainFrame.addInternalFrameListener(
711             new javax.swing.event.InternalFrameAdapter()
712             {
713               @Override
714               public void internalFrameClosing(InternalFrameEvent e)
715               {
716                 closeAction();
717               }
718             });
719     mainFrame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
720     Integer x = getTempUserPrefs().get("FTSPanel.x");
721     Integer y = getTempUserPrefs().get("FTSPanel.y");
722     if (x != null && y != null)
723     {
724       mainFrame.setLocation(x, y);
725     }
726     Desktop.addInternalFrame(mainFrame, getFTSFrameTitle(), width, height);
727   }
728
729   abstract protected void showHelp();
730
731   protected void closeAction()
732   {
733     getTempUserPrefs().put("FTSPanel.width", this.getWidth());
734     getTempUserPrefs().put("FTSPanel.height", pnl_results.getHeight());
735     getTempUserPrefs().put("FTSPanel.x", mainFrame.getX());
736     getTempUserPrefs().put("FTSPanel.y", mainFrame.getY());
737     mainFrame.dispose();
738     txt_search.persistCache();
739   }
740
741   public class DeferredTextInputListener implements DocumentListener
742   {
743     private final Timer swingTimer;
744
745     public DeferredTextInputListener(int timeOut, ActionListener listener,
746             boolean repeats)
747     {
748       swingTimer = new Timer(timeOut, listener);
749       swingTimer.setRepeats(repeats);
750     }
751
752     public void start()
753     {
754       swingTimer.start();
755     }
756
757     public void stop()
758     {
759       swingTimer.stop();
760     }
761
762     @Override
763     public void insertUpdate(DocumentEvent e)
764     {
765       swingTimer.restart();
766     }
767
768     @Override
769     public void removeUpdate(DocumentEvent e)
770     {
771       swingTimer.restart();
772     }
773
774     @Override
775     public void changedUpdate(DocumentEvent e)
776     {
777       swingTimer.restart();
778     }
779
780   }
781
782   void performSearchAction()
783   {
784     String typed = getTypedText();
785     if (typed != null && typed.length() > 0
786             && !typed.equalsIgnoreCase(lastSearchTerm))
787     {
788       searchAction(true);
789       paginatorCart.clear();
790       lastSearchTerm = typed;
791     }
792   }
793
794   public boolean wantedFieldsUpdated()
795   {
796     if (previousWantedFields == null)
797     {
798       return false;
799     }
800
801     return Arrays.equals(getFTSRestClient()
802             .getAllDefaultDisplayedFTSDataColumns().toArray(new Object[0]),
803             previousWantedFields) ? false : true;
804
805   }
806
807   public void validateSelection()
808   {
809     if (tbl_summary.getSelectedRows().length > 0
810             || !paginatorCart.isEmpty())
811     {
812       btn_ok.setEnabled(true);
813     }
814     else
815     {
816       btn_ok.setEnabled(false);
817     }
818   }
819
820   public JComboBox<FTSDataColumnI> getCmbSearchTarget()
821   {
822     return cmb_searchTarget;
823   }
824
825   public JInternalFrame getMainFrame()
826   {
827     return mainFrame;
828   }
829
830   protected void delayAndEnableActionButtons()
831   {
832     new Thread()
833     {
834       @Override
835       public void run()
836       {
837         try
838         {
839           Thread.sleep(1500);
840         } catch (InterruptedException e)
841         {
842           e.printStackTrace();
843         }
844         btn_ok.setEnabled(true);
845         btn_back.setEnabled(true);
846         btn_cancel.setEnabled(true);
847       }
848     }.start();
849   }
850
851   protected void checkForErrors()
852   {
853     lbl_warning.setVisible(false);
854     lbl_blank.setVisible(true);
855     if (errorWarning.length() > 0)
856     {
857       lbl_loading.setVisible(false);
858       lbl_blank.setVisible(false);
859       lbl_warning.setToolTipText(
860               JvSwingUtils.wrapTooltip(true, errorWarning.toString()));
861       lbl_warning.setVisible(true);
862     }
863   }
864
865   /**
866    * Action on Back button is to close this panel and open a new Sequence
867    * Fetcher panel
868    */
869   public void btn_back_ActionPerformed()
870   {
871     closeAction();
872     new SequenceFetcher(progressIndicator);
873   }
874
875   protected void disableActionButtons()
876   {
877     btn_ok.setEnabled(false);
878     btn_back.setEnabled(false);
879     btn_cancel.setEnabled(false);
880   }
881
882   public void btn_cancel_ActionPerformed()
883   {
884     closeAction();
885   }
886
887   /**
888    * Populates search target combo-box options
889    */
890   public void populateCmbSearchTargetOptions()
891   {
892     List<FTSDataColumnI> searchableTargets = new ArrayList<>();
893     try
894     {
895       Collection<FTSDataColumnI> foundFTSTargets = getFTSRestClient()
896               .getSearchableDataColumns();
897       searchableTargets.addAll(foundFTSTargets);
898     } catch (Exception e)
899     {
900       e.printStackTrace();
901     }
902
903     Collections.sort(searchableTargets, new Comparator<FTSDataColumnI>()
904     {
905       @Override
906       public int compare(FTSDataColumnI o1, FTSDataColumnI o2)
907       {
908         return o1.getName().compareTo(o2.getName());
909       }
910     });
911
912     for (FTSDataColumnI searchTarget : searchableTargets)
913     {
914       cmb_searchTarget.addItem(searchTarget);
915     }
916   }
917
918   public void transferToSequenceFetcher(String ids)
919   {
920     seqFetcher.setQuery(ids);
921     Thread worker = new Thread(seqFetcher);
922     worker.start();
923   }
924
925   @Override
926   public String getTypedText()
927   {
928     return txt_search.getUserInput();
929   }
930
931   @Override
932   public JTable getResultTable()
933   {
934     return tbl_summary;
935   }
936
937   public void reset()
938   {
939     lbl_loading.setVisible(false);
940     errorWarning.setLength(0);
941     lbl_warning.setVisible(false);
942     lbl_blank.setVisible(true);
943     btn_ok.setEnabled(false);
944     mainFrame.setTitle(getFTSFrameTitle());
945     refresh();
946     tbl_summary.setModel(new DefaultTableModel());
947     tbl_summary.setVisible(false);
948   }
949
950   @Override
951   public void setPrevPageButtonEnabled(boolean isEnabled)
952   {
953     btn_prev_page.setEnabled(isEnabled);
954   }
955
956   @Override
957   public void setNextPageButtonEnabled(boolean isEnabled)
958   {
959     btn_next_page.setEnabled(isEnabled);
960   }
961
962   @Override
963   public void setErrorMessage(String message)
964   {
965     errorWarning.append(message);
966   }
967
968   @Override
969   public void updateSearchFrameTitle(String title)
970   {
971     mainFrame.setTitle(title);
972   }
973
974   @Override
975   public void setSearchInProgress(Boolean isSearchInProgress)
976   {
977     lbl_blank.setVisible(!isSearchInProgress);
978     lbl_loading.setVisible(isSearchInProgress);
979     txt_search.setEditable(!isSearchInProgress);
980   }
981
982   @Override
983   public void prevPageAction()
984   {
985     updatePaginatorCart();
986     if (offSet >= pageLimit)
987     {
988       offSet = offSet - pageLimit;
989       searchAction(false);
990     }
991     else
992     {
993       refreshPaginatorState();
994     }
995   }
996
997   @Override
998   public void nextPageAction()
999   {
1000     updatePaginatorCart();
1001     offSet = offSet + pageLimit;
1002     searchAction(false);
1003   }
1004
1005   public void updatePaginatorCart()
1006   {
1007     int primaryKeyColIndex = 0;
1008     JTable resultTable = getResultTable();
1009     int totalRows = resultTable.getRowCount();
1010     try
1011     {
1012       primaryKeyColIndex = getFTSRestClient()
1013               .getPrimaryKeyColumIndex(wantedFields, false);
1014     } catch (Exception e)
1015     {
1016       e.printStackTrace();
1017     }
1018
1019     for (int row = 0; row < totalRows; row++)
1020     {
1021       String id = (String) resultTable.getValueAt(row, primaryKeyColIndex);
1022       if (paginatorCart.contains(id))
1023       {
1024         paginatorCart.remove(id);
1025       }
1026     }
1027     int[] selectedRows = resultTable.getSelectedRows();
1028     for (int summaryRow : selectedRows)
1029     {
1030       String idStr = resultTable.getValueAt(summaryRow, primaryKeyColIndex)
1031               .toString();
1032       paginatorCart.add(idStr);
1033     }
1034   }
1035
1036   public void updateSummaryTableSelections()
1037   {
1038     JTable resultTable = getResultTable();
1039     if (paginatorCart.isEmpty())
1040     {
1041       return;
1042     }
1043     int primaryKeyColIndex = 0;
1044     try
1045     {
1046       primaryKeyColIndex = getFTSRestClient()
1047               .getPrimaryKeyColumIndex(wantedFields, false);
1048     } catch (Exception e)
1049     {
1050       e.printStackTrace();
1051     }
1052     int totalRows = resultTable.getRowCount();
1053     for (int row = 0; row < totalRows; row++)
1054     {
1055       String id = (String) resultTable.getValueAt(row, primaryKeyColIndex);
1056       if (paginatorCart.contains(id))
1057       {
1058         resultTable.addRowSelectionInterval(row, row);
1059       }
1060     }
1061     validateSelection();
1062   }
1063
1064   public void refreshPaginatorState()
1065   {
1066     setPrevPageButtonEnabled(false);
1067     setNextPageButtonEnabled(false);
1068     if (resultSetCount == 0 && pageLimit == 0)
1069     {
1070       return;
1071     }
1072     if (resultSetCount >= pageLimit)
1073     {
1074       setNextPageButtonEnabled(true);
1075     }
1076     if (offSet >= pageLimit)
1077     {
1078       setPrevPageButtonEnabled(true);
1079     }
1080   }
1081
1082   public void refresh()
1083   {
1084     mainFrame.setTitle(getFTSFrameTitle());
1085   }
1086
1087   @Override
1088   public abstract void okAction();
1089 }