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";
168 protected static final String VIEWS_LOCAL_PDB = "VIEWS_LOCAL_PDB";
170 protected JTable tbl_local_pdb = new JTable();
172 protected JScrollPane scrl_localPDB = new JScrollPane(tbl_local_pdb);
174 protected JTabbedPane pnl_filter = new JTabbedPane();
176 protected FTSDataColumnPreferences pdbDocFieldPrefs = new FTSDataColumnPreferences(
177 PreferenceSource.STRUCTURE_CHOOSER,
178 PDBFTSRestClient.getInstance());
180 protected FTSDataColumnI[] previousWantedFields;
182 protected static Map<String, Integer> tempUserPrefs = new HashMap<String, Integer>();
184 private JTable tbl_summary = new JTable()
186 private boolean inLayout;
189 public boolean getScrollableTracksViewportWidth()
191 return hasExcessWidth();
196 public void doLayout()
198 if (hasExcessWidth())
200 autoResizeMode = AUTO_RESIZE_SUBSEQUENT_COLUMNS;
205 autoResizeMode = AUTO_RESIZE_OFF;
208 protected boolean hasExcessWidth()
210 return getPreferredSize().width < getParent().getWidth();
214 public void columnMarginChanged(ChangeEvent e)
220 TableColumn resizingColumn = getTableHeader().getResizingColumn();
221 // Need to do this here, before the parent's
222 // layout manager calls getPreferredSize().
223 if (resizingColumn != null && autoResizeMode == AUTO_RESIZE_OFF
226 resizingColumn.setPreferredWidth(resizingColumn.getWidth());
227 String colHeader = resizingColumn.getHeaderValue().toString();
228 tempUserPrefs.put(colHeader, resizingColumn.getWidth());
234 public String getToolTipText(MouseEvent evt)
236 String toolTipText = null;
237 java.awt.Point pnt = evt.getPoint();
238 int rowIndex = rowAtPoint(pnt);
239 int colIndex = columnAtPoint(pnt);
243 if (getValueAt(rowIndex, colIndex) == null)
247 toolTipText = getValueAt(rowIndex, colIndex).toString();
248 } catch (Exception e)
250 // e.printStackTrace();
252 toolTipText = (toolTipText == null ? null
253 : (toolTipText.length() > 500
254 ? JvSwingUtils.wrapTooltip(true,
255 "\"" + toolTipText.subSequence(0, 500)
257 : JvSwingUtils.wrapTooltip(true, toolTipText)));
262 protected JScrollPane scrl_foundStructures = new JScrollPane(tbl_summary);
264 public GStructureChooser()
269 mainFrame.setVisible(false);
270 mainFrame.invalidate();
272 } catch (Exception e)
279 * Initializes the GUI default properties
283 private void jbInit() throws Exception
285 Integer width = tempUserPrefs.get("structureChooser.width") == null
287 : tempUserPrefs.get("structureChooser.width");
288 Integer height = tempUserPrefs.get("structureChooser.height") == null
290 : tempUserPrefs.get("structureChooser.height");
291 tbl_summary.setAutoCreateRowSorter(true);
292 tbl_summary.getTableHeader().setReorderingAllowed(false);
293 tbl_summary.addMouseListener(new MouseAdapter()
296 public void mouseClicked(MouseEvent e)
298 validateSelections();
302 public void mouseReleased(MouseEvent e)
304 validateSelections();
307 tbl_summary.addKeyListener(new KeyAdapter()
310 public void keyPressed(KeyEvent evt)
312 validateSelections();
313 switch (evt.getKeyCode())
315 case KeyEvent.VK_ESCAPE: // escape key
318 case KeyEvent.VK_ENTER: // enter key
319 if (btn_view.isEnabled())
321 ok_ActionPerformed();
324 case KeyEvent.VK_TAB: // tab key
325 if (evt.isShiftDown())
327 pnl_filter.requestFocus();
331 btn_view.requestFocus();
340 tbl_local_pdb.setAutoCreateRowSorter(true);
341 tbl_local_pdb.getTableHeader().setReorderingAllowed(false);
342 tbl_local_pdb.addMouseListener(new MouseAdapter()
345 public void mouseClicked(MouseEvent e)
347 validateSelections();
351 public void mouseReleased(MouseEvent e)
353 validateSelections();
356 tbl_local_pdb.addKeyListener(new KeyAdapter()
359 public void keyPressed(KeyEvent evt)
361 validateSelections();
362 switch (evt.getKeyCode())
364 case KeyEvent.VK_ESCAPE: // escape key
367 case KeyEvent.VK_ENTER: // enter key
368 if (btn_view.isEnabled())
370 ok_ActionPerformed();
373 case KeyEvent.VK_TAB: // tab key
374 if (evt.isShiftDown())
376 cmb_filterOption.requestFocus();
380 if (btn_view.isEnabled())
382 btn_view.requestFocus();
386 btn_cancel.requestFocus();
396 btn_view.setFont(new java.awt.Font("Verdana", 0, 12));
397 btn_view.setText(MessageManager.getString("action.view"));
398 btn_view.addActionListener(new java.awt.event.ActionListener()
401 public void actionPerformed(ActionEvent e)
403 ok_ActionPerformed();
406 btn_view.addKeyListener(new KeyAdapter()
409 public void keyPressed(KeyEvent evt)
411 if (evt.getKeyCode() == KeyEvent.VK_ENTER)
413 ok_ActionPerformed();
418 btn_cancel.setFont(new java.awt.Font("Verdana", 0, 12));
419 btn_cancel.setText(MessageManager.getString("action.cancel"));
420 btn_cancel.addActionListener(new java.awt.event.ActionListener()
423 public void actionPerformed(ActionEvent e)
425 closeAction(pnl_filter.getHeight());
428 btn_cancel.addKeyListener(new KeyAdapter()
431 public void keyPressed(KeyEvent evt)
433 if (evt.getKeyCode() == KeyEvent.VK_ENTER)
435 closeAction(pnl_filter.getHeight());
440 btn_pdbFromFile.setFont(new java.awt.Font("Verdana", 0, 12));
441 String btn_title = MessageManager.getString("label.select_pdb_file");
442 btn_pdbFromFile.setText(btn_title + " ");
443 btn_pdbFromFile.addActionListener(new java.awt.event.ActionListener()
446 public void actionPerformed(ActionEvent e)
448 pdbFromFile_actionPerformed();
451 btn_pdbFromFile.addKeyListener(new KeyAdapter()
454 public void keyPressed(KeyEvent evt)
456 if (evt.getKeyCode() == KeyEvent.VK_ENTER)
458 pdbFromFile_actionPerformed();
463 scrl_foundStructures.setPreferredSize(new Dimension(width, height));
465 scrl_localPDB.setPreferredSize(new Dimension(width, height));
466 scrl_localPDB.setHorizontalScrollBarPolicy(
467 JScrollPane.HORIZONTAL_SCROLLBAR_NEVER);
469 cmb_filterOption.setFont(new java.awt.Font("Verdana", 0, 12));
470 chk_invertFilter.setFont(new java.awt.Font("Verdana", 0, 12));
471 chk_rememberSettings.setFont(new java.awt.Font("Verdana", 0, 12));
472 chk_rememberSettings.setVisible(false);
473 txt_search.setToolTipText(JvSwingUtils.wrapTooltip(true,
474 MessageManager.getString("label.enter_pdb_id")));
475 cmb_filterOption.setToolTipText(
476 MessageManager.getString("info.select_filter_option"));
477 txt_search.getDocument().addDocumentListener(new DocumentListener()
480 public void insertUpdate(DocumentEvent e)
482 txt_search_ActionPerformed();
486 public void removeUpdate(DocumentEvent e)
488 txt_search_ActionPerformed();
492 public void changedUpdate(DocumentEvent e)
494 txt_search_ActionPerformed();
498 cmb_filterOption.addItemListener(this);
500 // add CustomComboSeparatorsRenderer to filter option combo-box
501 cmb_filterOption.setRenderer(new CustomComboSeparatorsRenderer(
502 (ListCellRenderer<Object>) cmb_filterOption.getRenderer())
505 protected boolean addSeparatorAfter(JList list, FilterOption value,
508 return value.isAddSeparatorAfter();
512 chk_invertFilter.addItemListener(this);
514 pnl_actions.add(chk_rememberSettings);
515 pnl_actions.add(btn_view);
516 pnl_actions.add(btn_cancel);
518 // pnl_filter.add(lbl_result);
519 pnl_main.add(cmb_filterOption);
520 pnl_main.add(lbl_loading);
521 pnl_main.add(chk_invertFilter);
522 lbl_loading.setVisible(false);
524 pnl_fileChooser.add(btn_pdbFromFile);
525 pnl_fileChooser.add(lbl_fromFileStatus);
526 pnl_fileChooserBL.add(fileChooserAssSeqPanel, BorderLayout.NORTH);
527 pnl_fileChooserBL.add(pnl_fileChooser, BorderLayout.CENTER);
529 pnl_idInput.add(txt_search);
530 pnl_idInput.add(lbl_pdbManualFetchStatus);
531 pnl_idInputBL.add(idInputAssSeqPanel, BorderLayout.NORTH);
532 pnl_idInputBL.add(pnl_idInput, BorderLayout.CENTER);
534 final String foundStructureSummary = MessageManager
535 .getString("label.found_structures_summary");
536 final String configureCols = MessageManager
537 .getString("label.configure_displayed_columns");
538 ChangeListener changeListener = new ChangeListener()
541 public void stateChanged(ChangeEvent changeEvent)
543 JTabbedPane sourceTabbedPane = (JTabbedPane) changeEvent
545 int index = sourceTabbedPane.getSelectedIndex();
546 btn_view.setVisible(true);
547 btn_cancel.setVisible(true);
548 if (sourceTabbedPane.getTitleAt(index).equals(configureCols))
550 btn_view.setEnabled(false);
551 btn_cancel.setEnabled(false);
552 btn_view.setVisible(false);
553 btn_cancel.setVisible(false);
554 previousWantedFields = pdbDocFieldPrefs
555 .getStructureSummaryFields()
556 .toArray(new FTSDataColumnI[0]);
558 if (sourceTabbedPane.getTitleAt(index)
559 .equals(foundStructureSummary))
561 btn_cancel.setEnabled(true);
562 if (wantedFieldsUpdated())
568 validateSelections();
573 pnl_filter.addChangeListener(changeListener);
574 pnl_filter.setPreferredSize(new Dimension(width, height));
575 pnl_filter.add(foundStructureSummary, scrl_foundStructures);
576 pnl_filter.add(configureCols, pdbDocFieldPrefs);
578 pnl_locPDB.add(scrl_localPDB);
580 pnl_switchableViews.add(pnl_fileChooserBL, VIEWS_FROM_FILE);
581 pnl_switchableViews.add(pnl_idInputBL, VIEWS_ENTER_ID);
582 pnl_switchableViews.add(pnl_filter, VIEWS_FILTER);
583 pnl_switchableViews.add(pnl_locPDB, VIEWS_LOCAL_PDB);
585 this.setLayout(mainLayout);
586 this.add(pnl_main, java.awt.BorderLayout.NORTH);
587 this.add(pnl_switchableViews, java.awt.BorderLayout.CENTER);
588 // this.add(pnl_actions, java.awt.BorderLayout.SOUTH);
589 statusPanel.setLayout(new GridLayout());
590 pnl_actionsAndStatus.add(pnl_actions, BorderLayout.CENTER);
591 pnl_actionsAndStatus.add(statusPanel, BorderLayout.SOUTH);
592 statusPanel.add(statusBar, null);
593 this.add(pnl_actionsAndStatus, java.awt.BorderLayout.SOUTH);
595 mainFrame.addInternalFrameListener(
596 new javax.swing.event.InternalFrameAdapter()
599 public void internalFrameClosing(InternalFrameEvent e)
601 closeAction(pnl_filter.getHeight());
604 mainFrame.setVisible(true);
605 mainFrame.setContentPane(this);
606 mainFrame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
607 Integer x = tempUserPrefs.get("structureChooser.x");
608 Integer y = tempUserPrefs.get("structureChooser.y");
609 if (x != null && y != null)
611 mainFrame.setLocation(x, y);
613 Desktop.addInternalFrame(mainFrame, frameTitle, width, height);
616 protected void closeAction(int preferredHeight)
618 // System.out.println(">>>>>>>>>> closing internal frame!!!");
619 // System.out.println("width : " + mainFrame.getWidth());
620 // System.out.println("heigh : " + mainFrame.getHeight());
621 // System.out.println("x : " + mainFrame.getX());
622 // System.out.println("y : " + mainFrame.getY());
623 tempUserPrefs.put("structureChooser.width", pnl_filter.getWidth());
624 tempUserPrefs.put("structureChooser.height", preferredHeight);
625 tempUserPrefs.put("structureChooser.x", mainFrame.getX());
626 tempUserPrefs.put("structureChooser.y", mainFrame.getY());
630 public boolean wantedFieldsUpdated()
632 if (previousWantedFields == null)
637 FTSDataColumnI[] currentWantedFields = pdbDocFieldPrefs
638 .getStructureSummaryFields().toArray(new FTSDataColumnI[0]);
639 return Arrays.equals(currentWantedFields, previousWantedFields) ? false
646 * Event listener for the 'filter' combo-box and 'invert' check-box
648 public void itemStateChanged(ItemEvent e)
654 * This inner class provides the data model for the structure filter combo-box
659 public class FilterOption
663 private String value;
667 private boolean addSeparatorAfter;
670 * Model for structure filter option
673 * - the name of the Option
675 * - the value of the option
677 * - the category of the filter option
678 * @param addSeparatorAfter
679 * - if true, a horizontal separator is rendered immediately after
680 * this filter option, otherwise
682 public FilterOption(String name, String value, String view,
683 boolean addSeparatorAfter)
688 this.addSeparatorAfter = addSeparatorAfter;
691 public String getName()
696 public void setName(String name)
701 public String getValue()
706 public void setValue(String value)
711 public String getView()
716 public void setView(String view)
722 public String toString()
727 public boolean isAddSeparatorAfter()
729 return addSeparatorAfter;
732 public void setAddSeparatorAfter(boolean addSeparatorAfter)
734 this.addSeparatorAfter = addSeparatorAfter;
739 * This inner class provides the provides the data model for associate
740 * sequence combo-box - cmb_assSeq
745 public class AssociateSeqOptions
747 private SequenceI sequence;
751 public AssociateSeqOptions(SequenceI seq)
754 this.name = (seq.getName().length() >= 23)
755 ? seq.getName().substring(0, 23)
759 public AssociateSeqOptions(String name, SequenceI seq)
766 public String toString()
771 public String getName()
776 public void setName(String name)
781 public SequenceI getSequence()
786 public void setSequence(SequenceI sequence)
788 this.sequence = sequence;
794 * This inner class holds the Layout and configuration of the panel which
795 * handles association of manually fetched structures to a unique sequence
796 * when more than one sequence selection is made
801 public class AssciateSeqPanel extends JPanel implements ItemListener
803 private JComboBox<AssociateSeqOptions> cmb_assSeq = new JComboBox<AssociateSeqOptions>();
805 private JLabel lbl_associateSeq = new JLabel();
807 public AssciateSeqPanel()
809 this.setLayout(new FlowLayout());
810 this.add(cmb_assSeq);
811 this.add(lbl_associateSeq);
812 cmb_assSeq.setToolTipText(
813 MessageManager.getString("info.associate_wit_sequence"));
814 cmb_assSeq.addItemListener(this);
817 public void loadCmbAssSeq()
819 populateCmbAssociateSeqOptions(cmb_assSeq, lbl_associateSeq);
822 public JComboBox<AssociateSeqOptions> getCmb_assSeq()
827 public void setCmb_assSeq(JComboBox<AssociateSeqOptions> cmb_assSeq)
829 this.cmb_assSeq = cmb_assSeq;
833 public void itemStateChanged(ItemEvent e)
835 if (e.getStateChange() == ItemEvent.SELECTED)
837 cmbAssSeqStateChanged();
842 public JTable getResultTable()
847 public JComboBox<FilterOption> getCmbFilterOption()
849 return cmb_filterOption;
853 * Custom ListCellRenderer for adding a separator between different categories
854 * of structure chooser filter option drop-down.
859 public abstract class CustomComboSeparatorsRenderer
860 implements ListCellRenderer<Object>
862 private ListCellRenderer<Object> regent;
864 private JPanel separatorPanel = new JPanel(new BorderLayout());
866 private JSeparator jSeparator = new JSeparator();
868 public CustomComboSeparatorsRenderer(
869 ListCellRenderer<Object> listCellRenderer)
871 this.regent = listCellRenderer;
875 public Component getListCellRendererComponent(JList list, Object value,
876 int index, boolean isSelected, boolean cellHasFocus)
879 Component comp = regent.getListCellRendererComponent(list, value,
880 index, isSelected, cellHasFocus);
882 && addSeparatorAfter(list, (FilterOption) value, index))
884 separatorPanel.removeAll();
885 separatorPanel.add(comp, BorderLayout.CENTER);
886 separatorPanel.add(jSeparator, BorderLayout.SOUTH);
887 return separatorPanel;
895 protected abstract boolean addSeparatorAfter(JList list,
896 FilterOption value, int index);
899 protected abstract void stateChanged(ItemEvent e);
901 protected abstract void ok_ActionPerformed();
903 protected abstract void pdbFromFile_actionPerformed();
905 protected abstract void txt_search_ActionPerformed();
907 public abstract void populateCmbAssociateSeqOptions(
908 JComboBox<AssociateSeqOptions> cmb_assSeq,
909 JLabel lbl_associateSeq);
911 public abstract void cmbAssSeqStateChanged();
913 public abstract void tabRefresh();
915 public abstract void validateSelections();