X-Git-Url: http://source.jalview.org/gitweb/?a=blobdiff_plain;f=src%2Fjalview%2Fgui%2FFeatureSettings.java;h=b49593a1697a2842b036a8a55d02a6a02c3cc905;hb=006890b02106eb31841e6e84d75f1027434823e0;hp=5aa9499c209c59089820124a63ad09bb02811498;hpb=20fde02b6f6f28396595d8a3b90fb48783da0b9e;p=jalview.git diff --git a/src/jalview/gui/FeatureSettings.java b/src/jalview/gui/FeatureSettings.java index 5aa9499..b49593a 100644 --- a/src/jalview/gui/FeatureSettings.java +++ b/src/jalview/gui/FeatureSettings.java @@ -20,30 +20,6 @@ */ package jalview.gui; -import jalview.api.AlignViewportI; -import jalview.api.FeatureColourI; -import jalview.api.FeatureSettingsControllerI; -import jalview.api.ViewStyleI; -import jalview.datamodel.AlignmentI; -import jalview.datamodel.SequenceI; -import jalview.datamodel.features.FeatureMatcher; -import jalview.datamodel.features.FeatureMatcherI; -import jalview.datamodel.features.FeatureMatcherSet; -import jalview.datamodel.features.FeatureMatcherSetI; -import jalview.gui.Help.HelpId; -import jalview.gui.JalviewColourChooser.ColourChooserListener; -import jalview.io.JalviewFileChooser; -import jalview.io.JalviewFileView; -import jalview.schemes.FeatureColour; -import jalview.util.MessageManager; -import jalview.util.Platform; -import jalview.viewmodel.seqfeatures.FeatureRendererModel.FeatureSettingsBean; -import jalview.viewmodel.styles.ViewStyle; -import jalview.xml.binding.jalview.JalviewUserColours; -import jalview.xml.binding.jalview.JalviewUserColours.Colour; -import jalview.xml.binding.jalview.JalviewUserColours.Filter; -import jalview.xml.binding.jalview.ObjectFactory; - import java.awt.BorderLayout; import java.awt.Color; import java.awt.Component; @@ -112,8 +88,35 @@ import javax.xml.bind.Marshaller; import javax.xml.stream.XMLInputFactory; import javax.xml.stream.XMLStreamReader; +import jalview.api.AlignViewControllerGuiI; +import jalview.api.AlignViewportI; +import jalview.api.FeatureColourI; +import jalview.api.FeatureSettingsControllerI; +import jalview.api.SplitContainerI; +import jalview.api.ViewStyleI; +import jalview.controller.FeatureSettingsControllerGuiI; +import jalview.datamodel.AlignmentI; +import jalview.datamodel.SequenceI; +import jalview.datamodel.features.FeatureMatcher; +import jalview.datamodel.features.FeatureMatcherI; +import jalview.datamodel.features.FeatureMatcherSet; +import jalview.datamodel.features.FeatureMatcherSetI; +import jalview.gui.Help.HelpId; +import jalview.gui.JalviewColourChooser.ColourChooserListener; +import jalview.io.JalviewFileChooser; +import jalview.io.JalviewFileView; +import jalview.schemes.FeatureColour; +import jalview.util.MessageManager; +import jalview.util.Platform; +import jalview.viewmodel.seqfeatures.FeatureRendererModel.FeatureSettingsBean; +import jalview.viewmodel.styles.ViewStyle; +import jalview.xml.binding.jalview.JalviewUserColours; +import jalview.xml.binding.jalview.JalviewUserColours.Colour; +import jalview.xml.binding.jalview.JalviewUserColours.Filter; +import jalview.xml.binding.jalview.ObjectFactory; + public class FeatureSettings extends JPanel - implements FeatureSettingsControllerI + implements FeatureSettingsControllerI, FeatureSettingsControllerGuiI { private static final String SEQUENCE_FEATURE_COLOURS = MessageManager .getString("label.sequence_feature_colours"); @@ -163,6 +166,10 @@ public class FeatureSettings extends JPanel JSlider transparency = new JSlider(); + private JCheckBox showComplementOnTop; + + private JCheckBox showComplement; + /* * when true, constructor is still executing - so ignore UI events */ @@ -178,10 +185,36 @@ public class FeatureSettings extends JPanel boolean handlingUpdate = false; /* + * a change listener to ensure the dialog is updated if + * FeatureRenderer discovers new features + */ + private PropertyChangeListener change; + + /* * holds {featureCount, totalExtent} for each feature type */ Map typeWidth = null; + private void storeOriginalSettings() + { + // save transparency for restore on Cancel + originalTransparency = fr.getTransparency(); + + updateTransparencySliderFromFR(); + + originalFilters = new HashMap<>(fr.getFeatureFilters()); // shallow copy + originalViewStyle = new ViewStyle(af.viewport.getViewStyle()); + } + + private void updateTransparencySliderFromFR() + { + boolean incon = inConstruction; + inConstruction = true; + + int transparencyAsPercent = (int) (fr.getTransparency() * 100); + transparency.setValue(100 - transparencyAsPercent); + inConstruction = incon; + } /** * Constructor * @@ -192,13 +225,7 @@ public class FeatureSettings extends JPanel this.af = alignFrame; fr = af.getFeatureRenderer(); - // save transparency for restore on Cancel - originalTransparency = fr.getTransparency(); - int originalTransparencyAsPercent = (int) (originalTransparency * 100); - transparency.setMaximum(100 - originalTransparencyAsPercent); - - originalFilters = new HashMap<>(fr.getFeatureFilters()); // shallow copy - originalViewStyle = new ViewStyle(af.viewport.getViewStyle()); + storeOriginalSettings(); try { @@ -356,7 +383,6 @@ public class FeatureSettings extends JPanel } discoverAllFeatureData(); - final PropertyChangeListener change; final FeatureSettings fs = this; fr.addPropertyChangeListener(change = new PropertyChangeListener() { @@ -374,38 +400,98 @@ public class FeatureSettings extends JPanel }); - frame = new JInternalFrame(); - frame.setContentPane(this); - Desktop.addInternalFrame(frame, - MessageManager.getString("label.sequence_feature_settings"), - 600, Platform.isAMacAndNotJS() ? 480 : 450); - frame.setMinimumSize(new Dimension(MIN_WIDTH, MIN_HEIGHT)); + SplitContainerI splitframe = af.getSplitViewContainer(); + if (splitframe != null) + { + frame = null; // keeps eclipse happy + splitframe.addFeatureSettingsUI(this); + } + else + { + frame = new JInternalFrame(); + frame.setContentPane(this); + Rectangle bounds = af.getFeatureSettingsGeometry(); + String title; + if (af.getAlignPanels().size() > 1 || Desktop.getAlignmentPanels( + af.alignPanel.av.getSequenceSetId()).length > 1) + { + title = MessageManager.formatMessage( + "label.sequence_feature_settings_for_view", + af.alignPanel.getViewName()); + } + else + { + title = MessageManager.getString("label.sequence_feature_settings"); + } + if (bounds == null) + { + if (Platform.isAMacAndNotJS()) + { + Desktop.addInternalFrame(frame, title, 600, 480); + } + else + { + Desktop.addInternalFrame(frame, title, 600, 450); + } + } + else + { + Desktop.addInternalFrame(frame, title, false, bounds.width, + bounds.height); + frame.setBounds(bounds); + frame.setVisible(true); + } + frame.setMinimumSize(new Dimension(MIN_WIDTH, MIN_HEIGHT)); - frame.addInternalFrameListener( - new javax.swing.event.InternalFrameAdapter() - { - @Override - public void internalFrameClosed( - javax.swing.event.InternalFrameEvent evt) + frame.addInternalFrameListener( + new javax.swing.event.InternalFrameAdapter() { - fr.removePropertyChangeListener(change); - } - }); - frame.setLayer(JLayeredPane.PALETTE_LAYER); - inConstruction = false; - } + @Override + public void internalFrameClosed( + javax.swing.event.InternalFrameEvent evt) + { + featureSettings_isClosed(); + }; + }); + frame.setLayer(JLayeredPane.PALETTE_LAYER); + } + inConstruction = false; + } /** - * Constructs and shows a popup menu of possible actions on the selected row - * and feature type - * - * @param rowSelected - * @param type - * @param typeCol - * @param pt + * Sets the state of buttons to show complement features from viewport + * settings */ - protected void showPopupMenu(final int rowSelected, final String type, - final Object typeCol, final Point pt) + private void updateComplementButtons() + { + showComplement.setSelected(af.getViewport().isShowComplementFeatures()); + showComplementOnTop + .setSelected(af.getViewport().isShowComplementFeaturesOnTop()); + } + + @Override + public AlignViewControllerGuiI getAlignframe() + { + return af; + } + + @Override + public void featureSettings_isClosed() + { + fr.removePropertyChangeListener(change); + change = null; + } + + /** + * Constructs and shows a popup menu of possible actions on the selected row and + * feature type + * + * @param rowSelected + * @param type + * @param typeCol + * @param pt + */ + protected void showPopupMenu(final int rowSelected, final String type, final Object typeCol, final Point pt) { JPopupMenu men = new JPopupMenu(MessageManager .formatMessage("label.settings_for_param", new String[] @@ -431,10 +517,9 @@ public class FeatureSettings extends JPanel { if (e.getSource() == variableColourCB) { - men.setVisible(true); // BH 2018 for JavaScript because this is a - // checkbox - men.setVisible(false); // BH 2018 for JavaScript because this is a - // checkbox + // BH 2018 for JavaScript because this is a checkbox + men.setVisible(true); + men.setVisible(false); if (featureColour.isSimpleColour()) { /* @@ -492,24 +577,20 @@ public class FeatureSettings extends JPanel men.add(scr); scr.addActionListener(new ActionListener() { - @Override public void actionPerformed(ActionEvent e) { - af.avc.sortAlignmentByFeatureScore(Arrays.asList(new String[] - { type })); + sortByScore(Arrays.asList(new String[] { type })); } }); JMenuItem dens = new JMenuItem( MessageManager.getString("label.sort_by_density")); dens.addActionListener(new ActionListener() { - @Override public void actionPerformed(ActionEvent e) { - af.avc.sortAlignmentByFeatureDensity(Arrays.asList(new String[] - { type })); + sortByDensity(Arrays.asList(new String[] { type })); } }); men.add(dens); @@ -567,6 +648,47 @@ public class FeatureSettings extends JPanel men.show(table, pt.x, pt.y); } + /** + * Sort the sequences in the alignment by the number of features for the given + * feature types (or all features if null) + * + * @param featureTypes + */ + protected void sortByDensity(List featureTypes) + { + af.avc.sortAlignmentByFeatureDensity(featureTypes); + } + + /** + * Sort the sequences in the alignment by average score for the given feature + * types (or all features if null) + * + * @param featureTypes + */ + protected void sortByScore(List featureTypes) + { + af.avc.sortAlignmentByFeatureScore(featureTypes); + } + + /** + * Returns true if at least one feature type is visible. Else shows a warning + * dialog and returns false. + * + * @param title + * @return + */ + private boolean canSortBy(String title) + { + if (fr.getDisplayedFeatureTypes().isEmpty()) + { + JvOptionPane.showMessageDialog(this, + MessageManager.getString("label.no_features_to_sort_by"), + title, JvOptionPane.OK_OPTION); + return false; + } + return true; + } + @Override synchronized public void discoverAllFeatureData() { @@ -1151,11 +1273,38 @@ public class FeatureSettings extends JPanel table.repaint(); } + /** + * close ourselves but leave any existing UI handlers (e.g a CDS/Protein tabbed + * feature settings dialog) intact + */ + public void closeOldSettings() + { + closeDialog(false); + } + + /** + * close the feature settings dialog (and any containing frame) + */ public void close() { + closeDialog(true); + } + + private void closeDialog(boolean closeContainingFrame) + { try { - frame.setClosed(true); + if (frame != null) + { + af.setFeatureSettingsGeometry(frame.getBounds()); + frame.setClosed(true); + } + else + { + SplitContainerI sc = af.getSplitViewContainer(); + sc.closeFeatureSettings(this, closeContainingFrame); + af.featureSettings = null; + } } catch (Exception exe) { } @@ -1206,6 +1355,9 @@ public class FeatureSettings extends JPanel { this.setLayout(new BorderLayout()); + final boolean hasComplement = af.getViewport() + .getCodingComplement() != null; + JPanel settingsPane = new JPanel(); settingsPane.setLayout(new BorderLayout()); @@ -1239,26 +1391,32 @@ public class FeatureSettings extends JPanel } }); - JButton sortByScore = new JButton( - MessageManager.getString("label.seq_sort_by_score")); + final String byScoreLabel = MessageManager.getString("label.seq_sort_by_score"); + JButton sortByScore = new JButton(byScoreLabel); sortByScore.setFont(JvSwingUtils.getLabelFont()); sortByScore.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { - af.avc.sortAlignmentByFeatureScore(null); + if (canSortBy(byScoreLabel)) + { + sortByScore(null); + } } }); - JButton sortByDens = new JButton( - MessageManager.getString("label.sequence_sort_by_density")); + final String byDensityLabel = MessageManager.getString("label.sequence_sort_by_density"); + JButton sortByDens = new JButton(byDensityLabel); sortByDens.setFont(JvSwingUtils.getLabelFont()); sortByDens.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { - af.avc.sortAlignmentByFeatureDensity(null); + if (canSortBy(byDensityLabel)) + { + sortByDensity(null); + } } }); @@ -1278,30 +1436,48 @@ public class FeatureSettings extends JPanel } } }); - - JButton cancel = new JButton(MessageManager.getString("action.cancel")); + // Cancel for a SplitFrame should just revert changes to the currently displayed + // settings. May want to do this for either or both - so need a splitview + // feature settings cancel/OK. + JButton cancel = new JButton(MessageManager + .getString(hasComplement ? "action.revert" : "action.cancel")); + cancel.setToolTipText(MessageManager.getString(hasComplement + ? "action.undo_changes_to_feature_settings" + : "action.undo_changes_to_feature_settings_and_close_the_dialog")); cancel.setFont(JvSwingUtils.getLabelFont()); + // TODO: disable cancel (and apply!) until current settings are different cancel.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { - fr.setTransparency(originalTransparency); - fr.setFeatureFilters(originalFilters); - updateFeatureRenderer(originalData); - af.getViewport().setViewStyle(originalViewStyle); - close(); + revert(); + refreshDisplay(); + if (!hasComplement) + { + close(); + } } }); - - JButton ok = new JButton(MessageManager.getString("action.ok")); + // Cancel for the whole dialog should cancel both CDS and Protein. + // OK for an individual feature settings just applies changes, but dialog + // remains open + JButton ok = new JButton(MessageManager + .getString(hasComplement ? "action.apply" : "action.ok")); ok.setFont(JvSwingUtils.getLabelFont()); ok.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { - close(); + if (!hasComplement) + { + close(); + } + else + { + storeOriginalSettings(); + } } }); @@ -1355,8 +1531,7 @@ public class FeatureSettings extends JPanel ? MessageManager.getString("label.protein") .toLowerCase() : "CDS"); - JCheckBox showComplement = new JCheckBox(text); - showComplement.setSelected(af.getViewport().isShowComplementFeatures()); + showComplement = new JCheckBox(text); showComplement.addActionListener(new ActionListener() { @Override @@ -1368,10 +1543,8 @@ public class FeatureSettings extends JPanel } }); - JCheckBox showComplementOnTop = new JCheckBox( + showComplementOnTop = new JCheckBox( MessageManager.getString("label.on_top")); - showComplementOnTop - .setSelected(af.getViewport().isShowComplementFeaturesOnTop()); showComplementOnTop.addActionListener(new ActionListener() { @Override @@ -1383,6 +1556,8 @@ public class FeatureSettings extends JPanel } }); + updateComplementButtons(); + JPanel lowerPanel = new JPanel(new GridLayout(1, 2)); bigPanel.add(lowerPanel, BorderLayout.SOUTH); @@ -1393,9 +1568,8 @@ public class FeatureSettings extends JPanel transbuttons.add(sortByDens); transbuttons.add(help); - boolean hasComplement = af.getViewport().getCodingComplement() != null; JPanel transPanelLeft = new JPanel( - new GridLayout(hasComplement ? 3 : 2, 1)); + new GridLayout(hasComplement ? 4 : 2, 1)); transPanelLeft.add(new JLabel(" Colour transparency" + ":")); transPanelLeft.add(transparency); if (hasComplement) @@ -1992,6 +2166,27 @@ public class FeatureSettings extends JPanel return button; } } + + public boolean isOpen() + { + if (af.getSplitViewContainer() != null) + { + return af.getSplitViewContainer().isFeatureSettingsOpen(); + } + return frame != null && !frame.isClosed(); + } + + @Override + public void revert() + { + fr.setTransparency(originalTransparency); + fr.setFeatureFilters(originalFilters); + updateFeatureRenderer(originalData); + af.getViewport().setViewStyle(originalViewStyle); + updateTransparencySliderFromFR(); + updateComplementButtons(); + refreshDisplay(); + } } class FeatureIcon implements Icon