2 * Jalview - A Sequence Alignment Editor and Viewer (Version 2.8.2)
3 * Copyright (C) 2014 The Jalview Authors
5 * This file is part of Jalview.
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.
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.
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.
22 package jalview.jbgui;
24 import jalview.datamodel.SequenceI;
25 import jalview.fts.api.FTSDataColumnI;
26 import jalview.fts.core.FTSDataColumnPreferences;
27 import jalview.fts.core.FTSDataColumnPreferences.PreferenceSource;
28 import jalview.fts.service.pdb.PDBFTSRestClient;
29 import jalview.gui.AlignmentPanel;
30 import jalview.gui.Desktop;
31 import jalview.gui.JvSwingUtils;
32 import jalview.gui.StructureViewer;
33 import jalview.util.MessageManager;
35 import java.awt.BorderLayout;
36 import java.awt.CardLayout;
37 import java.awt.Component;
38 import java.awt.Dimension;
39 import java.awt.FlowLayout;
40 import java.awt.GridLayout;
41 import java.awt.event.ActionEvent;
42 import java.awt.event.ItemEvent;
43 import java.awt.event.ItemListener;
44 import java.awt.event.KeyAdapter;
45 import java.awt.event.KeyEvent;
46 import java.awt.event.MouseAdapter;
47 import java.awt.event.MouseEvent;
48 import java.util.Arrays;
49 import java.util.HashMap;
52 import javax.swing.ImageIcon;
53 import javax.swing.JButton;
54 import javax.swing.JCheckBox;
55 import javax.swing.JComboBox;
56 import javax.swing.JFrame;
57 import javax.swing.JInternalFrame;
58 import javax.swing.JLabel;
59 import javax.swing.JList;
60 import javax.swing.JPanel;
61 import javax.swing.JScrollPane;
62 import javax.swing.JSeparator;
63 import javax.swing.JTabbedPane;
64 import javax.swing.JTable;
65 import javax.swing.JTextField;
66 import javax.swing.ListCellRenderer;
67 import javax.swing.event.ChangeEvent;
68 import javax.swing.event.ChangeListener;
69 import javax.swing.event.DocumentEvent;
70 import javax.swing.event.DocumentListener;
71 import javax.swing.event.InternalFrameEvent;
72 import javax.swing.table.TableColumn;
74 import net.miginfocom.swing.MigLayout;
76 @SuppressWarnings("serial")
78 * GUI layout for structure chooser
83 public abstract class GStructureChooser extends JPanel
84 implements ItemListener
86 protected JPanel statusPanel = new JPanel();
88 public JLabel statusBar = new JLabel();
90 private JPanel pnl_actionsAndStatus = new JPanel(new BorderLayout());
92 protected String frameTitle = MessageManager
93 .getString("label.structure_chooser");
95 protected JInternalFrame mainFrame = new JInternalFrame(frameTitle);
97 protected JComboBox<FilterOption> cmb_filterOption = new JComboBox<>();
99 protected AlignmentPanel ap;
101 protected StringBuilder errorWarning = new StringBuilder();
103 protected JLabel lbl_result = new JLabel(
104 MessageManager.getString("label.select"));
106 protected JButton btn_view = new JButton();
108 protected JButton btn_cancel = new JButton();
110 protected JButton btn_pdbFromFile = new JButton();
112 protected JTextField txt_search = new JTextField(14);
114 private JPanel pnl_actions = new JPanel(new MigLayout());
116 private JPanel pnl_main = new JPanel();
118 private JPanel pnl_idInput = new JPanel(new FlowLayout());
120 private JPanel pnl_fileChooser = new JPanel(new FlowLayout());
122 private JPanel pnl_idInputBL = new JPanel(new BorderLayout());
124 private JPanel pnl_fileChooserBL = new JPanel(new BorderLayout());
126 private JPanel pnl_locPDB = new JPanel(new BorderLayout());
128 protected JPanel pnl_switchableViews = new JPanel(new CardLayout());
130 protected CardLayout layout_switchableViews = (CardLayout) (pnl_switchableViews
133 private BorderLayout mainLayout = new BorderLayout();
135 protected JCheckBox chk_rememberSettings = new JCheckBox(
136 MessageManager.getString("label.dont_ask_me_again"));
138 protected JCheckBox chk_invertFilter = new JCheckBox(
139 MessageManager.getString("label.invert"));
141 protected ImageIcon loadingImage = new ImageIcon(
142 getClass().getResource("/images/loading.gif"));
144 protected ImageIcon goodImage = new ImageIcon(
145 getClass().getResource("/images/good.png"));
147 protected ImageIcon errorImage = new ImageIcon(
148 getClass().getResource("/images/error.png"));
150 protected ImageIcon warningImage = new ImageIcon(
151 getClass().getResource("/images/warning.gif"));
153 protected JLabel lbl_warning = new JLabel(warningImage);
155 protected JLabel lbl_loading = new JLabel(loadingImage);
157 protected JLabel lbl_pdbManualFetchStatus = new JLabel(errorImage);
159 protected JLabel lbl_fromFileStatus = new JLabel(errorImage);
161 protected AssciateSeqPanel idInputAssSeqPanel = new AssciateSeqPanel();
163 protected AssciateSeqPanel fileChooserAssSeqPanel = new AssciateSeqPanel();
165 protected static final String VIEWS_FILTER = "VIEWS_FILTER";
167 protected static final String VIEWS_FROM_FILE = "VIEWS_FROM_FILE";
169 protected static final String VIEWS_ENTER_ID = "VIEWS_ENTER_ID";
171 protected JComboBox<StructureViewer> targetView = new JComboBox();
174 * 'cached' structure view
176 protected static final String VIEWS_LOCAL_PDB = "VIEWS_LOCAL_PDB";
178 protected JTable tbl_local_pdb = new JTable();
180 protected JScrollPane scrl_localPDB = new JScrollPane(tbl_local_pdb);
182 protected JTabbedPane pnl_filter = new JTabbedPane();
184 protected FTSDataColumnPreferences pdbDocFieldPrefs = new FTSDataColumnPreferences(
185 PreferenceSource.STRUCTURE_CHOOSER,
186 PDBFTSRestClient.getInstance());
188 protected FTSDataColumnI[] previousWantedFields;
190 protected static Map<String, Integer> tempUserPrefs = new HashMap<>();
192 private JTable tbl_summary = new JTable()
194 private boolean inLayout;
197 public boolean getScrollableTracksViewportWidth()
199 return hasExcessWidth();
204 public void doLayout()
206 if (hasExcessWidth())
208 autoResizeMode = AUTO_RESIZE_SUBSEQUENT_COLUMNS;
213 autoResizeMode = AUTO_RESIZE_OFF;
216 protected boolean hasExcessWidth()
218 return getPreferredSize().width < getParent().getWidth();
222 public void columnMarginChanged(ChangeEvent e)
228 TableColumn resizingColumn = getTableHeader().getResizingColumn();
229 // Need to do this here, before the parent's
230 // layout manager calls getPreferredSize().
231 if (resizingColumn != null && autoResizeMode == AUTO_RESIZE_OFF
234 resizingColumn.setPreferredWidth(resizingColumn.getWidth());
235 String colHeader = resizingColumn.getHeaderValue().toString();
236 tempUserPrefs.put(colHeader, resizingColumn.getWidth());
242 public String getToolTipText(MouseEvent evt)
244 String toolTipText = null;
245 java.awt.Point pnt = evt.getPoint();
246 int rowIndex = rowAtPoint(pnt);
247 int colIndex = columnAtPoint(pnt);
251 if (getValueAt(rowIndex, colIndex) == null)
255 toolTipText = getValueAt(rowIndex, colIndex).toString();
256 } catch (Exception e)
258 // e.printStackTrace();
260 toolTipText = (toolTipText == null ? null
261 : (toolTipText.length() > 500
262 ? JvSwingUtils.wrapTooltip(true,
263 "\"" + toolTipText.subSequence(0, 500)
265 : JvSwingUtils.wrapTooltip(true, toolTipText)));
270 protected JScrollPane scrl_foundStructures = new JScrollPane(tbl_summary);
272 public GStructureChooser()
277 mainFrame.setVisible(false);
278 mainFrame.invalidate();
280 } catch (Exception e)
287 * Initializes the GUI default properties
291 private void jbInit() throws Exception
293 Integer width = tempUserPrefs.get("structureChooser.width") == null
295 : tempUserPrefs.get("structureChooser.width");
296 Integer height = tempUserPrefs.get("structureChooser.height") == null
298 : tempUserPrefs.get("structureChooser.height");
299 tbl_summary.setAutoCreateRowSorter(true);
300 tbl_summary.getTableHeader().setReorderingAllowed(false);
301 tbl_summary.addMouseListener(new MouseAdapter()
304 public void mouseClicked(MouseEvent e)
306 validateSelections();
310 public void mouseReleased(MouseEvent e)
312 validateSelections();
315 tbl_summary.addKeyListener(new KeyAdapter()
318 public void keyPressed(KeyEvent evt)
320 validateSelections();
321 switch (evt.getKeyCode())
323 case KeyEvent.VK_ESCAPE: // escape key
326 case KeyEvent.VK_ENTER: // enter key
327 if (btn_view.isEnabled())
329 ok_ActionPerformed();
332 case KeyEvent.VK_TAB: // tab key
333 if (evt.isShiftDown())
335 pnl_filter.requestFocus();
339 btn_view.requestFocus();
348 tbl_local_pdb.setAutoCreateRowSorter(true);
349 tbl_local_pdb.getTableHeader().setReorderingAllowed(false);
350 tbl_local_pdb.addMouseListener(new MouseAdapter()
353 public void mouseClicked(MouseEvent e)
355 validateSelections();
359 public void mouseReleased(MouseEvent e)
361 validateSelections();
364 tbl_local_pdb.addKeyListener(new KeyAdapter()
367 public void keyPressed(KeyEvent evt)
369 validateSelections();
370 switch (evt.getKeyCode())
372 case KeyEvent.VK_ESCAPE: // escape key
375 case KeyEvent.VK_ENTER: // enter key
376 if (btn_view.isEnabled())
378 ok_ActionPerformed();
381 case KeyEvent.VK_TAB: // tab key
382 if (evt.isShiftDown())
384 cmb_filterOption.requestFocus();
388 if (btn_view.isEnabled())
390 btn_view.requestFocus();
394 btn_cancel.requestFocus();
404 btn_view.setFont(new java.awt.Font("Verdana", 0, 12));
405 btn_view.setText(MessageManager.getString("action.view"));
406 btn_view.addActionListener(new java.awt.event.ActionListener()
409 public void actionPerformed(ActionEvent e)
411 ok_ActionPerformed();
414 btn_view.addKeyListener(new KeyAdapter()
417 public void keyPressed(KeyEvent evt)
419 if (evt.getKeyCode() == KeyEvent.VK_ENTER)
421 ok_ActionPerformed();
426 btn_cancel.setFont(new java.awt.Font("Verdana", 0, 12));
427 btn_cancel.setText(MessageManager.getString("action.cancel"));
428 btn_cancel.addActionListener(new java.awt.event.ActionListener()
431 public void actionPerformed(ActionEvent e)
433 closeAction(pnl_filter.getHeight());
436 btn_cancel.addKeyListener(new KeyAdapter()
439 public void keyPressed(KeyEvent evt)
441 if (evt.getKeyCode() == KeyEvent.VK_ENTER)
443 closeAction(pnl_filter.getHeight());
448 btn_pdbFromFile.setFont(new java.awt.Font("Verdana", 0, 12));
449 String btn_title = MessageManager.getString("label.select_pdb_file");
450 btn_pdbFromFile.setText(btn_title + " ");
451 btn_pdbFromFile.addActionListener(new java.awt.event.ActionListener()
454 public void actionPerformed(ActionEvent e)
456 pdbFromFile_actionPerformed();
459 btn_pdbFromFile.addKeyListener(new KeyAdapter()
462 public void keyPressed(KeyEvent evt)
464 if (evt.getKeyCode() == KeyEvent.VK_ENTER)
466 pdbFromFile_actionPerformed();
471 scrl_foundStructures.setPreferredSize(new Dimension(width, height));
473 scrl_localPDB.setPreferredSize(new Dimension(width, height));
474 scrl_localPDB.setHorizontalScrollBarPolicy(
475 JScrollPane.HORIZONTAL_SCROLLBAR_NEVER);
477 cmb_filterOption.setFont(new java.awt.Font("Verdana", 0, 12));
478 chk_invertFilter.setFont(new java.awt.Font("Verdana", 0, 12));
479 chk_rememberSettings.setFont(new java.awt.Font("Verdana", 0, 12));
480 chk_rememberSettings.setVisible(false);
481 txt_search.setToolTipText(JvSwingUtils.wrapTooltip(true,
482 MessageManager.getString("label.enter_pdb_id_tip")));
483 cmb_filterOption.setToolTipText(
484 MessageManager.getString("info.select_filter_option"));
485 txt_search.getDocument().addDocumentListener(new DocumentListener()
488 public void insertUpdate(DocumentEvent e)
490 txt_search_ActionPerformed();
494 public void removeUpdate(DocumentEvent e)
496 txt_search_ActionPerformed();
500 public void changedUpdate(DocumentEvent e)
502 txt_search_ActionPerformed();
506 cmb_filterOption.addItemListener(this);
508 // add CustomComboSeparatorsRenderer to filter option combo-box
509 cmb_filterOption.setRenderer(new CustomComboSeparatorsRenderer(
510 (ListCellRenderer<Object>) cmb_filterOption.getRenderer())
513 protected boolean addSeparatorAfter(JList list, FilterOption value,
516 return value.isAddSeparatorAfter();
520 chk_invertFilter.addItemListener(this);
522 targetView.setVisible(false);
523 pnl_actions.add(targetView,"wrap");
524 pnl_actions.add(chk_rememberSettings);
525 pnl_actions.add(btn_view);
526 pnl_actions.add(btn_cancel);
528 // pnl_filter.add(lbl_result);
529 pnl_main.add(cmb_filterOption);
530 pnl_main.add(lbl_loading);
531 pnl_main.add(chk_invertFilter);
532 lbl_loading.setVisible(false);
534 pnl_fileChooser.add(btn_pdbFromFile);
535 pnl_fileChooser.add(lbl_fromFileStatus);
536 pnl_fileChooserBL.add(fileChooserAssSeqPanel, BorderLayout.NORTH);
537 pnl_fileChooserBL.add(pnl_fileChooser, BorderLayout.CENTER);
539 pnl_idInput.add(txt_search);
540 pnl_idInput.add(lbl_pdbManualFetchStatus);
541 pnl_idInputBL.add(idInputAssSeqPanel, BorderLayout.NORTH);
542 pnl_idInputBL.add(pnl_idInput, BorderLayout.CENTER);
544 final String foundStructureSummary = MessageManager
545 .getString("label.found_structures_summary");
546 final String configureCols = MessageManager
547 .getString("label.configure_displayed_columns");
548 ChangeListener changeListener = new ChangeListener()
551 public void stateChanged(ChangeEvent changeEvent)
553 JTabbedPane sourceTabbedPane = (JTabbedPane) changeEvent
555 int index = sourceTabbedPane.getSelectedIndex();
556 btn_view.setVisible(true);
557 btn_cancel.setVisible(true);
558 if (sourceTabbedPane.getTitleAt(index).equals(configureCols))
560 btn_view.setEnabled(false);
561 btn_cancel.setEnabled(false);
562 btn_view.setVisible(false);
563 btn_cancel.setVisible(false);
564 previousWantedFields = pdbDocFieldPrefs
565 .getStructureSummaryFields()
566 .toArray(new FTSDataColumnI[0]);
568 if (sourceTabbedPane.getTitleAt(index)
569 .equals(foundStructureSummary))
571 btn_cancel.setEnabled(true);
572 if (wantedFieldsUpdated())
578 validateSelections();
583 pnl_filter.addChangeListener(changeListener);
584 pnl_filter.setPreferredSize(new Dimension(width, height));
585 pnl_filter.add(foundStructureSummary, scrl_foundStructures);
586 pnl_filter.add(configureCols, pdbDocFieldPrefs);
588 pnl_locPDB.add(scrl_localPDB);
590 pnl_switchableViews.add(pnl_fileChooserBL, VIEWS_FROM_FILE);
591 pnl_switchableViews.add(pnl_idInputBL, VIEWS_ENTER_ID);
592 pnl_switchableViews.add(pnl_filter, VIEWS_FILTER);
593 pnl_switchableViews.add(pnl_locPDB, VIEWS_LOCAL_PDB);
595 this.setLayout(mainLayout);
596 this.add(pnl_main, java.awt.BorderLayout.NORTH);
597 this.add(pnl_switchableViews, java.awt.BorderLayout.CENTER);
598 // this.add(pnl_actions, java.awt.BorderLayout.SOUTH);
599 statusPanel.setLayout(new GridLayout());
600 pnl_actionsAndStatus.add(pnl_actions, BorderLayout.CENTER);
601 pnl_actionsAndStatus.add(statusPanel, BorderLayout.SOUTH);
602 statusPanel.add(statusBar, null);
603 this.add(pnl_actionsAndStatus, java.awt.BorderLayout.SOUTH);
605 mainFrame.addInternalFrameListener(
606 new javax.swing.event.InternalFrameAdapter()
609 public void internalFrameClosing(InternalFrameEvent e)
611 closeAction(pnl_filter.getHeight());
614 mainFrame.setVisible(true);
615 mainFrame.setContentPane(this);
616 mainFrame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
617 Integer x = tempUserPrefs.get("structureChooser.x");
618 Integer y = tempUserPrefs.get("structureChooser.y");
619 if (x != null && y != null)
621 mainFrame.setLocation(x, y);
623 Desktop.addInternalFrame(mainFrame, frameTitle, width, height);
626 protected void closeAction(int preferredHeight)
628 // System.out.println(">>>>>>>>>> closing internal frame!!!");
629 // System.out.println("width : " + mainFrame.getWidth());
630 // System.out.println("heigh : " + mainFrame.getHeight());
631 // System.out.println("x : " + mainFrame.getX());
632 // System.out.println("y : " + mainFrame.getY());
633 tempUserPrefs.put("structureChooser.width", pnl_filter.getWidth());
634 tempUserPrefs.put("structureChooser.height", preferredHeight);
635 tempUserPrefs.put("structureChooser.x", mainFrame.getX());
636 tempUserPrefs.put("structureChooser.y", mainFrame.getY());
640 public boolean wantedFieldsUpdated()
642 if (previousWantedFields == null)
647 FTSDataColumnI[] currentWantedFields = pdbDocFieldPrefs
648 .getStructureSummaryFields().toArray(new FTSDataColumnI[0]);
649 return Arrays.equals(currentWantedFields, previousWantedFields) ? false
656 * Event listener for the 'filter' combo-box and 'invert' check-box
658 public void itemStateChanged(ItemEvent e)
664 * This inner class provides the data model for the structure filter combo-box
669 public class FilterOption
673 private String value;
677 private boolean addSeparatorAfter;
680 * Model for structure filter option
683 * - the name of the Option
685 * - the value of the option
687 * - the category of the filter option
688 * @param addSeparatorAfter
689 * - if true, a horizontal separator is rendered immediately after
690 * this filter option, otherwise
692 public FilterOption(String name, String value, String view,
693 boolean addSeparatorAfter)
698 this.addSeparatorAfter = addSeparatorAfter;
701 public String getName()
706 public void setName(String name)
711 public String getValue()
716 public void setValue(String value)
721 public String getView()
726 public void setView(String view)
732 public String toString()
737 public boolean isAddSeparatorAfter()
739 return addSeparatorAfter;
742 public void setAddSeparatorAfter(boolean addSeparatorAfter)
744 this.addSeparatorAfter = addSeparatorAfter;
749 * This inner class provides the provides the data model for associate
750 * sequence combo-box - cmb_assSeq
755 public class AssociateSeqOptions
757 private SequenceI sequence;
761 public AssociateSeqOptions(SequenceI seq)
764 this.name = (seq.getName().length() >= 23)
765 ? seq.getName().substring(0, 23)
769 public AssociateSeqOptions(String name, SequenceI seq)
776 public String toString()
781 public String getName()
786 public void setName(String name)
791 public SequenceI getSequence()
796 public void setSequence(SequenceI sequence)
798 this.sequence = sequence;
804 * This inner class holds the Layout and configuration of the panel which
805 * handles association of manually fetched structures to a unique sequence
806 * when more than one sequence selection is made
811 public class AssciateSeqPanel extends JPanel implements ItemListener
813 private JComboBox<AssociateSeqOptions> cmb_assSeq = new JComboBox<>();
815 private JLabel lbl_associateSeq = new JLabel();
817 public AssciateSeqPanel()
819 this.setLayout(new FlowLayout());
820 this.add(cmb_assSeq);
821 this.add(lbl_associateSeq);
822 cmb_assSeq.setToolTipText(
823 MessageManager.getString("info.associate_wit_sequence"));
824 cmb_assSeq.addItemListener(this);
827 public void loadCmbAssSeq()
829 populateCmbAssociateSeqOptions(cmb_assSeq, lbl_associateSeq);
832 public JComboBox<AssociateSeqOptions> getCmb_assSeq()
837 public void setCmb_assSeq(JComboBox<AssociateSeqOptions> cmb_assSeq)
839 this.cmb_assSeq = cmb_assSeq;
843 public void itemStateChanged(ItemEvent e)
845 if (e.getStateChange() == ItemEvent.SELECTED)
847 cmbAssSeqStateChanged();
852 public JTable getResultTable()
857 public JComboBox<FilterOption> getCmbFilterOption()
859 return cmb_filterOption;
863 * Custom ListCellRenderer for adding a separator between different categories
864 * of structure chooser filter option drop-down.
869 public abstract class CustomComboSeparatorsRenderer
870 implements ListCellRenderer<Object>
872 private ListCellRenderer<Object> regent;
874 private JPanel separatorPanel = new JPanel(new BorderLayout());
876 private JSeparator jSeparator = new JSeparator();
878 public CustomComboSeparatorsRenderer(
879 ListCellRenderer<Object> listCellRenderer)
881 this.regent = listCellRenderer;
885 public Component getListCellRendererComponent(JList list, Object value,
886 int index, boolean isSelected, boolean cellHasFocus)
889 Component comp = regent.getListCellRendererComponent(list, value,
890 index, isSelected, cellHasFocus);
892 && addSeparatorAfter(list, (FilterOption) value, index))
894 separatorPanel.removeAll();
895 separatorPanel.add(comp, BorderLayout.CENTER);
896 separatorPanel.add(jSeparator, BorderLayout.SOUTH);
897 return separatorPanel;
905 protected abstract boolean addSeparatorAfter(JList list,
906 FilterOption value, int index);
909 protected abstract void stateChanged(ItemEvent e);
911 protected abstract void ok_ActionPerformed();
913 protected abstract void pdbFromFile_actionPerformed();
915 protected abstract void txt_search_ActionPerformed();
917 public abstract void populateCmbAssociateSeqOptions(
918 JComboBox<AssociateSeqOptions> cmb_assSeq,
919 JLabel lbl_associateSeq);
921 public abstract void cmbAssSeqStateChanged();
923 public abstract void tabRefresh();
925 public abstract void validateSelections();