JAL-4036 Don't autosearch changing index when autosearch is de-selected
[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       }
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().getPrimaryKeyColumn()
567                   .getName();
568           if (primaryKeyName.equalsIgnoreCase(
569                   getCmbSearchTarget().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 }