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