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