X-Git-Url: http://source.jalview.org/gitweb/?a=blobdiff_plain;f=src%2Fjalview%2Fgui%2FCalculationChooser.java;h=13506a5edb7217d117c53953fbb01de787b0cbdf;hb=f820a6e0b7ec599b0e040109c3361cdb3e6d9aa0;hp=6f5510ce3d2b62008950019404eed332cc799163;hpb=620d3204a1b556ba249595be908fbc190cf7e1cf;p=jalview.git diff --git a/src/jalview/gui/CalculationChooser.java b/src/jalview/gui/CalculationChooser.java index 6f5510c..13506a5 100644 --- a/src/jalview/gui/CalculationChooser.java +++ b/src/jalview/gui/CalculationChooser.java @@ -25,6 +25,8 @@ import jalview.analysis.scoremodels.ScoreModels; import jalview.analysis.scoremodels.SimilarityParams; import jalview.api.analysis.ScoreModelI; import jalview.api.analysis.SimilarityParamsI; +import jalview.bin.Cache; +import jalview.datamodel.SequenceGroup; import jalview.util.MessageManager; import java.awt.BorderLayout; @@ -60,8 +62,13 @@ import javax.swing.event.InternalFrameAdapter; import javax.swing.event.InternalFrameEvent; /** - * A dialog where a user can choose and action Tree or PCA calculation options + * A dialog where a user can choose and action Tree or PCA calculation options. + * + * Allows also for dialog-free static methods openPCAPanel(...) and + * openTreePanel(...) for scripted use. + * */ +@SuppressWarnings("serial") public class CalculationChooser extends JPanel { /* @@ -72,7 +79,7 @@ public class CalculationChooser extends JPanel */ private static boolean treeMatchGaps = true; - private static final Font VERDANA_11PT = new Font("Verdana", 0, 11); + private static Font VERDANA_11PT; private static final int MIN_TREE_SELECTION = 3; @@ -100,9 +107,45 @@ public class CalculationChooser extends JPanel private JCheckBox shorterSequence; - final ComboBoxTooltipRenderer renderer = new ComboBoxTooltipRenderer(); + private static ComboBoxTooltipRenderer renderer; // BH was not static + + List tips = new ArrayList<>(); + + /* + * the most recently opened PCA results panel + */ + private PCAPanel pcaPanel; + + /** + * Open a new Tree panel on the desktop statically. Params are standard (not + * set by Groovy). No dialog is opened. + * + * @param af + * @param treeType + * @param modelName + * @return null if successful; the string + * "label.you_need_at_least_n_sequences" if number of sequences + * selected is inappropriate + */ + public static Object openTreePanel(AlignFrame af, String treeType, + String modelName) + { + return openTreePanel(af, treeType, modelName, null); + } - List tips = new ArrayList(); + /** + * public static method for JalviewJS API to open a PCAPanel without + * necessarily using a dialog. + * + * @param af + * @param modelName + * @return the PCAPanel, or the string "label.you_need_at_least_n_sequences" + * if number of sequences selected is inappropriate + */ + public static Object openPcaPanel(AlignFrame af, String modelName) + { + return openPcaPanel(af, modelName, null); + } /** * Constructor @@ -149,12 +192,15 @@ public class CalculationChooser extends JPanel pca = new JRadioButton( MessageManager.getString("label.principal_component_analysis")); pca.setOpaque(false); + neighbourJoining = new JRadioButton( MessageManager.getString("label.tree_calc_nj")); neighbourJoining.setSelected(true); + neighbourJoining.setOpaque(false); + averageDistance = new JRadioButton( MessageManager.getString("label.tree_calc_av")); - neighbourJoining.setOpaque(false); + averageDistance.setOpaque(false); JPanel calcChoicePanel = new JPanel(new FlowLayout(FlowLayout.LEFT)); calcChoicePanel.setOpaque(false); @@ -163,14 +209,14 @@ public class CalculationChooser extends JPanel JPanel treePanel = new JPanel(new FlowLayout(FlowLayout.LEFT)); treePanel.setOpaque(false); - treePanel.setBorder(BorderFactory.createTitledBorder(MessageManager - .getString("label.tree"))); + JvSwingUtils.createTitledBorder(treePanel, + MessageManager.getString("label.tree"), true); // then copy the inset dimensions for the border-less PCA panel JPanel pcaBorderless = new JPanel(new FlowLayout(FlowLayout.LEFT)); Insets b = treePanel.getBorder().getBorderInsets(treePanel); - pcaBorderless.setBorder(BorderFactory.createEmptyBorder(2, b.left, 2, - b.right)); + pcaBorderless.setBorder( + BorderFactory.createEmptyBorder(2, b.left, 2, b.right)); pcaBorderless.setOpaque(false); pcaBorderless.add(pca, FlowLayout.LEFT); @@ -185,7 +231,7 @@ public class CalculationChooser extends JPanel calcTypes.add(pca); calcTypes.add(neighbourJoining); calcTypes.add(averageDistance); - + ActionListener calcChanged = new ActionListener() { @Override @@ -222,6 +268,10 @@ public class CalculationChooser extends JPanel paramsPanel.add(includeGappedColumns); paramsPanel.add(shorterSequence); + if (VERDANA_11PT == null) + { + VERDANA_11PT = new Font("Verdana", 0, 11); + } /* * OK / Cancel buttons */ @@ -264,14 +314,12 @@ public class CalculationChooser extends JPanel setMinimumSize(new Dimension(325, height - 10)); String title = MessageManager.getString("label.choose_calculation"); - if (af.getViewport().viewName != null) + if (af.getViewport().getViewName() != null) { - title = title + " (" + af.getViewport().viewName + ")"; + title = title + " (" + af.getViewport().getViewName() + ")"; } - Desktop.addInternalFrame(frame, - title, width, - height, false); + Desktop.addInternalFrame(frame, title, width, height, false); calcChoicePanel.doLayout(); revalidate(); /* @@ -286,6 +334,7 @@ public class CalculationChooser extends JPanel }; }); + validateCalcTypes(); frame.setLayer(JLayeredPane.PALETTE_LAYER); } @@ -336,8 +385,8 @@ public class CalculationChooser extends JPanel */ private boolean checkEnabled(JRadioButton calc, int size, int minsize) { - String ttip = MessageManager.formatMessage( - "label.you_need_at_least_n_sequences", minsize); + String ttip = MessageManager + .formatMessage("label.you_need_at_least_n_sequences", minsize); calc.setEnabled(size >= minsize); if (!calc.isEnabled()) @@ -371,7 +420,11 @@ public class CalculationChooser extends JPanel */ protected JComboBox buildModelOptionsList() { - final JComboBox scoreModelsCombo = new JComboBox(); + JComboBox scoreModelsCombo = new JComboBox<>(); + if (renderer == null) + { + renderer = new ComboBoxTooltipRenderer(); + } scoreModelsCombo.setRenderer(renderer); /* @@ -384,7 +437,8 @@ public class CalculationChooser extends JPanel @Override public void mouseEntered(MouseEvent e) { - scoreModelsCombo.setToolTipText(tips.get(scoreModelsCombo.getSelectedIndex())); + scoreModelsCombo.setToolTipText( + tips.get(scoreModelsCombo.getSelectedIndex())); } @Override @@ -413,39 +467,42 @@ public class CalculationChooser extends JPanel { Object curSel = comboBox.getSelectedItem(); toolTips.clear(); - DefaultComboBoxModel model = new DefaultComboBoxModel(); + DefaultComboBoxModel model = new DefaultComboBoxModel<>(); + + /* + * select the score models applicable to the alignment type + */ + boolean nucleotide = af.getViewport().getAlignment().isNucleotide(); + List models = getApplicableScoreModels(nucleotide, + pca.isSelected()); /* * now we can actually add entries to the combobox, * remembering their descriptions for tooltips */ - ScoreModels scoreModels = ScoreModels.getInstance(); boolean selectedIsPresent = false; - for (ScoreModelI sm : scoreModels.getModels()) + for (ScoreModelI sm : models) { - boolean nucleotide = af.getViewport().getAlignment().isNucleotide(); - if (sm.isDNA() && nucleotide || sm.isProtein() && !nucleotide) + if (curSel != null && sm.getName().equals(curSel)) + { + selectedIsPresent = true; + curSel = sm.getName(); + } + model.addElement(sm.getName()); + + /* + * tooltip is description if provided, else text lookup with + * fallback on the model name + */ + String tooltip = sm.getDescription(); + if (tooltip == null) { - if (curSel != null && sm.getName().equals(curSel)) - { - selectedIsPresent = true; - curSel = sm.getName(); - } - model.addElement(sm.getName()); - - /* - * tooltip is description if provided, else text lookup with - * fallback on the model name - */ - String tooltip = sm.getDescription(); - if (tooltip == null) - { - tooltip = MessageManager.getStringOrReturn("label.score_model_", - sm.getName()); - } - toolTips.add(tooltip); + tooltip = MessageManager.getStringOrReturn("label.score_model_", + sm.getName()); } + toolTips.add(tooltip); } + if (selectedIsPresent) { model.setSelectedItem(curSel); @@ -455,6 +512,48 @@ public class CalculationChooser extends JPanel } /** + * Builds a list of score models which are applicable for the alignment and + * calculation type (peptide or generic models for protein, nucleotide or + * generic models for nucleotide). + *

+ * As a special case, includes BLOSUM62 as an extra option for nucleotide PCA. + * This is for backwards compatibility with Jalview prior to 2.8 when BLOSUM62 + * was the only score matrix supported. This is included if property + * BLOSUM62_PCA_FOR_NUCLEOTIDE is set to true in the Jalview properties file. + * + * @param nucleotide + * @param forPca + * @return + */ + protected static List getApplicableScoreModels( + boolean nucleotide, boolean forPca) + { + List filtered = new ArrayList<>(); + + ScoreModels scoreModels = ScoreModels.getInstance(); + for (ScoreModelI sm : scoreModels.getModels()) + { + if (!nucleotide && sm.isProtein() || nucleotide && sm.isDNA()) + { + filtered.add(sm); + } + } + + /* + * special case: add BLOSUM62 as last option for nucleotide PCA, + * for backwards compatibility with Jalview < 2.8 (JAL-2962) + */ + if (nucleotide && forPca + && Cache.getDefault(Preferences.BLOSUM62_PCA_FOR_NUCLEOTIDE, + false)) + { + filtered.add(scoreModels.getBlosum62()); + } + + return filtered; + } + + /** * Open and calculate the selected tree or PCA on 'OK' */ protected void calculate_actionPerformed() @@ -483,57 +582,123 @@ public class CalculationChooser extends JPanel */ protected void openTreePanel(String modelName, SimilarityParamsI params) { + Object ret = openTreePanel(af, + neighbourJoining.isSelected() ? TreeBuilder.NEIGHBOUR_JOINING + : TreeBuilder.AVERAGE_DISTANCE, + modelName, params); + if (ret instanceof String) + { + JvOptionPane.showMessageDialog(this, // was opening on Desktop? + MessageManager.formatMessage( + (String) ret, + MIN_TREE_SELECTION), + MessageManager.getString("label.not_enough_sequences"), + JvOptionPane.WARNING_MESSAGE); + + } + } + + /** + * Open a new PCA panel on the desktop + * + * @param modelName + * @param params + */ + protected void openPcaPanel(String modelName, SimilarityParamsI params) + { + Object ret = openPcaPanel(af, modelName, params); + if (ret instanceof String) + { + JvOptionPane.showInternalMessageDialog(this, + MessageManager.formatMessage( + (String) ret, + MIN_PCA_SELECTION), + MessageManager + .getString("label.sequence_selection_insufficient"), + JvOptionPane.WARNING_MESSAGE); + } + else + { + // only used for test suite + pcaPanel = (PCAPanel) ret; + } + + } + + /** + * Open a new Tree panel on the desktop statically + * + * @param af + * @param treeType + * @param modelName + * @param params + * @return null, or the string "label.you_need_at_least_n_sequences" if number + * of sequences selected is inappropriate + */ + public static Object openTreePanel(AlignFrame af, String treeType, + String modelName, SimilarityParamsI params) + { + /* * gui validation shouldn't allow insufficient sequences here, but leave * this check in in case this method gets exposed programmatically in future */ AlignViewport viewport = af.getViewport(); - if (viewport.getSelectionGroup().getSize() < MIN_TREE_SELECTION) + SequenceGroup sg = viewport.getSelectionGroup(); + if (sg != null && sg.getSize() < MIN_TREE_SELECTION) { - JvOptionPane - .showMessageDialog( - Desktop.desktop, - MessageManager - .formatMessage("label.you_need_at_least_n_sequences", - MIN_TREE_SELECTION), - MessageManager - .getString("label.not_enough_sequences"), - JvOptionPane.WARNING_MESSAGE); - return; + return "label.you_need_at_least_n_sequences"; + } + + if (params == null) + { + params = getSimilarityParameters(false); } - String treeType = neighbourJoining.isSelected() ? TreeBuilder.NEIGHBOUR_JOINING - : TreeBuilder.AVERAGE_DISTANCE; af.newTreePanel(treeType, modelName, params); + return null; } /** - * Open a new PCA panel on the desktop + * public static method for JalviewJS API * + * @param af * @param modelName * @param params + * @return the PCAPanel, or null if number of sequences selected is + * inappropriate */ - protected void openPcaPanel(String modelName, SimilarityParamsI params) + public static Object openPcaPanel(AlignFrame af, String modelName, + SimilarityParamsI params) { + AlignViewport viewport = af.getViewport(); /* * gui validation shouldn't allow insufficient sequences here, but leave * this check in in case this method gets exposed programmatically in future + * + * */ if (((viewport.getSelectionGroup() != null) - && (viewport.getSelectionGroup().getSize() < MIN_PCA_SELECTION) && (viewport - .getSelectionGroup().getSize() > 0)) + && (viewport.getSelectionGroup().getSize() < MIN_PCA_SELECTION) + && (viewport.getSelectionGroup().getSize() > 0)) || (viewport.getAlignment().getHeight() < MIN_PCA_SELECTION)) { - JvOptionPane.showInternalMessageDialog(this, MessageManager - .formatMessage("label.you_need_at_least_n_sequences", - MIN_PCA_SELECTION), MessageManager - .getString("label.sequence_selection_insufficient"), - JvOptionPane.WARNING_MESSAGE); - return; + return "label.you_need_at_least_n_sequences"; } - new PCAPanel(af.alignPanel, modelName, params); + + if (params == null) + { + params = getSimilarityParameters(true); + } + + /* + * construct the panel and kick off its calculation thread + */ + PCAPanel pcap = new PCAPanel(af.alignPanel, modelName, params); + new Thread(pcap).start(); + return pcap; } /** @@ -549,6 +714,7 @@ public class CalculationChooser extends JPanel } } + /** * Returns a data bean holding parameters for similarity (or distance) model * calculation @@ -556,7 +722,8 @@ public class CalculationChooser extends JPanel * @param doPCA * @return */ - protected SimilarityParamsI getSimilarityParameters(boolean doPCA) + public static SimilarityParamsI getSimilarityParameters( + boolean doPCA) { // commented out: parameter choices read from gui widgets // SimilarityParamsI params = new SimilarityParams( @@ -575,7 +742,9 @@ public class CalculationChooser extends JPanel */ boolean matchGap = doPCA ? false : treeMatchGaps; - return new SimilarityParams(includeGapGap, matchGap, includeGapResidue, matchOnShortestLength); + return new SimilarityParams(includeGapGap, matchGap, includeGapResidue, + matchOnShortestLength); + } /** @@ -590,4 +759,10 @@ public class CalculationChooser extends JPanel { } } + + public PCAPanel getPcaPanel() + { + // only called for FreeUpMemoryTest + return pcaPanel; + } }