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 JCheckBox chk_superpose = new JCheckBox(
113 MessageManager.getString("label.superpose_structures"));
115 protected JTextField txt_search = new JTextField(14);
117 private JPanel pnl_actions = new JPanel(new MigLayout());
119 private JPanel pnl_main = new JPanel();
121 private JPanel pnl_idInput = new JPanel(new FlowLayout());
123 private JPanel pnl_fileChooser = new JPanel(new FlowLayout());
125 private JPanel pnl_idInputBL = new JPanel(new BorderLayout());
127 private JPanel pnl_fileChooserBL = new JPanel(new BorderLayout());
129 private JPanel pnl_locPDB = new JPanel(new BorderLayout());
131 protected JPanel pnl_switchableViews = new JPanel(new CardLayout());
133 protected CardLayout layout_switchableViews = (CardLayout) (pnl_switchableViews
136 private BorderLayout mainLayout = new BorderLayout();
138 protected JCheckBox chk_rememberSettings = new JCheckBox(
139 MessageManager.getString("label.dont_ask_me_again"));
141 protected JCheckBox chk_invertFilter = new JCheckBox(
142 MessageManager.getString("label.invert"));
144 protected ImageIcon loadingImage = new ImageIcon(
145 getClass().getResource("/images/loading.gif"));
147 protected ImageIcon goodImage = new ImageIcon(
148 getClass().getResource("/images/good.png"));
150 protected ImageIcon errorImage = new ImageIcon(
151 getClass().getResource("/images/error.png"));
153 protected ImageIcon warningImage = new ImageIcon(
154 getClass().getResource("/images/warning.gif"));
156 protected JLabel lbl_warning = new JLabel(warningImage);
158 protected JLabel lbl_loading = new JLabel(loadingImage);
160 protected JLabel lbl_pdbManualFetchStatus = new JLabel(errorImage);
162 protected JLabel lbl_fromFileStatus = new JLabel(errorImage);
164 protected AssciateSeqPanel idInputAssSeqPanel = new AssciateSeqPanel();
166 protected AssciateSeqPanel fileChooserAssSeqPanel = new AssciateSeqPanel();
168 protected static final String VIEWS_FILTER = "VIEWS_FILTER";
170 protected static final String VIEWS_FROM_FILE = "VIEWS_FROM_FILE";
172 protected static final String VIEWS_ENTER_ID = "VIEWS_ENTER_ID";
174 protected JComboBox<StructureViewer> targetView = new JComboBox();
177 * 'cached' structure view
179 protected static final String VIEWS_LOCAL_PDB = "VIEWS_LOCAL_PDB";
181 protected JTable tbl_local_pdb = new JTable();
183 protected JScrollPane scrl_localPDB = new JScrollPane(tbl_local_pdb);
185 protected JTabbedPane pnl_filter = new JTabbedPane();
187 protected FTSDataColumnPreferences pdbDocFieldPrefs = new FTSDataColumnPreferences(
188 PreferenceSource.STRUCTURE_CHOOSER,
189 PDBFTSRestClient.getInstance());
191 protected FTSDataColumnI[] previousWantedFields;
193 protected static Map<String, Integer> tempUserPrefs = new HashMap<>();
195 private JTable tbl_summary = new JTable()
197 private boolean inLayout;
200 public boolean getScrollableTracksViewportWidth()
202 return hasExcessWidth();
207 public void doLayout()
209 if (hasExcessWidth())
211 autoResizeMode = AUTO_RESIZE_SUBSEQUENT_COLUMNS;
216 autoResizeMode = AUTO_RESIZE_OFF;
219 protected boolean hasExcessWidth()
221 return getPreferredSize().width < getParent().getWidth();
225 public void columnMarginChanged(ChangeEvent e)
231 TableColumn resizingColumn = getTableHeader().getResizingColumn();
232 // Need to do this here, before the parent's
233 // layout manager calls getPreferredSize().
234 if (resizingColumn != null && autoResizeMode == AUTO_RESIZE_OFF
237 resizingColumn.setPreferredWidth(resizingColumn.getWidth());
238 String colHeader = resizingColumn.getHeaderValue().toString();
239 tempUserPrefs.put(colHeader, resizingColumn.getWidth());
245 public String getToolTipText(MouseEvent evt)
247 String toolTipText = null;
248 java.awt.Point pnt = evt.getPoint();
249 int rowIndex = rowAtPoint(pnt);
250 int colIndex = columnAtPoint(pnt);
254 if (getValueAt(rowIndex, colIndex) == null)
258 toolTipText = getValueAt(rowIndex, colIndex).toString();
259 } catch (Exception e)
261 // e.printStackTrace();
263 toolTipText = (toolTipText == null ? null
264 : (toolTipText.length() > 500
265 ? JvSwingUtils.wrapTooltip(true,
266 "\"" + toolTipText.subSequence(0, 500)
268 : JvSwingUtils.wrapTooltip(true, toolTipText)));
273 protected JScrollPane scrl_foundStructures = new JScrollPane(tbl_summary);
275 public GStructureChooser()
280 mainFrame.setVisible(false);
281 mainFrame.invalidate();
283 } catch (Exception e)
290 * Initializes the GUI default properties
294 private void jbInit() throws Exception
296 Integer width = tempUserPrefs.get("structureChooser.width") == null
298 : tempUserPrefs.get("structureChooser.width");
299 Integer height = tempUserPrefs.get("structureChooser.height") == null
301 : tempUserPrefs.get("structureChooser.height");
302 tbl_summary.setAutoCreateRowSorter(true);
303 tbl_summary.getTableHeader().setReorderingAllowed(false);
304 tbl_summary.addMouseListener(new MouseAdapter()
307 public void mouseClicked(MouseEvent e)
309 validateSelections();
313 public void mouseReleased(MouseEvent e)
315 validateSelections();
318 tbl_summary.addKeyListener(new KeyAdapter()
321 public void keyPressed(KeyEvent evt)
323 validateSelections();
324 switch (evt.getKeyCode())
326 case KeyEvent.VK_ESCAPE: // escape key
329 case KeyEvent.VK_ENTER: // enter key
330 if (btn_view.isEnabled())
332 ok_ActionPerformed();
335 case KeyEvent.VK_TAB: // tab key
336 if (evt.isShiftDown())
338 pnl_filter.requestFocus();
342 btn_view.requestFocus();
351 tbl_local_pdb.setAutoCreateRowSorter(true);
352 tbl_local_pdb.getTableHeader().setReorderingAllowed(false);
353 tbl_local_pdb.addMouseListener(new MouseAdapter()
356 public void mouseClicked(MouseEvent e)
358 validateSelections();
362 public void mouseReleased(MouseEvent e)
364 validateSelections();
367 tbl_local_pdb.addKeyListener(new KeyAdapter()
370 public void keyPressed(KeyEvent evt)
372 validateSelections();
373 switch (evt.getKeyCode())
375 case KeyEvent.VK_ESCAPE: // escape key
378 case KeyEvent.VK_ENTER: // enter key
379 if (btn_view.isEnabled())
381 ok_ActionPerformed();
384 case KeyEvent.VK_TAB: // tab key
385 if (evt.isShiftDown())
387 cmb_filterOption.requestFocus();
391 if (btn_view.isEnabled())
393 btn_view.requestFocus();
397 btn_cancel.requestFocus();
407 btn_view.setFont(new java.awt.Font("Verdana", 0, 12));
408 btn_view.setText(MessageManager.getString("action.view"));
409 btn_view.addActionListener(new java.awt.event.ActionListener()
412 public void actionPerformed(ActionEvent e)
414 ok_ActionPerformed();
417 btn_view.addKeyListener(new KeyAdapter()
420 public void keyPressed(KeyEvent evt)
422 if (evt.getKeyCode() == KeyEvent.VK_ENTER)
424 ok_ActionPerformed();
429 btn_cancel.setFont(new java.awt.Font("Verdana", 0, 12));
430 btn_cancel.setText(MessageManager.getString("action.cancel"));
431 btn_cancel.addActionListener(new java.awt.event.ActionListener()
434 public void actionPerformed(ActionEvent e)
436 closeAction(pnl_filter.getHeight());
439 btn_cancel.addKeyListener(new KeyAdapter()
442 public void keyPressed(KeyEvent evt)
444 if (evt.getKeyCode() == KeyEvent.VK_ENTER)
446 closeAction(pnl_filter.getHeight());
451 btn_pdbFromFile.setFont(new java.awt.Font("Verdana", 0, 12));
452 String btn_title = MessageManager.getString("label.select_pdb_file");
453 btn_pdbFromFile.setText(btn_title + " ");
454 btn_pdbFromFile.addActionListener(new java.awt.event.ActionListener()
457 public void actionPerformed(ActionEvent e)
459 pdbFromFile_actionPerformed();
462 btn_pdbFromFile.addKeyListener(new KeyAdapter()
465 public void keyPressed(KeyEvent evt)
467 if (evt.getKeyCode() == KeyEvent.VK_ENTER)
469 pdbFromFile_actionPerformed();
474 scrl_foundStructures.setPreferredSize(new Dimension(width, height));
476 scrl_localPDB.setPreferredSize(new Dimension(width, height));
477 scrl_localPDB.setHorizontalScrollBarPolicy(
478 JScrollPane.HORIZONTAL_SCROLLBAR_NEVER);
480 cmb_filterOption.setFont(new java.awt.Font("Verdana", 0, 12));
481 chk_invertFilter.setFont(new java.awt.Font("Verdana", 0, 12));
482 chk_rememberSettings.setFont(new java.awt.Font("Verdana", 0, 12));
483 chk_rememberSettings.setVisible(false);
484 txt_search.setToolTipText(JvSwingUtils.wrapTooltip(true,
485 MessageManager.getString("label.enter_pdb_id_tip")));
486 cmb_filterOption.setToolTipText(
487 MessageManager.getString("info.select_filter_option"));
488 txt_search.getDocument().addDocumentListener(new DocumentListener()
491 public void insertUpdate(DocumentEvent e)
493 txt_search_ActionPerformed();
497 public void removeUpdate(DocumentEvent e)
499 txt_search_ActionPerformed();
503 public void changedUpdate(DocumentEvent e)
505 txt_search_ActionPerformed();
509 cmb_filterOption.addItemListener(this);
511 // add CustomComboSeparatorsRenderer to filter option combo-box
512 cmb_filterOption.setRenderer(new CustomComboSeparatorsRenderer(
513 (ListCellRenderer<Object>) cmb_filterOption.getRenderer())
516 protected boolean addSeparatorAfter(JList list, FilterOption value,
519 return value.isAddSeparatorAfter();
523 chk_invertFilter.addItemListener(this);
525 targetView.setVisible(false);
526 pnl_actions.add(targetView,"wrap");
527 pnl_actions.add(chk_rememberSettings);
528 pnl_actions.add(btn_view);
529 pnl_actions.add(btn_cancel);
530 pnl_actions.add(chk_superpose, "left");
532 // pnl_filter.add(lbl_result);
533 pnl_main.add(cmb_filterOption);
534 pnl_main.add(lbl_loading);
535 pnl_main.add(chk_invertFilter);
536 lbl_loading.setVisible(false);
538 pnl_fileChooser.add(btn_pdbFromFile);
539 pnl_fileChooser.add(lbl_fromFileStatus);
540 pnl_fileChooserBL.add(fileChooserAssSeqPanel, BorderLayout.NORTH);
541 pnl_fileChooserBL.add(pnl_fileChooser, BorderLayout.CENTER);
543 pnl_idInput.add(txt_search);
544 pnl_idInput.add(lbl_pdbManualFetchStatus);
545 pnl_idInputBL.add(idInputAssSeqPanel, BorderLayout.NORTH);
546 pnl_idInputBL.add(pnl_idInput, BorderLayout.CENTER);
548 final String foundStructureSummary = MessageManager
549 .getString("label.found_structures_summary");
550 final String configureCols = MessageManager
551 .getString("label.configure_displayed_columns");
552 ChangeListener changeListener = new ChangeListener()
555 public void stateChanged(ChangeEvent changeEvent)
557 JTabbedPane sourceTabbedPane = (JTabbedPane) changeEvent
559 int index = sourceTabbedPane.getSelectedIndex();
560 btn_view.setVisible(true);
561 btn_cancel.setVisible(true);
562 if (sourceTabbedPane.getTitleAt(index).equals(configureCols))
564 btn_view.setEnabled(false);
565 btn_cancel.setEnabled(false);
566 btn_view.setVisible(false);
567 btn_cancel.setVisible(false);
568 previousWantedFields = pdbDocFieldPrefs
569 .getStructureSummaryFields()
570 .toArray(new FTSDataColumnI[0]);
572 if (sourceTabbedPane.getTitleAt(index)
573 .equals(foundStructureSummary))
575 btn_cancel.setEnabled(true);
576 if (wantedFieldsUpdated())
582 validateSelections();
587 pnl_filter.addChangeListener(changeListener);
588 pnl_filter.setPreferredSize(new Dimension(width, height));
589 pnl_filter.add(foundStructureSummary, scrl_foundStructures);
590 pnl_filter.add(configureCols, pdbDocFieldPrefs);
592 pnl_locPDB.add(scrl_localPDB);
594 pnl_switchableViews.add(pnl_fileChooserBL, VIEWS_FROM_FILE);
595 pnl_switchableViews.add(pnl_idInputBL, VIEWS_ENTER_ID);
596 pnl_switchableViews.add(pnl_filter, VIEWS_FILTER);
597 pnl_switchableViews.add(pnl_locPDB, VIEWS_LOCAL_PDB);
599 this.setLayout(mainLayout);
600 this.add(pnl_main, java.awt.BorderLayout.NORTH);
601 this.add(pnl_switchableViews, java.awt.BorderLayout.CENTER);
602 // this.add(pnl_actions, java.awt.BorderLayout.SOUTH);
603 statusPanel.setLayout(new GridLayout());
604 pnl_actionsAndStatus.add(pnl_actions, BorderLayout.CENTER);
605 pnl_actionsAndStatus.add(statusPanel, BorderLayout.SOUTH);
606 statusPanel.add(statusBar, null);
607 this.add(pnl_actionsAndStatus, java.awt.BorderLayout.SOUTH);
609 mainFrame.addInternalFrameListener(
610 new javax.swing.event.InternalFrameAdapter()
613 public void internalFrameClosing(InternalFrameEvent e)
615 closeAction(pnl_filter.getHeight());
618 mainFrame.setVisible(true);
619 mainFrame.setContentPane(this);
620 mainFrame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
621 Integer x = tempUserPrefs.get("structureChooser.x");
622 Integer y = tempUserPrefs.get("structureChooser.y");
623 if (x != null && y != null)
625 mainFrame.setLocation(x, y);
627 Desktop.addInternalFrame(mainFrame, frameTitle, width, height);
630 protected void closeAction(int preferredHeight)
632 // System.out.println(">>>>>>>>>> closing internal frame!!!");
633 // System.out.println("width : " + mainFrame.getWidth());
634 // System.out.println("heigh : " + mainFrame.getHeight());
635 // System.out.println("x : " + mainFrame.getX());
636 // System.out.println("y : " + mainFrame.getY());
637 tempUserPrefs.put("structureChooser.width", pnl_filter.getWidth());
638 tempUserPrefs.put("structureChooser.height", preferredHeight);
639 tempUserPrefs.put("structureChooser.x", mainFrame.getX());
640 tempUserPrefs.put("structureChooser.y", mainFrame.getY());
644 public boolean wantedFieldsUpdated()
646 if (previousWantedFields == null)
651 FTSDataColumnI[] currentWantedFields = pdbDocFieldPrefs
652 .getStructureSummaryFields().toArray(new FTSDataColumnI[0]);
653 return Arrays.equals(currentWantedFields, previousWantedFields) ? false
660 * Event listener for the 'filter' combo-box and 'invert' check-box
662 public void itemStateChanged(ItemEvent e)
668 * This inner class provides the data model for the structure filter combo-box
673 public class FilterOption
677 private String value;
681 private boolean addSeparatorAfter;
684 * Model for structure filter option
687 * - the name of the Option
689 * - the value of the option
691 * - the category of the filter option
692 * @param addSeparatorAfter
693 * - if true, a horizontal separator is rendered immediately after
694 * this filter option, otherwise
696 public FilterOption(String name, String value, String view,
697 boolean addSeparatorAfter)
702 this.addSeparatorAfter = addSeparatorAfter;
705 public String getName()
710 public void setName(String name)
715 public String getValue()
720 public void setValue(String value)
725 public String getView()
730 public void setView(String view)
736 public String toString()
741 public boolean isAddSeparatorAfter()
743 return addSeparatorAfter;
746 public void setAddSeparatorAfter(boolean addSeparatorAfter)
748 this.addSeparatorAfter = addSeparatorAfter;
753 * This inner class provides the provides the data model for associate
754 * sequence combo-box - cmb_assSeq
759 public class AssociateSeqOptions
761 private SequenceI sequence;
765 public AssociateSeqOptions(SequenceI seq)
768 this.name = (seq.getName().length() >= 23)
769 ? seq.getName().substring(0, 23)
773 public AssociateSeqOptions(String name, SequenceI seq)
780 public String toString()
785 public String getName()
790 public void setName(String name)
795 public SequenceI getSequence()
800 public void setSequence(SequenceI sequence)
802 this.sequence = sequence;
808 * This inner class holds the Layout and configuration of the panel which
809 * handles association of manually fetched structures to a unique sequence
810 * when more than one sequence selection is made
815 public class AssciateSeqPanel extends JPanel implements ItemListener
817 private JComboBox<AssociateSeqOptions> cmb_assSeq = new JComboBox<>();
819 private JLabel lbl_associateSeq = new JLabel();
821 public AssciateSeqPanel()
823 this.setLayout(new FlowLayout());
824 this.add(cmb_assSeq);
825 this.add(lbl_associateSeq);
826 cmb_assSeq.setToolTipText(
827 MessageManager.getString("info.associate_wit_sequence"));
828 cmb_assSeq.addItemListener(this);
831 public void loadCmbAssSeq()
833 populateCmbAssociateSeqOptions(cmb_assSeq, lbl_associateSeq);
836 public JComboBox<AssociateSeqOptions> getCmb_assSeq()
841 public void setCmb_assSeq(JComboBox<AssociateSeqOptions> cmb_assSeq)
843 this.cmb_assSeq = cmb_assSeq;
847 public void itemStateChanged(ItemEvent e)
849 if (e.getStateChange() == ItemEvent.SELECTED)
851 cmbAssSeqStateChanged();
856 public JTable getResultTable()
861 public JComboBox<FilterOption> getCmbFilterOption()
863 return cmb_filterOption;
867 * Custom ListCellRenderer for adding a separator between different categories
868 * of structure chooser filter option drop-down.
873 public abstract class CustomComboSeparatorsRenderer
874 implements ListCellRenderer<Object>
876 private ListCellRenderer<Object> regent;
878 private JPanel separatorPanel = new JPanel(new BorderLayout());
880 private JSeparator jSeparator = new JSeparator();
882 public CustomComboSeparatorsRenderer(
883 ListCellRenderer<Object> listCellRenderer)
885 this.regent = listCellRenderer;
889 public Component getListCellRendererComponent(JList list, Object value,
890 int index, boolean isSelected, boolean cellHasFocus)
893 Component comp = regent.getListCellRendererComponent(list, value,
894 index, isSelected, cellHasFocus);
896 && addSeparatorAfter(list, (FilterOption) value, index))
898 separatorPanel.removeAll();
899 separatorPanel.add(comp, BorderLayout.CENTER);
900 separatorPanel.add(jSeparator, BorderLayout.SOUTH);
901 return separatorPanel;
909 protected abstract boolean addSeparatorAfter(JList list,
910 FilterOption value, int index);
913 protected abstract void stateChanged(ItemEvent e);
915 protected abstract void ok_ActionPerformed();
917 protected abstract void pdbFromFile_actionPerformed();
919 protected abstract void txt_search_ActionPerformed();
921 public abstract void populateCmbAssociateSeqOptions(
922 JComboBox<AssociateSeqOptions> cmb_assSeq,
923 JLabel lbl_associateSeq);
925 public abstract void cmbAssSeqStateChanged();
927 public abstract void tabRefresh();
929 public abstract void validateSelections();