From 19e044a2ce25aa395f9cf22f15c7378221636d21 Mon Sep 17 00:00:00 2001 From: gmungoc Date: Fri, 5 May 2017 16:14:36 +0100 Subject: [PATCH] JAL-964 JAL-2510 update Feature Settings from Amend Features, warn if hidden type or group --- resources/lang/Messages.properties | 3 +- resources/lang/Messages_es.properties | 1 + src/jalview/appletgui/FeatureRenderer.java | 94 +++++++++++++--- src/jalview/appletgui/FeatureSettings.java | 105 +++++++++++------- src/jalview/gui/FeatureRenderer.java | 112 ++++++++++++++++---- src/jalview/gui/FeatureSettings.java | 57 ++++++---- .../seqfeatures/FeatureRendererModel.java | 16 ++- 7 files changed, 292 insertions(+), 96 deletions(-) diff --git a/resources/lang/Messages.properties b/resources/lang/Messages.properties index e63752d..198430e 100644 --- a/resources/lang/Messages.properties +++ b/resources/lang/Messages.properties @@ -1307,4 +1307,5 @@ label.conservation_descr = Conservation of total alignment less than {0}% gaps label.consensus_descr = PID label.complement_consensus_descr = PID for cDNA label.strucconsensus_descr = PID for base pairs -label.occupancy_descr = Number of aligned positions \ No newline at end of file +label.occupancy_descr = Number of aligned positions +label.warning_hidden = Warning: {0} {1} is currently hidden \ No newline at end of file diff --git a/resources/lang/Messages_es.properties b/resources/lang/Messages_es.properties index 6ddbb44..96a775d 100644 --- a/resources/lang/Messages_es.properties +++ b/resources/lang/Messages_es.properties @@ -1301,3 +1301,4 @@ warn.name_cannot_be_duplicate = Los nombres URL definidos por el usuario deben s label.invalid_name = Nombre inválido ! label.output_seq_details = Seleccionar Detalles de la secuencia para ver todas label.urllinks = Enlaces +label.warning_hidden = Advertencia: {0} {1} está actualmente oculto \ No newline at end of file diff --git a/src/jalview/appletgui/FeatureRenderer.java b/src/jalview/appletgui/FeatureRenderer.java index be027ec..2db2cab 100644 --- a/src/jalview/appletgui/FeatureRenderer.java +++ b/src/jalview/appletgui/FeatureRenderer.java @@ -36,7 +36,9 @@ import java.awt.Button; import java.awt.Choice; import java.awt.Color; import java.awt.Dimension; +import java.awt.FlowLayout; import java.awt.Font; +import java.awt.Frame; import java.awt.Graphics; import java.awt.GridLayout; import java.awt.Label; @@ -48,6 +50,8 @@ import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.awt.event.MouseAdapter; import java.awt.event.MouseEvent; +import java.awt.event.TextEvent; +import java.awt.event.TextListener; import java.util.Hashtable; /** @@ -180,9 +184,9 @@ public class FeatureRenderer extends final SequenceFeature[] features, boolean create, final AlignmentPanel ap, String featureType) { - Panel bigPanel = new Panel(new BorderLayout()); + final Panel bigPanel = new Panel(new BorderLayout()); final TextField name = new TextField(16); - final TextField source = new TextField(16); + final TextField group = new TextField(16); final TextArea description = new TextArea(3, 35); final TextField start = new TextField(8); final TextField end = new TextField(8); @@ -190,6 +194,22 @@ public class FeatureRenderer extends Button deleteButton = new Button("Delete"); deleteFeature = false; + name.addTextListener(new TextListener() + { + @Override + public void textValueChanged(TextEvent e) + { + warnIfTypeHidden(ap.alignFrame, name.getText()); + } + }); + group.addTextListener(new TextListener() + { + @Override + public void textValueChanged(TextEvent e) + { + warnIfGroupHidden(ap.alignFrame, group.getText()); + } + }); colourPanel = new FeatureColourPanel(); colourPanel.setSize(110, 15); final FeatureRenderer fr = this; @@ -233,7 +253,7 @@ public class FeatureRenderer extends featureIndex = index; name.setText(features[index].getType()); description.setText(features[index].getDescription()); - source.setText(features[index].getFeatureGroup()); + group.setText(features[index].getFeatureGroup()); start.setText(features[index].getBegin() + ""); end.setText(features[index].getEnd() + ""); @@ -269,7 +289,7 @@ public class FeatureRenderer extends tmp = new Panel(); panel.add(tmp); tmp.add(new Label(MessageManager.getString("label.group:"), Label.RIGHT)); - tmp.add(source); + tmp.add(group); tmp = new Panel(); panel.add(tmp); @@ -345,7 +365,7 @@ public class FeatureRenderer extends if (create) { name.setText(lastFeatureAdded); - source.setText(lastFeatureGroupAdded); + group.setText(lastFeatureGroupAdded); } else { @@ -361,7 +381,7 @@ public class FeatureRenderer extends } }); name.setText(features[0].getType()); - source.setText(features[0].getFeatureGroup()); + group.setText(features[0].getFeatureGroup()); } start.setText(features[0].getBegin() + ""); @@ -396,7 +416,7 @@ public class FeatureRenderer extends if (dialog.accept) { lastFeatureAdded = name.getText().trim(); - lastFeatureGroupAdded = source.getText().trim(); + lastFeatureGroupAdded = group.getText().trim(); lastDescriptionAdded = description.getText().replace('\n', ' '); } @@ -411,6 +431,8 @@ public class FeatureRenderer extends SequenceFeature sf = features[featureIndex]; if (dialog.accept) { + boolean typeOrGroupChanged = (!lastFeatureAdded.equals(sf.type) || !lastFeatureGroupAdded + .equals(sf.featureGroup)); sf.type = lastFeatureAdded; sf.featureGroup = lastFeatureGroupAdded; sf.description = lastDescriptionAdded; @@ -428,17 +450,24 @@ public class FeatureRenderer extends } ffile.parseDescriptionHTML(sf, false); - setVisible(lastFeatureAdded); // if user edited name then make sure new - // type is visible + if (typeOrGroupChanged) + { + featuresAdded(); + } } if (deleteFeature) { sequences[0].deleteFeature(sf); + // ensure Feature Settings reflects removal of feature / group + featuresAdded(); } } else { + /* + * adding feature(s) + */ if (dialog.accept && name.getText().length() > 0) { for (int i = 0; i < sequences.length; i++) @@ -453,14 +482,8 @@ public class FeatureRenderer extends Color newColour = colourPanel.getBackground(); // setColour(lastFeatureAdded, fcol); - if (lastFeatureGroupAdded != null) - { - setGroupVisibility(lastFeatureGroupAdded, true); - } setColour(lastFeatureAdded, new FeatureColour(newColour)); // was fcol - setVisible(lastFeatureAdded); - findAllFeatures(false); // different to original applet behaviour ? - // findAllFeatures(); + featuresAdded(); } else { @@ -479,4 +502,43 @@ public class FeatureRenderer extends return true; } + + protected void warnIfGroupHidden(Frame frame, String group) + { + if (featureGroups.containsKey(group) && !featureGroups.get(group)) + { + String msg = MessageManager.formatMessage("label.warning_hidden", + MessageManager.getString("label.group"), group); + showWarning(frame, msg); + } + } + + protected void warnIfTypeHidden(Frame frame, String type) + { + if (getRenderOrder().contains(type)) + { + if (!showFeatureOfType(type)) + { + String msg = MessageManager.formatMessage("label.warning_hidden", + MessageManager.getString("label.feature_type"), type); + showWarning(frame, msg); + } + } + } + + /** + * @param frame + * @param msg + */ + protected void showWarning(Frame frame, String msg) + { + JVDialog d = new JVDialog(frame, "", true, 350, 200); + Panel mp = new Panel(); + d.ok.setLabel(MessageManager.getString("action.ok")); + d.cancel.setVisible(false); + mp.setLayout(new FlowLayout()); + mp.add(new Label(msg)); + d.setMainPanel(mp); + d.setVisible(true); + } } diff --git a/src/jalview/appletgui/FeatureSettings.java b/src/jalview/appletgui/FeatureSettings.java index 1b9fbf9..9d2f601 100755 --- a/src/jalview/appletgui/FeatureSettings.java +++ b/src/jalview/appletgui/FeatureSettings.java @@ -58,8 +58,10 @@ import java.awt.event.WindowAdapter; import java.awt.event.WindowEvent; import java.util.Arrays; import java.util.Enumeration; +import java.util.HashSet; import java.util.List; import java.util.Map; +import java.util.Set; import java.util.Vector; public class FeatureSettings extends Panel implements ItemListener, @@ -106,6 +108,7 @@ public class FeatureSettings extends Panel implements ItemListener, { fr.findAllFeatures(true); // was default - now true to make all visible } + groupPanel = new Panel(); discoverAllFeatureData(); @@ -133,17 +136,15 @@ public class FeatureSettings extends Panel implements ItemListener, add(lowerPanel, BorderLayout.SOUTH); - if (groupPanel != null) - { - groupPanel.setLayout(new GridLayout( - (fr.getFeatureGroupsSize()) / 4 + 1, 4)); // JBPNote - this was - // scaled on number of - // visible groups. seems - // broken - groupPanel.validate(); + groupPanel.setLayout(new GridLayout( + (fr.getFeatureGroupsSize()) / 4 + 1, 4)); // JBPNote - this was + // scaled on number of + // visible groups. seems + // broken + groupPanel.validate(); + + add(groupPanel, BorderLayout.NORTH); - add(groupPanel, BorderLayout.NORTH); - } frame = new Frame(); frame.add(this); final FeatureSettings me = this; @@ -326,44 +327,43 @@ public class FeatureSettings extends Panel implements ItemListener, if (fr.getAllFeatureColours() != null && fr.getAllFeatureColours().size() > 0) { - rebuildGroups(); + // rebuildGroups(); } resetTable(false); } /** - * rebuilds the group panel + * Answers the visibility of the given group, and adds a checkbox for it if + * there is not one already */ - public void rebuildGroups() + public boolean checkGroupState(String group) { - boolean rdrw = false; - if (groupPanel == null) - { - groupPanel = new Panel(); - } - else - { - rdrw = true; - groupPanel.removeAll(); - } - // TODO: JAL-964 - smoothly incorporate new group entries if panel already - // displayed and new groups present - for (String group : fr.getFeatureGroups()) - { - boolean vis = fr.checkGroupVisibility(group, false); - Checkbox check = new MyCheckbox(group, vis, false); - check.addMouseListener(this); - check.setFont(new Font("Serif", Font.BOLD, 12)); - check.addItemListener(groupItemListener); - // note - visibility seems to correlate with displayed. ???wtf ?? - check.setVisible(vis); - groupPanel.add(check); - } - if (rdrw) + boolean visible = fr.checkGroupVisibility(group, true); + + /* + * is there already a checkbox for this group? + */ + for (int g = 0; g < groupPanel.getComponentCount(); g++) { - groupPanel.validate(); + if (((Checkbox) groupPanel.getComponent(g)).getLabel().equals(group)) + { + ((Checkbox) groupPanel.getComponent(g)).setState(visible); + return visible; + } } + + /* + * add a new checkbox + */ + Checkbox check = new MyCheckbox(group, visible, false); + check.addMouseListener(this); + check.setFont(new Font("Serif", Font.BOLD, 12)); + check.addItemListener(groupItemListener); + groupPanel.add(check); + + groupPanel.validate(); + return visible; } // This routine adds and removes checkboxes depending on @@ -373,7 +373,9 @@ public class FeatureSettings extends Panel implements ItemListener, SequenceFeature[] tmpfeatures; String group = null, type; Vector visibleChecks = new Vector(); + Set foundGroups = new HashSet(); AlignmentI alignment = av.getAlignment(); + for (int i = 0; i < alignment.getHeight(); i++) { if (alignment.getSequenceAt(i).getSequenceFeatures() == null) @@ -386,8 +388,9 @@ public class FeatureSettings extends Panel implements ItemListener, while (index < tmpfeatures.length) { group = tmpfeatures[index].featureGroup; + foundGroups.add(group); - if (group == null || fr.checkGroupVisibility(group, true)) + if (group == null || checkGroupState(group)) { type = tmpfeatures[index].getType(); if (!visibleChecks.contains(type)) @@ -399,6 +402,11 @@ public class FeatureSettings extends Panel implements ItemListener, } } + /* + * remove any checkboxes for groups not present + */ + pruneGroups(foundGroups); + Component[] comps; int cSize = featurePanel.getComponentCount(); MyCheckbox check; @@ -458,6 +466,25 @@ public class FeatureSettings extends Panel implements ItemListener, } /** + * Remove from the groups panel any checkboxes for groups that are not in the + * foundGroups set. This enables removing a group from the display when the + * last feature in that group is deleted. + * + * @param foundGroups + */ + protected void pruneGroups(Set foundGroups) + { + for (int g = 0; g < groupPanel.getComponentCount(); g++) + { + Checkbox checkbox = (Checkbox) groupPanel.getComponent(g); + if (!foundGroups.contains(checkbox.getLabel())) + { + groupPanel.remove(checkbox); + } + } + } + + /** * update the checklist of feature types with the given type * * @param groupsChanged diff --git a/src/jalview/gui/FeatureRenderer.java b/src/jalview/gui/FeatureRenderer.java index 50a8689..7be3e51 100644 --- a/src/jalview/gui/FeatureRenderer.java +++ b/src/jalview/gui/FeatureRenderer.java @@ -54,6 +54,8 @@ import javax.swing.JSpinner; import javax.swing.JTextArea; import javax.swing.JTextField; import javax.swing.SwingConstants; +import javax.swing.event.DocumentEvent; +import javax.swing.event.DocumentListener; /** * DOCUMENT ME! @@ -131,8 +133,51 @@ public class FeatureRenderer extends featureIndex = 0; final JPanel mainPanel = new JPanel(new BorderLayout()); + final JTextField name = new JTextField(25); - final JTextField source = new JTextField(25); + name.getDocument().addDocumentListener(new DocumentListener() + { + @Override + public void insertUpdate(DocumentEvent e) + { + warnIfTypeHidden(mainPanel, name.getText()); + } + + @Override + public void removeUpdate(DocumentEvent e) + { + warnIfTypeHidden(mainPanel, name.getText()); + } + + @Override + public void changedUpdate(DocumentEvent e) + { + warnIfTypeHidden(mainPanel, name.getText()); + } + }); + + final JTextField group = new JTextField(25); + group.getDocument().addDocumentListener(new DocumentListener() + { + @Override + public void insertUpdate(DocumentEvent e) + { + warnIfGroupHidden(mainPanel, group.getText()); + } + + @Override + public void removeUpdate(DocumentEvent e) + { + warnIfGroupHidden(mainPanel, group.getText()); + } + + @Override + public void changedUpdate(DocumentEvent e) + { + warnIfGroupHidden(mainPanel, group.getText()); + } + }); + final JTextArea description = new JTextArea(3, 25); final JSpinner start = new JSpinner(); final JSpinner end = new JSpinner(); @@ -222,7 +267,7 @@ public class FeatureRenderer extends SequenceFeature sf = features.get(index); name.setText(sf.getType()); description.setText(sf.getDescription()); - source.setText(sf.getFeatureGroup()); + group.setText(sf.getFeatureGroup()); start.setValue(new Integer(sf.getBegin())); end.setValue(new Integer(sf.getEnd())); @@ -246,8 +291,6 @@ public class FeatureRenderer extends gridPanel.add(choosePanel); } - // //////// - // //////////////////////////////////// JPanel namePanel = new JPanel(); gridPanel.add(namePanel); @@ -259,7 +302,7 @@ public class FeatureRenderer extends gridPanel.add(groupPanel); groupPanel.add(new JLabel(MessageManager.getString("label.group:"), JLabel.RIGHT)); - groupPanel.add(source); + groupPanel.add(group); JPanel colourPanel = new JPanel(); gridPanel.add(colourPanel); @@ -336,12 +379,12 @@ public class FeatureRenderer extends if (create) { name.setText(lastFeatureAdded); - source.setText(lastFeatureGroupAdded); + group.setText(lastFeatureGroupAdded); } else { name.setText(firstFeature.getType()); - source.setText(firstFeature.getFeatureGroup()); + group.setText(firstFeature.getFeatureGroup()); } start.setValue(new Integer(firstFeature.getBegin())); @@ -380,7 +423,7 @@ public class FeatureRenderer extends if (reply == JvOptionPane.OK_OPTION && name.getText().length() > 0) { lastFeatureAdded = name.getText().trim(); - lastFeatureGroupAdded = source.getText().trim(); + lastFeatureGroupAdded = group.getText().trim(); lastDescriptionAdded = description.getText().replaceAll("\n", " "); // TODO: determine if the null feature group is valid if (lastFeatureGroupAdded.length() < 1) @@ -399,19 +442,21 @@ public class FeatureRenderer extends * NO_OPTION corresponds to the Delete button */ sequences.get(0).getDatasetSequence().deleteFeature(sf); + // update Feature Settings for removal of feature / group + featuresAdded(); } else if (reply == JvOptionPane.YES_OPTION) { /* * YES_OPTION corresponds to the Amend button */ - boolean typeChanged = !lastFeatureAdded.equals(sf.type); + boolean typeOrGroupChanged = (!lastFeatureAdded.equals(sf.type) || !lastFeatureGroupAdded + .equals(sf.featureGroup)); sf.type = lastFeatureAdded; sf.featureGroup = lastFeatureGroupAdded; sf.description = lastDescriptionAdded; setColour(sf.type, fcol); - getFeaturesDisplayed().setVisible(sf.type); try { @@ -422,9 +467,9 @@ public class FeatureRenderer extends } ffile.parseDescriptionHTML(sf, false); - if (typeChanged) + if (typeOrGroupChanged) { - findAllFeatures(); + featuresAdded(); } } } @@ -444,14 +489,9 @@ public class FeatureRenderer extends ffile.parseDescriptionHTML(sf, false); } - if (lastFeatureGroupAdded != null) - { - setGroupVisibility(lastFeatureGroupAdded, true); - } setColour(lastFeatureAdded, fcol); - setVisible(lastFeatureAdded); - findAllFeatures(false); + featuresAdded(); alignPanel.paintAlignment(true); @@ -469,6 +509,42 @@ public class FeatureRenderer extends } /** + * Show a warning message if the entered type is one that is currently hidden + * + * @param panel + * @param type + */ + protected void warnIfTypeHidden(JPanel panel, String type) + { + if (getRenderOrder().contains(type)) + { + if (!showFeatureOfType(type)) + { + String msg = MessageManager.formatMessage("label.warning_hidden", + MessageManager.getString("label.feature_type"), type); + JvOptionPane.showMessageDialog(panel, msg, "", + JvOptionPane.OK_OPTION); + } + } + } + + /** + * Show a warning message if the entered group is one that is currently hidden + * + * @param panel + * @param group + */ + protected void warnIfGroupHidden(JPanel panel, String group) + { + if (featureGroups.containsKey(group) && !featureGroups.get(group)) + { + String msg = MessageManager.formatMessage("label.warning_hidden", + MessageManager.getString("label.group"), group); + JvOptionPane.showMessageDialog(panel, msg, "", JvOptionPane.OK_OPTION); + } + } + + /** * update the amend feature button dependent on the given style * * @param bigPanel diff --git a/src/jalview/gui/FeatureSettings.java b/src/jalview/gui/FeatureSettings.java index feb09fc..67bfb79 100644 --- a/src/jalview/gui/FeatureSettings.java +++ b/src/jalview/gui/FeatureSettings.java @@ -61,6 +61,7 @@ import java.io.InputStreamReader; import java.io.OutputStreamWriter; import java.io.PrintWriter; import java.util.Arrays; +import java.util.HashSet; import java.util.Hashtable; import java.util.Iterator; import java.util.List; @@ -131,6 +132,11 @@ public class FeatureSettings extends JPanel implements private static final int MIN_HEIGHT = 400; + /** + * Constructor + * + * @param af + */ public FeatureSettings(AlignFrame af) { this.af = af; @@ -531,27 +537,15 @@ public class FeatureSettings extends JPanel implements { boolean visible = fr.checkGroupVisibility(group, true); - if (groupPanel == null) - { - groupPanel = new JPanel(); - } - - boolean alreadyAdded = false; for (int g = 0; g < groupPanel.getComponentCount(); g++) { if (((JCheckBox) groupPanel.getComponent(g)).getText().equals(group)) { - alreadyAdded = true; ((JCheckBox) groupPanel.getComponent(g)).setSelected(visible); - break; + return visible; } } - if (alreadyAdded) - { - - return visible; - } final String grp = group; final JCheckBox check = new JCheckBox(group, visible); check.setFont(new Font("Serif", Font.BOLD, 12)); @@ -590,6 +584,7 @@ public class FeatureSettings extends JPanel implements SequenceFeature[] tmpfeatures; String group = null, type; Vector visibleChecks = new Vector(); + Set foundGroups = new HashSet(); // Find out which features should be visible depending on which groups // are selected / deselected @@ -608,6 +603,7 @@ public class FeatureSettings extends JPanel implements while (index < tmpfeatures.length) { group = tmpfeatures[index].featureGroup; + foundGroups.add(group); if (tmpfeatures[index].begin == 0 && tmpfeatures[index].end == 0) { @@ -712,20 +708,35 @@ public class FeatureSettings extends JPanel implements table.setModel(new FeatureTableModel(data)); table.getColumnModel().getColumn(0).setPreferredWidth(200); - if (groupPanel != null) - { - groupPanel.setLayout(new GridLayout( - fr.getFeatureGroupsSize() / 4 + 1, 4)); - - groupPanel.validate(); - bigPanel.add(groupPanel, BorderLayout.NORTH); - } + groupPanel.setLayout(new GridLayout(fr.getFeatureGroupsSize() / 4 + 1, + 4)); + pruneGroups(foundGroups); + groupPanel.validate(); updateFeatureRenderer(data, groupChanged != null); resettingTable = false; } /** + * Remove from the groups panel any checkboxes for groups that are not in the + * foundGroups set. This enables removing a group from the display when the + * last feature in that group is deleted. + * + * @param foundGroups + */ + protected void pruneGroups(Set foundGroups) + { + for (int g = 0; g < groupPanel.getComponentCount(); g++) + { + JCheckBox checkbox = (JCheckBox) groupPanel.getComponent(g); + if (!foundGroups.contains(checkbox.getText())) + { + groupPanel.remove(checkbox); + } + } + } + + /** * reorder data based on the featureRenderers global priority list. * * @param data @@ -1065,6 +1076,10 @@ public class FeatureSettings extends JPanel implements settingsPane.setLayout(borderLayout2); dasSettingsPane.setLayout(borderLayout3); bigPanel.setLayout(borderLayout4); + + groupPanel = new JPanel(); + bigPanel.add(groupPanel, BorderLayout.NORTH); + invert.setFont(JvSwingUtils.getLabelFont()); invert.setText(MessageManager.getString("label.invert_selection")); invert.addActionListener(new ActionListener() diff --git a/src/jalview/viewmodel/seqfeatures/FeatureRendererModel.java b/src/jalview/viewmodel/seqfeatures/FeatureRendererModel.java index 84c9477..f6addb8 100644 --- a/src/jalview/viewmodel/seqfeatures/FeatureRendererModel.java +++ b/src/jalview/viewmodel/seqfeatures/FeatureRendererModel.java @@ -36,6 +36,7 @@ import java.beans.PropertyChangeSupport; import java.util.ArrayList; import java.util.Arrays; import java.util.HashMap; +import java.util.HashSet; import java.util.Hashtable; import java.util.Iterator; import java.util.List; @@ -344,6 +345,8 @@ public abstract class FeatureRendererModel implements { minmax = new Hashtable(); } + + Set oldGroups = new HashSet(featureGroups.keySet()); AlignmentI alignment = av.getAlignment(); for (int i = 0; i < alignment.getHeight(); i++) { @@ -358,9 +361,10 @@ public abstract class FeatureRendererModel implements int index = 0; while (index < features.length) { + String fgrp = features[index].getFeatureGroup(); + oldGroups.remove(fgrp); if (!featuresDisplayed.isRegistered(features[index].getType())) { - String fgrp = features[index].getFeatureGroup(); if (fgrp != null) { Boolean groupDisplayed = featureGroups.get(fgrp); @@ -424,6 +428,16 @@ public abstract class FeatureRendererModel implements index++; } } + + /* + * oldGroups now consists of groups that no longer + * have any feature in them - remove these + */ + for (String grp : oldGroups) + { + featureGroups.remove(grp); + } + updateRenderOrder(allfeatures); findingFeatures = false; } -- 1.7.10.2