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
79 public abstract class GStructureChooser extends JPanel implements
82 protected JPanel statusPanel = new JPanel();
84 public JLabel statusBar = new JLabel();
86 private JPanel pnl_actionsAndStatus = new JPanel(new BorderLayout());
88 protected String frameTitle = MessageManager
89 .getString("label.structure_chooser");
91 protected JInternalFrame mainFrame = new JInternalFrame(frameTitle);
93 protected JComboBox<FilterOption> cmb_filterOption = new JComboBox<FilterOption>();
95 protected AlignmentPanel ap;
97 protected StringBuilder errorWarning = new StringBuilder();
99 protected JLabel lbl_result = new JLabel(
100 MessageManager.getString("label.select"));
102 protected JButton btn_view = new JButton();
104 protected JButton btn_cancel = new JButton();
106 protected JButton btn_pdbFromFile = new JButton();
108 protected JTextField txt_search = new JTextField(14);
110 private JPanel pnl_actions = new JPanel();
112 private JPanel pnl_main = new JPanel();
114 private JPanel pnl_idInput = new JPanel(new FlowLayout());
116 private JPanel pnl_fileChooser = new JPanel(new FlowLayout());
118 private JPanel pnl_idInputBL = new JPanel(new BorderLayout());
120 private JPanel pnl_fileChooserBL = new JPanel(new BorderLayout());
122 private JPanel pnl_locPDB = new JPanel(new BorderLayout());
124 protected JPanel pnl_switchableViews = new JPanel(new CardLayout());
126 protected CardLayout layout_switchableViews = (CardLayout) (pnl_switchableViews
129 private BorderLayout mainLayout = new BorderLayout();
131 protected JCheckBox chk_rememberSettings = new JCheckBox(
132 MessageManager.getString("label.dont_ask_me_again"));
134 protected JCheckBox chk_invertFilter = new JCheckBox(
135 MessageManager.getString("label.invert"));
137 protected ImageIcon loadingImage = new ImageIcon(getClass().getResource(
138 "/images/loading.gif"));
140 protected ImageIcon goodImage = new ImageIcon(getClass().getResource(
141 "/images/good.png"));
143 protected ImageIcon errorImage = new ImageIcon(getClass().getResource(
144 "/images/error.png"));
146 protected ImageIcon warningImage = new ImageIcon(getClass().getResource(
147 "/images/warning.gif"));
149 protected JLabel lbl_warning = new JLabel(warningImage);
151 protected JLabel lbl_loading = new JLabel(loadingImage);
153 protected JLabel lbl_pdbManualFetchStatus = new JLabel(errorImage);
155 protected JLabel lbl_fromFileStatus = new JLabel(errorImage);
157 protected AssciateSeqPanel idInputAssSeqPanel = new AssciateSeqPanel();
159 protected AssciateSeqPanel fileChooserAssSeqPanel = new AssciateSeqPanel();
161 protected static final String VIEWS_FILTER = "VIEWS_FILTER";
163 protected static final String VIEWS_FROM_FILE = "VIEWS_FROM_FILE";
165 protected static final String VIEWS_ENTER_ID = "VIEWS_ENTER_ID";
167 protected static final String VIEWS_LOCAL_PDB = "VIEWS_LOCAL_PDB";
169 protected JTable tbl_local_pdb = new JTable();
171 protected JScrollPane scrl_localPDB = new JScrollPane(tbl_local_pdb);
173 protected JTabbedPane pnl_filter = new JTabbedPane();
175 protected FTSDataColumnPreferences pdbDocFieldPrefs = new FTSDataColumnPreferences(
176 PreferenceSource.STRUCTURE_CHOOSER,
177 PDBFTSRestClient.getInstance());
179 protected FTSDataColumnI[] previousWantedFields;
181 protected static Map<String, Integer> tempUserPrefs = new HashMap<String, Integer>();
183 private JTable tbl_summary = new JTable()
185 private boolean inLayout;
188 public boolean getScrollableTracksViewportWidth()
190 return hasExcessWidth();
195 public void doLayout()
197 if (hasExcessWidth())
199 autoResizeMode = AUTO_RESIZE_SUBSEQUENT_COLUMNS;
204 autoResizeMode = AUTO_RESIZE_OFF;
207 protected boolean hasExcessWidth()
209 return getPreferredSize().width < getParent().getWidth();
213 public void columnMarginChanged(ChangeEvent e)
219 TableColumn resizingColumn = getTableHeader().getResizingColumn();
220 // Need to do this here, before the parent's
221 // layout manager calls getPreferredSize().
222 if (resizingColumn != null && autoResizeMode == AUTO_RESIZE_OFF
225 resizingColumn.setPreferredWidth(resizingColumn.getWidth());
226 String colHeader = resizingColumn.getHeaderValue().toString();
227 tempUserPrefs.put(colHeader, resizingColumn.getWidth());
233 public String getToolTipText(MouseEvent evt)
235 String toolTipText = null;
236 java.awt.Point pnt = evt.getPoint();
237 int rowIndex = rowAtPoint(pnt);
238 int colIndex = columnAtPoint(pnt);
242 if (getValueAt(rowIndex, colIndex) == null)
246 toolTipText = getValueAt(rowIndex, colIndex).toString();
247 } catch (Exception e)
249 // e.printStackTrace();
251 toolTipText = (toolTipText == null ? null
252 : (toolTipText.length() > 500 ? JvSwingUtils.wrapTooltip(
253 true, "\"" + toolTipText.subSequence(0, 500)
254 + "...\"") : JvSwingUtils.wrapTooltip(true,
260 protected JScrollPane scrl_foundStructures = new JScrollPane(tbl_summary);
262 public GStructureChooser()
267 mainFrame.setVisible(false);
268 mainFrame.invalidate();
270 } catch (Exception e)
277 * Initializes the GUI default properties
281 private void jbInit() throws Exception
283 Integer width = tempUserPrefs.get("structureChooser.width") == null ? 800
284 : tempUserPrefs.get("structureChooser.width");
285 Integer height = tempUserPrefs.get("structureChooser.height") == null ? 400
286 : tempUserPrefs.get("structureChooser.height");
287 tbl_summary.setAutoCreateRowSorter(true);
288 tbl_summary.getTableHeader().setReorderingAllowed(false);
289 tbl_summary.addMouseListener(new MouseAdapter()
292 public void mouseClicked(MouseEvent e)
294 validateSelections();
298 public void mouseReleased(MouseEvent e)
300 validateSelections();
303 tbl_summary.addKeyListener(new KeyAdapter()
306 public void keyPressed(KeyEvent evt)
308 validateSelections();
309 switch (evt.getKeyCode())
311 case KeyEvent.VK_ESCAPE: // escape key
314 case KeyEvent.VK_ENTER: // enter key
315 if (btn_view.isEnabled())
317 ok_ActionPerformed();
320 case KeyEvent.VK_TAB: // tab key
321 if (evt.isShiftDown())
323 pnl_filter.requestFocus();
327 btn_view.requestFocus();
336 tbl_local_pdb.setAutoCreateRowSorter(true);
337 tbl_local_pdb.getTableHeader().setReorderingAllowed(false);
338 tbl_local_pdb.addMouseListener(new MouseAdapter()
341 public void mouseClicked(MouseEvent e)
343 validateSelections();
347 public void mouseReleased(MouseEvent e)
349 validateSelections();
352 tbl_local_pdb.addKeyListener(new KeyAdapter()
355 public void keyPressed(KeyEvent evt)
357 validateSelections();
358 switch (evt.getKeyCode())
360 case KeyEvent.VK_ESCAPE: // escape key
363 case KeyEvent.VK_ENTER: // enter key
364 if (btn_view.isEnabled())
366 ok_ActionPerformed();
369 case KeyEvent.VK_TAB: // tab key
370 if (evt.isShiftDown())
372 cmb_filterOption.requestFocus();
376 if (btn_view.isEnabled())
378 btn_view.requestFocus();
382 btn_cancel.requestFocus();
392 btn_view.setFont(new java.awt.Font("Verdana", 0, 12));
393 btn_view.setText(MessageManager.getString("action.view"));
394 btn_view.addActionListener(new java.awt.event.ActionListener()
397 public void actionPerformed(ActionEvent e)
399 ok_ActionPerformed();
402 btn_view.addKeyListener(new KeyAdapter()
405 public void keyPressed(KeyEvent evt)
407 if (evt.getKeyCode() == KeyEvent.VK_ENTER)
409 ok_ActionPerformed();
414 btn_cancel.setFont(new java.awt.Font("Verdana", 0, 12));
415 btn_cancel.setText(MessageManager.getString("action.cancel"));
416 btn_cancel.addActionListener(new java.awt.event.ActionListener()
419 public void actionPerformed(ActionEvent e)
421 closeAction(pnl_filter.getHeight());
424 btn_cancel.addKeyListener(new KeyAdapter()
427 public void keyPressed(KeyEvent evt)
429 if (evt.getKeyCode() == KeyEvent.VK_ENTER)
431 closeAction(pnl_filter.getHeight());
436 btn_pdbFromFile.setFont(new java.awt.Font("Verdana", 0, 12));
437 String btn_title = MessageManager.getString("label.select_pdb_file");
438 btn_pdbFromFile.setText(btn_title + " ");
439 btn_pdbFromFile.addActionListener(new java.awt.event.ActionListener()
442 public void actionPerformed(ActionEvent e)
444 pdbFromFile_actionPerformed();
447 btn_pdbFromFile.addKeyListener(new KeyAdapter()
450 public void keyPressed(KeyEvent evt)
452 if (evt.getKeyCode() == KeyEvent.VK_ENTER)
454 pdbFromFile_actionPerformed();
459 scrl_foundStructures.setPreferredSize(new Dimension(width, height));
461 scrl_localPDB.setPreferredSize(new Dimension(width, height));
463 .setHorizontalScrollBarPolicy(JScrollPane.HORIZONTAL_SCROLLBAR_NEVER);
465 cmb_filterOption.setFont(new java.awt.Font("Verdana", 0, 12));
466 chk_invertFilter.setFont(new java.awt.Font("Verdana", 0, 12));
467 chk_rememberSettings.setFont(new java.awt.Font("Verdana", 0, 12));
468 chk_rememberSettings.setVisible(false);
469 txt_search.setToolTipText(JvSwingUtils.wrapTooltip(true,
470 MessageManager.getString("label.enter_pdb_id")));
471 cmb_filterOption.setToolTipText(MessageManager
472 .getString("info.select_filter_option"));
473 txt_search.getDocument().addDocumentListener(new DocumentListener()
476 public void insertUpdate(DocumentEvent e)
478 txt_search_ActionPerformed();
482 public void removeUpdate(DocumentEvent e)
484 txt_search_ActionPerformed();
488 public void changedUpdate(DocumentEvent e)
490 txt_search_ActionPerformed();
494 cmb_filterOption.addItemListener(this);
496 // add CustomComboSeparatorsRenderer to filter option combo-box
497 cmb_filterOption.setRenderer(new CustomComboSeparatorsRenderer(
498 (ListCellRenderer<Object>) cmb_filterOption.getRenderer())
501 protected boolean addSeparatorAfter(JList list, FilterOption value,
504 return value.isAddSeparatorAfter();
508 chk_invertFilter.addItemListener(this);
510 pnl_actions.add(chk_rememberSettings);
511 pnl_actions.add(btn_view);
512 pnl_actions.add(btn_cancel);
514 // pnl_filter.add(lbl_result);
515 pnl_main.add(cmb_filterOption);
516 pnl_main.add(lbl_loading);
517 pnl_main.add(chk_invertFilter);
518 lbl_loading.setVisible(false);
520 pnl_fileChooser.add(btn_pdbFromFile);
521 pnl_fileChooser.add(lbl_fromFileStatus);
522 pnl_fileChooserBL.add(fileChooserAssSeqPanel, BorderLayout.NORTH);
523 pnl_fileChooserBL.add(pnl_fileChooser, BorderLayout.CENTER);
525 pnl_idInput.add(txt_search);
526 pnl_idInput.add(lbl_pdbManualFetchStatus);
527 pnl_idInputBL.add(idInputAssSeqPanel, BorderLayout.NORTH);
528 pnl_idInputBL.add(pnl_idInput, BorderLayout.CENTER);
530 final String foundStructureSummary = MessageManager
531 .getString("label.found_structures_summary");
532 final String configureCols = MessageManager
533 .getString("label.configure_displayed_columns");
534 ChangeListener changeListener = new ChangeListener()
537 public void stateChanged(ChangeEvent changeEvent)
539 JTabbedPane sourceTabbedPane = (JTabbedPane) changeEvent
541 int index = sourceTabbedPane.getSelectedIndex();
542 btn_view.setVisible(true);
543 btn_cancel.setVisible(true);
544 if (sourceTabbedPane.getTitleAt(index).equals(configureCols))
546 btn_view.setEnabled(false);
547 btn_cancel.setEnabled(false);
548 btn_view.setVisible(false);
549 btn_cancel.setVisible(false);
550 previousWantedFields = pdbDocFieldPrefs
551 .getStructureSummaryFields().toArray(
552 new FTSDataColumnI[0]);
554 if (sourceTabbedPane.getTitleAt(index)
555 .equals(foundStructureSummary))
557 btn_cancel.setEnabled(true);
558 if (wantedFieldsUpdated())
564 validateSelections();
569 pnl_filter.addChangeListener(changeListener);
570 pnl_filter.setPreferredSize(new Dimension(width, height));
571 pnl_filter.add(foundStructureSummary, scrl_foundStructures);
572 pnl_filter.add(configureCols, pdbDocFieldPrefs);
574 pnl_locPDB.add(scrl_localPDB);
576 pnl_switchableViews.add(pnl_fileChooserBL, VIEWS_FROM_FILE);
577 pnl_switchableViews.add(pnl_idInputBL, VIEWS_ENTER_ID);
578 pnl_switchableViews.add(pnl_filter, VIEWS_FILTER);
579 pnl_switchableViews.add(pnl_locPDB, VIEWS_LOCAL_PDB);
581 this.setLayout(mainLayout);
582 this.add(pnl_main, java.awt.BorderLayout.NORTH);
583 this.add(pnl_switchableViews, java.awt.BorderLayout.CENTER);
584 // this.add(pnl_actions, java.awt.BorderLayout.SOUTH);
585 statusPanel.setLayout(new GridLayout());
586 pnl_actionsAndStatus.add(pnl_actions, BorderLayout.CENTER);
587 pnl_actionsAndStatus.add(statusPanel, BorderLayout.SOUTH);
588 statusPanel.add(statusBar, null);
589 this.add(pnl_actionsAndStatus, java.awt.BorderLayout.SOUTH);
592 .addInternalFrameListener(new javax.swing.event.InternalFrameAdapter()
595 public void internalFrameClosing(InternalFrameEvent e)
597 closeAction(pnl_filter.getHeight());
600 mainFrame.setVisible(true);
601 mainFrame.setContentPane(this);
602 mainFrame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
603 Integer x = tempUserPrefs.get("structureChooser.x");
604 Integer y = tempUserPrefs.get("structureChooser.y");
605 if (x != null && y != null)
607 mainFrame.setLocation(x, y);
609 Desktop.addInternalFrame(mainFrame, frameTitle, width, height);
612 protected void closeAction(int preferredHeight)
614 // System.out.println(">>>>>>>>>> closing internal frame!!!");
615 // System.out.println("width : " + mainFrame.getWidth());
616 // System.out.println("heigh : " + mainFrame.getHeight());
617 // System.out.println("x : " + mainFrame.getX());
618 // System.out.println("y : " + mainFrame.getY());
619 tempUserPrefs.put("structureChooser.width", pnl_filter.getWidth());
620 tempUserPrefs.put("structureChooser.height", preferredHeight);
621 tempUserPrefs.put("structureChooser.x", mainFrame.getX());
622 tempUserPrefs.put("structureChooser.y", mainFrame.getY());
626 public boolean wantedFieldsUpdated()
628 if (previousWantedFields == null)
633 FTSDataColumnI[] currentWantedFields = pdbDocFieldPrefs
634 .getStructureSummaryFields().toArray(new FTSDataColumnI[0]);
635 return Arrays.equals(currentWantedFields, previousWantedFields) ? false
642 * Event listener for the 'filter' combo-box and 'invert' check-box
644 public void itemStateChanged(ItemEvent e)
650 * This inner class provides the data model for the structure filter combo-box
655 public class FilterOption
659 private String value;
663 private boolean addSeparatorAfter;
666 * Model for structure filter option
669 * - the name of the Option
671 * - the value of the option
673 * - the category of the filter option
674 * @param addSeparatorAfter
675 * - if true, a horizontal separator is rendered immediately after
676 * this filter option, otherwise
678 public FilterOption(String name, String value, String view,
679 boolean addSeparatorAfter)
684 this.addSeparatorAfter = addSeparatorAfter;
687 public String getName()
692 public void setName(String name)
697 public String getValue()
702 public void setValue(String value)
707 public String getView()
712 public void setView(String view)
718 public String toString()
723 public boolean isAddSeparatorAfter()
725 return addSeparatorAfter;
728 public void setAddSeparatorAfter(boolean addSeparatorAfter)
730 this.addSeparatorAfter = addSeparatorAfter;
735 * This inner class provides the provides the data model for associate
736 * sequence combo-box - cmb_assSeq
741 public class AssociateSeqOptions
743 private SequenceI sequence;
747 public AssociateSeqOptions(SequenceI seq)
750 this.name = (seq.getName().length() >= 23) ? seq.getName().substring(
751 0, 23) : seq.getName();
754 public AssociateSeqOptions(String name, SequenceI seq)
761 public String toString()
766 public String getName()
771 public void setName(String name)
776 public SequenceI getSequence()
781 public void setSequence(SequenceI sequence)
783 this.sequence = sequence;
789 * This inner class holds the Layout and configuration of the panel which
790 * handles association of manually fetched structures to a unique sequence
791 * when more than one sequence selection is made
796 public class AssciateSeqPanel extends JPanel implements ItemListener
798 private JComboBox<AssociateSeqOptions> cmb_assSeq = new JComboBox<AssociateSeqOptions>();
800 private JLabel lbl_associateSeq = new JLabel();
802 public AssciateSeqPanel()
804 this.setLayout(new FlowLayout());
805 this.add(cmb_assSeq);
806 this.add(lbl_associateSeq);
807 cmb_assSeq.setToolTipText(MessageManager
808 .getString("info.associate_wit_sequence"));
809 cmb_assSeq.addItemListener(this);
812 public void loadCmbAssSeq()
814 populateCmbAssociateSeqOptions(cmb_assSeq, lbl_associateSeq);
817 public JComboBox<AssociateSeqOptions> getCmb_assSeq()
822 public void setCmb_assSeq(JComboBox<AssociateSeqOptions> cmb_assSeq)
824 this.cmb_assSeq = cmb_assSeq;
828 public void itemStateChanged(ItemEvent e)
830 if (e.getStateChange() == ItemEvent.SELECTED)
832 cmbAssSeqStateChanged();
837 public JTable getResultTable()
842 public JComboBox<FilterOption> getCmbFilterOption()
844 return cmb_filterOption;
848 * Custom ListCellRenderer for adding a separator between different categories
849 * of structure chooser filter option drop-down.
854 public abstract class CustomComboSeparatorsRenderer implements
855 ListCellRenderer<Object>
857 private ListCellRenderer<Object> regent;
859 private JPanel separatorPanel = new JPanel(new BorderLayout());
861 private JSeparator jSeparator = new JSeparator();
863 public CustomComboSeparatorsRenderer(ListCellRenderer<Object> listCellRenderer)
865 this.regent = listCellRenderer;
869 public Component getListCellRendererComponent(JList list,
871 int index, boolean isSelected, boolean cellHasFocus)
874 Component comp = regent.getListCellRendererComponent(list, value,
875 index, isSelected, cellHasFocus);
877 && addSeparatorAfter(list, (FilterOption) value, index))
879 separatorPanel.removeAll();
880 separatorPanel.add(comp, BorderLayout.CENTER);
881 separatorPanel.add(jSeparator, BorderLayout.SOUTH);
882 return separatorPanel;
890 protected abstract boolean addSeparatorAfter(JList list,
895 protected abstract void stateChanged(ItemEvent e);
897 protected abstract void ok_ActionPerformed();
899 protected abstract void pdbFromFile_actionPerformed();
901 protected abstract void txt_search_ActionPerformed();
903 public abstract void populateCmbAssociateSeqOptions(
904 JComboBox<AssociateSeqOptions> cmb_assSeq, JLabel lbl_associateSeq);
906 public abstract void cmbAssSeqStateChanged();
908 public abstract void tabRefresh();
910 public abstract void validateSelections();