JAL-2349 JAL-3855 formatting
[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 && 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           searchAction(true);
548         }
549       }
550     });
551
552     txt_search.getComponent().setFont(VERDANA_12);
553
554     txt_search.addKeyListener(new KeyAdapter()
555     {
556       @Override
557       public void keyPressed(KeyEvent e)
558       {
559         if (e.getKeyCode() == KeyEvent.VK_ENTER)
560         {
561           if (getTypedText() == null || getTypedText().isEmpty())
562           {
563             return;
564           }
565           String primaryKeyName = getFTSRestClient().getPrimaryKeyColumn()
566                   .getName();
567           if (primaryKeyName.equalsIgnoreCase(
568                   getCmbSearchTarget().getSelectedItem().toString()))
569           {
570             // TODO: nicer to show the list in the result set before
571             // viewing in Jalview perhaps ?
572             transferToSequenceFetcher(getTypedText());
573           }
574           else
575           {
576             performSearchAction();
577           }
578         }
579       }
580     });
581     final DeferredTextInputListener listener = new DeferredTextInputListener(
582             1500, new ActionListener()
583             {
584               @Override
585               public void actionPerformed(ActionEvent e)
586               {
587                 if (btn_autosearch.isSelected()
588                         || txt_search.wasEnterPressed())
589                 {
590                   performSearchAction();
591                 }
592               }
593             }, false);
594     txt_search.addDocumentListener(listener);
595
596     txt_search.addFocusListener(new FocusListener()
597     {
598       @Override
599       public void focusGained(FocusEvent e)
600       {
601         listener.start();
602       }
603
604       @Override
605       public void focusLost(FocusEvent e)
606       {
607         // listener.stop();
608       }
609     });
610
611     txt_search.addActionListener(new ActionListener()
612     {
613       @Override
614       public void actionPerformed(ActionEvent e)
615       {
616         performSearchAction();
617       }
618     });
619     final String searchTabTitle = MessageManager
620             .getString("label.search_result");
621     final String configureCols = MessageManager
622             .getString("label.configure_displayed_columns");
623     ChangeListener changeListener = new ChangeListener()
624     {
625       @Override
626       public void stateChanged(ChangeEvent changeEvent)
627       {
628         JTabbedPane sourceTabbedPane = (JTabbedPane) changeEvent
629                 .getSource();
630         int index = sourceTabbedPane.getSelectedIndex();
631
632         btn_back.setVisible(true);
633         btn_cancel.setVisible(true);
634         btn_ok.setVisible(true);
635         if (sourceTabbedPane.getTitleAt(index).equals(configureCols))
636         {
637           btn_back.setVisible(false);
638           btn_cancel.setVisible(false);
639           btn_ok.setVisible(false);
640           btn_back.setEnabled(false);
641           btn_cancel.setEnabled(false);
642           btn_ok.setEnabled(false);
643           btn_next_page.setEnabled(false);
644           btn_prev_page.setEnabled(false);
645           txt_search.getComponent().setEnabled(false);
646           cmb_searchTarget.setEnabled(false);
647           previousWantedFields = getFTSRestClient()
648                   .getAllDefaultDisplayedFTSDataColumns()
649                   .toArray(new Object[0]);
650         }
651         if (sourceTabbedPane.getTitleAt(index).equals(searchTabTitle))
652         {
653           btn_back.setEnabled(true);
654           btn_cancel.setEnabled(true);
655           refreshPaginatorState();
656           txt_search.getComponent().setEnabled(true);
657           cmb_searchTarget.setEnabled(true);
658           if (wantedFieldsUpdated())
659           {
660             searchAction(true);
661             paginatorCart.clear();
662           }
663           else
664           {
665             validateSelection();
666           }
667         }
668       }
669     };
670     tabbedPane.addChangeListener(changeListener);
671     tabbedPane.setPreferredSize(new Dimension(width, height));
672     tabbedPane.add(searchTabTitle, scrl_searchResult);
673     tabbedPane.add(configureCols, new FTSDataColumnPreferences(
674             PreferenceSource.SEARCH_SUMMARY, getFTSRestClient()));
675
676     pnl_actions.add(btn_back);
677     pnl_actions.add(btn_ok);
678     pnl_actions.add(btn_cancel);
679
680     pnl_results.add(tabbedPane);
681     pnl_inputs.add(cmb_searchTarget);
682     pnl_inputs.add(txt_search.getComponent());
683     pnl_inputs.add(txt_help);
684     pnl_inputs.add(btn_autosearch);
685     pnl_inputs.add(lbl_loading);
686     pnl_inputs.add(lbl_warning);
687     pnl_inputs.add(lbl_blank);
688     pnl_inputs.add(btn_prev_page);
689     pnl_inputs.add(btn_next_page);
690
691     this.setLayout(mainLayout);
692     this.add(pnl_inputs, java.awt.BorderLayout.NORTH);
693     this.add(pnl_results, java.awt.BorderLayout.CENTER);
694     this.add(pnl_actions, java.awt.BorderLayout.SOUTH);
695     mainFrame.setVisible(true);
696     if (tabs != null)
697     {
698       tabs.setOpaque(true);
699       tabs.insertTab(MessageManager.getString("label.free_text_search"),
700               null, this, "", 0);
701       mainFrame.setContentPane(tabs);
702       tabs.setVisible(true);
703     }
704     else
705     {
706       mainFrame.setContentPane(this);
707     }
708     mainFrame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
709     mainFrame.addInternalFrameListener(
710             new javax.swing.event.InternalFrameAdapter()
711             {
712               @Override
713               public void internalFrameClosing(InternalFrameEvent e)
714               {
715                 closeAction();
716               }
717             });
718     mainFrame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
719     Integer x = getTempUserPrefs().get("FTSPanel.x");
720     Integer y = getTempUserPrefs().get("FTSPanel.y");
721     if (x != null && y != null)
722     {
723       mainFrame.setLocation(x, y);
724     }
725     Desktop.addInternalFrame(mainFrame, getFTSFrameTitle(), width, height);
726   }
727
728   abstract protected void showHelp();
729
730   protected void closeAction()
731   {
732     getTempUserPrefs().put("FTSPanel.width", this.getWidth());
733     getTempUserPrefs().put("FTSPanel.height", pnl_results.getHeight());
734     getTempUserPrefs().put("FTSPanel.x", mainFrame.getX());
735     getTempUserPrefs().put("FTSPanel.y", mainFrame.getY());
736     mainFrame.dispose();
737     txt_search.persistCache();
738   }
739
740   public class DeferredTextInputListener implements DocumentListener
741   {
742     private final Timer swingTimer;
743
744     public DeferredTextInputListener(int timeOut, ActionListener listener,
745             boolean repeats)
746     {
747       swingTimer = new Timer(timeOut, listener);
748       swingTimer.setRepeats(repeats);
749     }
750
751     public void start()
752     {
753       swingTimer.start();
754     }
755
756     public void stop()
757     {
758       swingTimer.stop();
759     }
760
761     @Override
762     public void insertUpdate(DocumentEvent e)
763     {
764       swingTimer.restart();
765     }
766
767     @Override
768     public void removeUpdate(DocumentEvent e)
769     {
770       swingTimer.restart();
771     }
772
773     @Override
774     public void changedUpdate(DocumentEvent e)
775     {
776       swingTimer.restart();
777     }
778
779   }
780
781   void performSearchAction()
782   {
783     String typed = getTypedText();
784     if (typed != null && typed.length() > 0
785             && !typed.equalsIgnoreCase(lastSearchTerm))
786     {
787       searchAction(true);
788       paginatorCart.clear();
789       lastSearchTerm = typed;
790     }
791   }
792
793   public boolean wantedFieldsUpdated()
794   {
795     if (previousWantedFields == null)
796     {
797       return false;
798     }
799
800     return Arrays.equals(getFTSRestClient()
801             .getAllDefaultDisplayedFTSDataColumns().toArray(new Object[0]),
802             previousWantedFields) ? false : true;
803
804   }
805
806   public void validateSelection()
807   {
808     if (tbl_summary.getSelectedRows().length > 0
809             || !paginatorCart.isEmpty())
810     {
811       btn_ok.setEnabled(true);
812     }
813     else
814     {
815       btn_ok.setEnabled(false);
816     }
817   }
818
819   public JComboBox<FTSDataColumnI> getCmbSearchTarget()
820   {
821     return cmb_searchTarget;
822   }
823
824   public JInternalFrame getMainFrame()
825   {
826     return mainFrame;
827   }
828
829   protected void delayAndEnableActionButtons()
830   {
831     new Thread()
832     {
833       @Override
834       public void run()
835       {
836         try
837         {
838           Thread.sleep(1500);
839         } catch (InterruptedException e)
840         {
841           e.printStackTrace();
842         }
843         btn_ok.setEnabled(true);
844         btn_back.setEnabled(true);
845         btn_cancel.setEnabled(true);
846       }
847     }.start();
848   }
849
850   protected void checkForErrors()
851   {
852     lbl_warning.setVisible(false);
853     lbl_blank.setVisible(true);
854     if (errorWarning.length() > 0)
855     {
856       lbl_loading.setVisible(false);
857       lbl_blank.setVisible(false);
858       lbl_warning.setToolTipText(
859               JvSwingUtils.wrapTooltip(true, errorWarning.toString()));
860       lbl_warning.setVisible(true);
861     }
862   }
863
864   /**
865    * Action on Back button is to close this panel and open a new Sequence
866    * Fetcher panel
867    */
868   public void btn_back_ActionPerformed()
869   {
870     closeAction();
871     new SequenceFetcher(progressIndicator);
872   }
873
874   protected void disableActionButtons()
875   {
876     btn_ok.setEnabled(false);
877     btn_back.setEnabled(false);
878     btn_cancel.setEnabled(false);
879   }
880
881   public void btn_cancel_ActionPerformed()
882   {
883     closeAction();
884   }
885
886   /**
887    * Populates search target combo-box options
888    */
889   public void populateCmbSearchTargetOptions()
890   {
891     List<FTSDataColumnI> searchableTargets = new ArrayList<>();
892     try
893     {
894       Collection<FTSDataColumnI> foundFTSTargets = getFTSRestClient()
895               .getSearchableDataColumns();
896       searchableTargets.addAll(foundFTSTargets);
897     } catch (Exception e)
898     {
899       e.printStackTrace();
900     }
901
902     Collections.sort(searchableTargets, new Comparator<FTSDataColumnI>()
903     {
904       @Override
905       public int compare(FTSDataColumnI o1, FTSDataColumnI o2)
906       {
907         return o1.getName().compareTo(o2.getName());
908       }
909     });
910
911     for (FTSDataColumnI searchTarget : searchableTargets)
912     {
913       cmb_searchTarget.addItem(searchTarget);
914     }
915   }
916
917   public void transferToSequenceFetcher(String ids)
918   {
919     seqFetcher.setQuery(ids);
920     Thread worker = new Thread(seqFetcher);
921     worker.start();
922   }
923
924   @Override
925   public String getTypedText()
926   {
927     return txt_search.getUserInput();
928   }
929
930   @Override
931   public JTable getResultTable()
932   {
933     return tbl_summary;
934   }
935
936   public void reset()
937   {
938     lbl_loading.setVisible(false);
939     errorWarning.setLength(0);
940     lbl_warning.setVisible(false);
941     lbl_blank.setVisible(true);
942     btn_ok.setEnabled(false);
943     mainFrame.setTitle(getFTSFrameTitle());
944     refresh();
945     tbl_summary.setModel(new DefaultTableModel());
946     tbl_summary.setVisible(false);
947   }
948
949   @Override
950   public void setPrevPageButtonEnabled(boolean isEnabled)
951   {
952     btn_prev_page.setEnabled(isEnabled);
953   }
954
955   @Override
956   public void setNextPageButtonEnabled(boolean isEnabled)
957   {
958     btn_next_page.setEnabled(isEnabled);
959   }
960
961   @Override
962   public void setErrorMessage(String message)
963   {
964     errorWarning.append(message);
965   }
966
967   @Override
968   public void updateSearchFrameTitle(String title)
969   {
970     mainFrame.setTitle(title);
971   }
972
973   @Override
974   public void setSearchInProgress(Boolean isSearchInProgress)
975   {
976     lbl_blank.setVisible(!isSearchInProgress);
977     lbl_loading.setVisible(isSearchInProgress);
978     txt_search.setEditable(!isSearchInProgress);
979   }
980
981   @Override
982   public void prevPageAction()
983   {
984     updatePaginatorCart();
985     if (offSet >= pageLimit)
986     {
987       offSet = offSet - pageLimit;
988       searchAction(false);
989     }
990     else
991     {
992       refreshPaginatorState();
993     }
994   }
995
996   @Override
997   public void nextPageAction()
998   {
999     updatePaginatorCart();
1000     offSet = offSet + pageLimit;
1001     searchAction(false);
1002   }
1003
1004   public void updatePaginatorCart()
1005   {
1006     int primaryKeyColIndex = 0;
1007     JTable resultTable = getResultTable();
1008     int totalRows = resultTable.getRowCount();
1009     try
1010     {
1011       primaryKeyColIndex = getFTSRestClient()
1012               .getPrimaryKeyColumIndex(wantedFields, false);
1013     } catch (Exception e)
1014     {
1015       e.printStackTrace();
1016     }
1017
1018     for (int row = 0; row < totalRows; row++)
1019     {
1020       String id = (String) resultTable.getValueAt(row, primaryKeyColIndex);
1021       if (paginatorCart.contains(id))
1022       {
1023         paginatorCart.remove(id);
1024       }
1025     }
1026     int[] selectedRows = resultTable.getSelectedRows();
1027     for (int summaryRow : selectedRows)
1028     {
1029       String idStr = resultTable.getValueAt(summaryRow, primaryKeyColIndex)
1030               .toString();
1031       paginatorCart.add(idStr);
1032     }
1033   }
1034
1035   public void updateSummaryTableSelections()
1036   {
1037     JTable resultTable = getResultTable();
1038     if (paginatorCart.isEmpty())
1039     {
1040       return;
1041     }
1042     int primaryKeyColIndex = 0;
1043     try
1044     {
1045       primaryKeyColIndex = getFTSRestClient()
1046               .getPrimaryKeyColumIndex(wantedFields, false);
1047     } catch (Exception e)
1048     {
1049       e.printStackTrace();
1050     }
1051     int totalRows = resultTable.getRowCount();
1052     for (int row = 0; row < totalRows; row++)
1053     {
1054       String id = (String) resultTable.getValueAt(row, primaryKeyColIndex);
1055       if (paginatorCart.contains(id))
1056       {
1057         resultTable.addRowSelectionInterval(row, row);
1058       }
1059     }
1060     validateSelection();
1061   }
1062
1063   public void refreshPaginatorState()
1064   {
1065     setPrevPageButtonEnabled(false);
1066     setNextPageButtonEnabled(false);
1067     if (resultSetCount == 0 && pageLimit == 0)
1068     {
1069       return;
1070     }
1071     if (resultSetCount >= pageLimit)
1072     {
1073       setNextPageButtonEnabled(true);
1074     }
1075     if (offSet >= pageLimit)
1076     {
1077       setPrevPageButtonEnabled(true);
1078     }
1079   }
1080
1081   public void refresh()
1082   {
1083     mainFrame.setTitle(getFTSFrameTitle());
1084   }
1085
1086   @Override
1087   public abstract void okAction();
1088 }