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.util.MessageManager;
34 import java.awt.BorderLayout;
35 import java.awt.CardLayout;
36 import java.awt.Component;
37 import java.awt.Dimension;
38 import java.awt.FlowLayout;
39 import java.awt.GridLayout;
40 import java.awt.event.ActionEvent;
41 import java.awt.event.ItemEvent;
42 import java.awt.event.ItemListener;
43 import java.awt.event.KeyAdapter;
44 import java.awt.event.KeyEvent;
45 import java.awt.event.MouseAdapter;
46 import java.awt.event.MouseEvent;
47 import java.util.Arrays;
48 import java.util.HashMap;
51 import javax.swing.ImageIcon;
52 import javax.swing.JButton;
53 import javax.swing.JCheckBox;
54 import javax.swing.JComboBox;
55 import javax.swing.JFrame;
56 import javax.swing.JInternalFrame;
57 import javax.swing.JLabel;
58 import javax.swing.JList;
59 import javax.swing.JPanel;
60 import javax.swing.JScrollPane;
61 import javax.swing.JSeparator;
62 import javax.swing.JTabbedPane;
63 import javax.swing.JTable;
64 import javax.swing.JTextField;
65 import javax.swing.ListCellRenderer;
66 import javax.swing.event.ChangeEvent;
67 import javax.swing.event.ChangeListener;
68 import javax.swing.event.DocumentEvent;
69 import javax.swing.event.DocumentListener;
70 import javax.swing.event.InternalFrameEvent;
71 import javax.swing.table.TableColumn;
73 @SuppressWarnings("serial")
75 * GUI layout for structure chooser
80 public abstract class GStructureChooser extends JPanel
81 implements ItemListener
83 protected JPanel statusPanel = new JPanel();
85 public JLabel statusBar = new JLabel();
87 private JPanel pnl_actionsAndStatus = new JPanel(new BorderLayout());
89 protected String frameTitle = MessageManager
90 .getString("label.structure_chooser");
92 protected JInternalFrame mainFrame = new JInternalFrame(frameTitle);
94 protected JComboBox<FilterOption> cmb_filterOption = new JComboBox<FilterOption>();
96 protected AlignmentPanel ap;
98 protected StringBuilder errorWarning = new StringBuilder();
100 protected JLabel lbl_result = new JLabel(
101 MessageManager.getString("label.select"));
103 protected JButton btn_view = new JButton();
105 protected JButton btn_cancel = new JButton();
107 protected JButton btn_pdbFromFile = new JButton();
109 protected JTextField txt_search = new JTextField(14);
111 private JPanel pnl_actions = new JPanel();
113 private JPanel pnl_main = new JPanel();
115 private JPanel pnl_idInput = new JPanel(new FlowLayout());
117 private JPanel pnl_fileChooser = new JPanel(new FlowLayout());
119 private JPanel pnl_idInputBL = new JPanel(new BorderLayout());
121 private JPanel pnl_fileChooserBL = new JPanel(new BorderLayout());
123 private JPanel pnl_locPDB = new JPanel(new BorderLayout());
125 protected JPanel pnl_switchableViews = new JPanel(new CardLayout());
127 protected CardLayout layout_switchableViews = (CardLayout) (pnl_switchableViews
130 private BorderLayout mainLayout = new BorderLayout();
132 protected JCheckBox chk_rememberSettings = new JCheckBox(
133 MessageManager.getString("label.dont_ask_me_again"));
135 protected JCheckBox chk_invertFilter = new JCheckBox(
136 MessageManager.getString("label.invert"));
138 protected ImageIcon loadingImage = new ImageIcon(
139 getClass().getResource("/images/loading.gif"));
141 protected ImageIcon goodImage = new ImageIcon(
142 getClass().getResource("/images/good.png"));
144 protected ImageIcon errorImage = new ImageIcon(
145 getClass().getResource("/images/error.png"));
147 protected ImageIcon warningImage = new ImageIcon(
148 getClass().getResource("/images/warning.gif"));
150 protected JLabel lbl_warning = new JLabel(warningImage);
152 protected JLabel lbl_loading = new JLabel(loadingImage);
154 protected JLabel lbl_pdbManualFetchStatus = new JLabel(errorImage);
156 protected JLabel lbl_fromFileStatus = new JLabel(errorImage);
158 protected AssciateSeqPanel idInputAssSeqPanel = new AssciateSeqPanel();
160 protected AssciateSeqPanel fileChooserAssSeqPanel = new AssciateSeqPanel();
162 protected static final String VIEWS_FILTER = "VIEWS_FILTER";
164 protected static final String VIEWS_FROM_FILE = "VIEWS_FROM_FILE";
166 protected static final String VIEWS_ENTER_ID = "VIEWS_ENTER_ID";
169 * 'cached' structure view
171 protected static final String VIEWS_LOCAL_PDB = "VIEWS_LOCAL_PDB";
173 protected JTable tbl_local_pdb = new JTable();
175 protected JScrollPane scrl_localPDB = new JScrollPane(tbl_local_pdb);
177 protected JTabbedPane pnl_filter = new JTabbedPane();
179 protected FTSDataColumnPreferences pdbDocFieldPrefs = new FTSDataColumnPreferences(
180 PreferenceSource.STRUCTURE_CHOOSER,
181 PDBFTSRestClient.getInstance());
183 protected FTSDataColumnI[] previousWantedFields;
185 protected static Map<String, Integer> tempUserPrefs = new HashMap<String, Integer>();
187 private JTable tbl_summary = new JTable()
189 private boolean inLayout;
192 public boolean getScrollableTracksViewportWidth()
194 return hasExcessWidth();
199 public void doLayout()
201 if (hasExcessWidth())
203 autoResizeMode = AUTO_RESIZE_SUBSEQUENT_COLUMNS;
208 autoResizeMode = AUTO_RESIZE_OFF;
211 protected boolean hasExcessWidth()
213 return getPreferredSize().width < getParent().getWidth();
217 public void columnMarginChanged(ChangeEvent e)
223 TableColumn resizingColumn = getTableHeader().getResizingColumn();
224 // Need to do this here, before the parent's
225 // layout manager calls getPreferredSize().
226 if (resizingColumn != null && autoResizeMode == AUTO_RESIZE_OFF
229 resizingColumn.setPreferredWidth(resizingColumn.getWidth());
230 String colHeader = resizingColumn.getHeaderValue().toString();
231 tempUserPrefs.put(colHeader, resizingColumn.getWidth());
237 public String getToolTipText(MouseEvent evt)
239 String toolTipText = null;
240 java.awt.Point pnt = evt.getPoint();
241 int rowIndex = rowAtPoint(pnt);
242 int colIndex = columnAtPoint(pnt);
246 if (getValueAt(rowIndex, colIndex) == null)
250 toolTipText = getValueAt(rowIndex, colIndex).toString();
251 } catch (Exception e)
253 // e.printStackTrace();
255 toolTipText = (toolTipText == null ? null
256 : (toolTipText.length() > 500
257 ? JvSwingUtils.wrapTooltip(true,
258 "\"" + toolTipText.subSequence(0, 500)
260 : JvSwingUtils.wrapTooltip(true, toolTipText)));
265 protected JScrollPane scrl_foundStructures = new JScrollPane(tbl_summary);
267 public GStructureChooser()
272 mainFrame.setVisible(false);
273 mainFrame.invalidate();
275 } catch (Exception e)
282 * Initializes the GUI default properties
286 private void jbInit() throws Exception
288 Integer width = tempUserPrefs.get("structureChooser.width") == null
290 : tempUserPrefs.get("structureChooser.width");
291 Integer height = tempUserPrefs.get("structureChooser.height") == null
293 : tempUserPrefs.get("structureChooser.height");
294 tbl_summary.setAutoCreateRowSorter(true);
295 tbl_summary.getTableHeader().setReorderingAllowed(false);
296 tbl_summary.addMouseListener(new MouseAdapter()
299 public void mouseClicked(MouseEvent e)
301 validateSelections();
305 public void mouseReleased(MouseEvent e)
307 validateSelections();
310 tbl_summary.addKeyListener(new KeyAdapter()
313 public void keyPressed(KeyEvent evt)
315 validateSelections();
316 switch (evt.getKeyCode())
318 case KeyEvent.VK_ESCAPE: // escape key
321 case KeyEvent.VK_ENTER: // enter key
322 if (btn_view.isEnabled())
324 ok_ActionPerformed();
327 case KeyEvent.VK_TAB: // tab key
328 if (evt.isShiftDown())
330 pnl_filter.requestFocus();
334 btn_view.requestFocus();
343 tbl_local_pdb.setAutoCreateRowSorter(true);
344 tbl_local_pdb.getTableHeader().setReorderingAllowed(false);
345 tbl_local_pdb.addMouseListener(new MouseAdapter()
348 public void mouseClicked(MouseEvent e)
350 validateSelections();
354 public void mouseReleased(MouseEvent e)
356 validateSelections();
359 tbl_local_pdb.addKeyListener(new KeyAdapter()
362 public void keyPressed(KeyEvent evt)
364 validateSelections();
365 switch (evt.getKeyCode())
367 case KeyEvent.VK_ESCAPE: // escape key
370 case KeyEvent.VK_ENTER: // enter key
371 if (btn_view.isEnabled())
373 ok_ActionPerformed();
376 case KeyEvent.VK_TAB: // tab key
377 if (evt.isShiftDown())
379 cmb_filterOption.requestFocus();
383 if (btn_view.isEnabled())
385 btn_view.requestFocus();
389 btn_cancel.requestFocus();
399 btn_view.setFont(new java.awt.Font("Verdana", 0, 12));
400 btn_view.setText(MessageManager.getString("action.view"));
401 btn_view.addActionListener(new java.awt.event.ActionListener()
404 public void actionPerformed(ActionEvent e)
406 ok_ActionPerformed();
409 btn_view.addKeyListener(new KeyAdapter()
412 public void keyPressed(KeyEvent evt)
414 if (evt.getKeyCode() == KeyEvent.VK_ENTER)
416 ok_ActionPerformed();
421 btn_cancel.setFont(new java.awt.Font("Verdana", 0, 12));
422 btn_cancel.setText(MessageManager.getString("action.cancel"));
423 btn_cancel.addActionListener(new java.awt.event.ActionListener()
426 public void actionPerformed(ActionEvent e)
428 closeAction(pnl_filter.getHeight());
431 btn_cancel.addKeyListener(new KeyAdapter()
434 public void keyPressed(KeyEvent evt)
436 if (evt.getKeyCode() == KeyEvent.VK_ENTER)
438 closeAction(pnl_filter.getHeight());
443 btn_pdbFromFile.setFont(new java.awt.Font("Verdana", 0, 12));
444 String btn_title = MessageManager.getString("label.select_pdb_file");
445 btn_pdbFromFile.setText(btn_title + " ");
446 btn_pdbFromFile.addActionListener(new java.awt.event.ActionListener()
449 public void actionPerformed(ActionEvent e)
451 pdbFromFile_actionPerformed();
454 btn_pdbFromFile.addKeyListener(new KeyAdapter()
457 public void keyPressed(KeyEvent evt)
459 if (evt.getKeyCode() == KeyEvent.VK_ENTER)
461 pdbFromFile_actionPerformed();
466 scrl_foundStructures.setPreferredSize(new Dimension(width, height));
468 scrl_localPDB.setPreferredSize(new Dimension(width, height));
469 scrl_localPDB.setHorizontalScrollBarPolicy(
470 JScrollPane.HORIZONTAL_SCROLLBAR_NEVER);
472 cmb_filterOption.setFont(new java.awt.Font("Verdana", 0, 12));
473 chk_invertFilter.setFont(new java.awt.Font("Verdana", 0, 12));
474 chk_rememberSettings.setFont(new java.awt.Font("Verdana", 0, 12));
475 chk_rememberSettings.setVisible(false);
476 txt_search.setToolTipText(JvSwingUtils.wrapTooltip(true,
477 MessageManager.getString("label.enter_pdb_id")));
478 cmb_filterOption.setToolTipText(
479 MessageManager.getString("info.select_filter_option"));
480 txt_search.getDocument().addDocumentListener(new DocumentListener()
483 public void insertUpdate(DocumentEvent e)
485 txt_search_ActionPerformed();
489 public void removeUpdate(DocumentEvent e)
491 txt_search_ActionPerformed();
495 public void changedUpdate(DocumentEvent e)
497 txt_search_ActionPerformed();
501 cmb_filterOption.addItemListener(this);
503 // add CustomComboSeparatorsRenderer to filter option combo-box
504 cmb_filterOption.setRenderer(new CustomComboSeparatorsRenderer(
505 (ListCellRenderer<Object>) cmb_filterOption.getRenderer())
508 protected boolean addSeparatorAfter(JList list, FilterOption value,
511 return value.isAddSeparatorAfter();
515 chk_invertFilter.addItemListener(this);
517 pnl_actions.add(chk_rememberSettings);
518 pnl_actions.add(btn_view);
519 pnl_actions.add(btn_cancel);
521 // pnl_filter.add(lbl_result);
522 pnl_main.add(cmb_filterOption);
523 pnl_main.add(lbl_loading);
524 pnl_main.add(chk_invertFilter);
525 lbl_loading.setVisible(false);
527 pnl_fileChooser.add(btn_pdbFromFile);
528 pnl_fileChooser.add(lbl_fromFileStatus);
529 pnl_fileChooserBL.add(fileChooserAssSeqPanel, BorderLayout.NORTH);
530 pnl_fileChooserBL.add(pnl_fileChooser, BorderLayout.CENTER);
532 pnl_idInput.add(txt_search);
533 pnl_idInput.add(lbl_pdbManualFetchStatus);
534 pnl_idInputBL.add(idInputAssSeqPanel, BorderLayout.NORTH);
535 pnl_idInputBL.add(pnl_idInput, BorderLayout.CENTER);
537 final String foundStructureSummary = MessageManager
538 .getString("label.found_structures_summary");
539 final String configureCols = MessageManager
540 .getString("label.configure_displayed_columns");
541 ChangeListener changeListener = new ChangeListener()
544 public void stateChanged(ChangeEvent changeEvent)
546 JTabbedPane sourceTabbedPane = (JTabbedPane) changeEvent
548 int index = sourceTabbedPane.getSelectedIndex();
549 btn_view.setVisible(true);
550 btn_cancel.setVisible(true);
551 if (sourceTabbedPane.getTitleAt(index).equals(configureCols))
553 btn_view.setEnabled(false);
554 btn_cancel.setEnabled(false);
555 btn_view.setVisible(false);
556 btn_cancel.setVisible(false);
557 previousWantedFields = pdbDocFieldPrefs
558 .getStructureSummaryFields()
559 .toArray(new FTSDataColumnI[0]);
561 if (sourceTabbedPane.getTitleAt(index)
562 .equals(foundStructureSummary))
564 btn_cancel.setEnabled(true);
565 if (wantedFieldsUpdated())
571 validateSelections();
576 pnl_filter.addChangeListener(changeListener);
577 pnl_filter.setPreferredSize(new Dimension(width, height));
578 pnl_filter.add(foundStructureSummary, scrl_foundStructures);
579 pnl_filter.add(configureCols, pdbDocFieldPrefs);
581 pnl_locPDB.add(scrl_localPDB);
583 pnl_switchableViews.add(pnl_fileChooserBL, VIEWS_FROM_FILE);
584 pnl_switchableViews.add(pnl_idInputBL, VIEWS_ENTER_ID);
585 pnl_switchableViews.add(pnl_filter, VIEWS_FILTER);
586 pnl_switchableViews.add(pnl_locPDB, VIEWS_LOCAL_PDB);
588 this.setLayout(mainLayout);
589 this.add(pnl_main, java.awt.BorderLayout.NORTH);
590 this.add(pnl_switchableViews, java.awt.BorderLayout.CENTER);
591 // this.add(pnl_actions, java.awt.BorderLayout.SOUTH);
592 statusPanel.setLayout(new GridLayout());
593 pnl_actionsAndStatus.add(pnl_actions, BorderLayout.CENTER);
594 pnl_actionsAndStatus.add(statusPanel, BorderLayout.SOUTH);
595 statusPanel.add(statusBar, null);
596 this.add(pnl_actionsAndStatus, java.awt.BorderLayout.SOUTH);
598 mainFrame.addInternalFrameListener(
599 new javax.swing.event.InternalFrameAdapter()
602 public void internalFrameClosing(InternalFrameEvent e)
604 closeAction(pnl_filter.getHeight());
607 mainFrame.setVisible(true);
608 mainFrame.setContentPane(this);
609 mainFrame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
610 Integer x = tempUserPrefs.get("structureChooser.x");
611 Integer y = tempUserPrefs.get("structureChooser.y");
612 if (x != null && y != null)
614 mainFrame.setLocation(x, y);
616 Desktop.addInternalFrame(mainFrame, frameTitle, width, height);
619 protected void closeAction(int preferredHeight)
621 // System.out.println(">>>>>>>>>> closing internal frame!!!");
622 // System.out.println("width : " + mainFrame.getWidth());
623 // System.out.println("heigh : " + mainFrame.getHeight());
624 // System.out.println("x : " + mainFrame.getX());
625 // System.out.println("y : " + mainFrame.getY());
626 tempUserPrefs.put("structureChooser.width", pnl_filter.getWidth());
627 tempUserPrefs.put("structureChooser.height", preferredHeight);
628 tempUserPrefs.put("structureChooser.x", mainFrame.getX());
629 tempUserPrefs.put("structureChooser.y", mainFrame.getY());
633 public boolean wantedFieldsUpdated()
635 if (previousWantedFields == null)
640 FTSDataColumnI[] currentWantedFields = pdbDocFieldPrefs
641 .getStructureSummaryFields().toArray(new FTSDataColumnI[0]);
642 return Arrays.equals(currentWantedFields, previousWantedFields) ? false
649 * Event listener for the 'filter' combo-box and 'invert' check-box
651 public void itemStateChanged(ItemEvent e)
657 * This inner class provides the data model for the structure filter combo-box
662 public class FilterOption
666 private String value;
670 private boolean addSeparatorAfter;
673 * Model for structure filter option
676 * - the name of the Option
678 * - the value of the option
680 * - the category of the filter option
681 * @param addSeparatorAfter
682 * - if true, a horizontal separator is rendered immediately after
683 * this filter option, otherwise
685 public FilterOption(String name, String value, String view,
686 boolean addSeparatorAfter)
691 this.addSeparatorAfter = addSeparatorAfter;
694 public String getName()
699 public void setName(String name)
704 public String getValue()
709 public void setValue(String value)
714 public String getView()
719 public void setView(String view)
725 public String toString()
730 public boolean isAddSeparatorAfter()
732 return addSeparatorAfter;
735 public void setAddSeparatorAfter(boolean addSeparatorAfter)
737 this.addSeparatorAfter = addSeparatorAfter;
742 * This inner class provides the provides the data model for associate
743 * sequence combo-box - cmb_assSeq
748 public class AssociateSeqOptions
750 private SequenceI sequence;
754 public AssociateSeqOptions(SequenceI seq)
757 this.name = (seq.getName().length() >= 23)
758 ? seq.getName().substring(0, 23)
762 public AssociateSeqOptions(String name, SequenceI seq)
769 public String toString()
774 public String getName()
779 public void setName(String name)
784 public SequenceI getSequence()
789 public void setSequence(SequenceI sequence)
791 this.sequence = sequence;
797 * This inner class holds the Layout and configuration of the panel which
798 * handles association of manually fetched structures to a unique sequence
799 * when more than one sequence selection is made
804 public class AssciateSeqPanel extends JPanel implements ItemListener
806 private JComboBox<AssociateSeqOptions> cmb_assSeq = new JComboBox<AssociateSeqOptions>();
808 private JLabel lbl_associateSeq = new JLabel();
810 public AssciateSeqPanel()
812 this.setLayout(new FlowLayout());
813 this.add(cmb_assSeq);
814 this.add(lbl_associateSeq);
815 cmb_assSeq.setToolTipText(
816 MessageManager.getString("info.associate_wit_sequence"));
817 cmb_assSeq.addItemListener(this);
820 public void loadCmbAssSeq()
822 populateCmbAssociateSeqOptions(cmb_assSeq, lbl_associateSeq);
825 public JComboBox<AssociateSeqOptions> getCmb_assSeq()
830 public void setCmb_assSeq(JComboBox<AssociateSeqOptions> cmb_assSeq)
832 this.cmb_assSeq = cmb_assSeq;
836 public void itemStateChanged(ItemEvent e)
838 if (e.getStateChange() == ItemEvent.SELECTED)
840 cmbAssSeqStateChanged();
845 public JTable getResultTable()
850 public JComboBox<FilterOption> getCmbFilterOption()
852 return cmb_filterOption;
856 * Custom ListCellRenderer for adding a separator between different categories
857 * of structure chooser filter option drop-down.
862 public abstract class CustomComboSeparatorsRenderer
863 implements ListCellRenderer<Object>
865 private ListCellRenderer<Object> regent;
867 private JPanel separatorPanel = new JPanel(new BorderLayout());
869 private JSeparator jSeparator = new JSeparator();
871 public CustomComboSeparatorsRenderer(
872 ListCellRenderer<Object> listCellRenderer)
874 this.regent = listCellRenderer;
878 public Component getListCellRendererComponent(JList list, Object value,
879 int index, boolean isSelected, boolean cellHasFocus)
882 Component comp = regent.getListCellRendererComponent(list, value,
883 index, isSelected, cellHasFocus);
885 && addSeparatorAfter(list, (FilterOption) value, index))
887 separatorPanel.removeAll();
888 separatorPanel.add(comp, BorderLayout.CENTER);
889 separatorPanel.add(jSeparator, BorderLayout.SOUTH);
890 return separatorPanel;
898 protected abstract boolean addSeparatorAfter(JList list,
899 FilterOption value, int index);
902 protected abstract void stateChanged(ItemEvent e);
904 protected abstract void ok_ActionPerformed();
906 protected abstract void pdbFromFile_actionPerformed();
908 protected abstract void txt_search_ActionPerformed();
910 public abstract void populateCmbAssociateSeqOptions(
911 JComboBox<AssociateSeqOptions> cmb_assSeq,
912 JLabel lbl_associateSeq);
914 public abstract void cmbAssSeqStateChanged();
916 public abstract void tabRefresh();
918 public abstract void validateSelections();