From: gmungoc Date: Fri, 1 Jun 2018 18:39:47 +0000 (+0100) Subject: JAL-3010 options to hide / apply changes to ontology sub-types X-Git-Url: http://source.jalview.org/gitweb/?a=commitdiff_plain;h=4d0add405d43affa61fbf54d8a6624665bc8498d;p=jalview.git JAL-3010 options to hide / apply changes to ontology sub-types --- diff --git a/resources/lang/Messages.properties b/resources/lang/Messages.properties index ae5b0e7..f6c3f8f 100644 --- a/resources/lang/Messages.properties +++ b/resources/lang/Messages.properties @@ -814,6 +814,7 @@ label.rest_client_submit = {0} using {1} label.fetch_retrieve_from =Retrieve from {0} label.fetch_retrieve_from_all_sources = Retrieve from all {0} sources in {1}
First is :{2} label.feature_settings_click_drag = Drag up or down to change render order.
Double click to select columns containing feature. +label.feature_settings_select_columns = Double click to select columns containing feature label.transparency_tip = Adjust transparency to 'see through' feature colours. label.opt_and_params_further_details = see further details by right-clicking label.opt_and_params_show_brief_desc_image_link = Click to show brief description
Right click for further information. diff --git a/resources/lang/Messages_es.properties b/resources/lang/Messages_es.properties index 555977d..6d0eb67 100644 --- a/resources/lang/Messages_es.properties +++ b/resources/lang/Messages_es.properties @@ -739,7 +739,8 @@ label.services_at = Servicios en {0} label.rest_client_submit = {0} utilizando {1} label.fetch_retrieve_from =Recuperar de {0} label.fetch_retrieve_from_all_sources = Recuperar de todas las fuentes {0} en {1}
La primera es :{2} -label.feature_settings_click_drag = Haga clic o arrastre los tipos de las características hacia arriba o hacia abajo para cambiar el orden de visualización.
Haga doble clic para seleccionar las columnas que contienen las características del alineamiento/selección actual.
+label.feature_settings_click_drag = Haga clic o arrastre los tipos de las características hacia arriba o hacia abajo para cambiar el orden de visualización.
Haga doble clic para seleccionar las columnas que contienen las características del alineamiento/selección actual. +label.feature_settings_select_columns =Haga doble clic para seleccionar las columnas que contienen las características del alineamiento/selección actual label.opt_and_params_further_details = ver los detalles adicionales haciendo clic en el botón derecho label.opt_and_params_show_brief_desc_image_link = Haga clic para ver una descripción breve
Haga clic en el botón derecho para obtener información adicional. label.opt_and_params_show_brief_desc = Haga clic para ver una descripción breve
diff --git a/src/jalview/gui/FeatureSettings.java b/src/jalview/gui/FeatureSettings.java index 821454f..cb571d8 100644 --- a/src/jalview/gui/FeatureSettings.java +++ b/src/jalview/gui/FeatureSettings.java @@ -30,6 +30,7 @@ import jalview.datamodel.features.FeatureMatcherSetI; import jalview.gui.Help.HelpId; import jalview.io.JalviewFileChooser; import jalview.io.JalviewFileView; +import jalview.io.gff.SequenceOntologyFactory; import jalview.schemabinding.version2.Filter; import jalview.schemabinding.version2.JalviewUserColours; import jalview.schemabinding.version2.MatcherSet; @@ -65,6 +66,7 @@ import java.io.FileOutputStream; import java.io.InputStreamReader; import java.io.OutputStreamWriter; import java.io.PrintWriter; +import java.util.ArrayList; import java.util.Arrays; import java.util.Comparator; import java.util.HashMap; @@ -95,6 +97,7 @@ import javax.swing.JScrollPane; import javax.swing.JSlider; import javax.swing.JTable; import javax.swing.ListSelectionModel; +import javax.swing.RowFilter; import javax.swing.SwingConstants; import javax.swing.SwingUtilities; import javax.swing.event.ChangeEvent; @@ -103,10 +106,13 @@ import javax.swing.table.AbstractTableModel; import javax.swing.table.TableCellEditor; import javax.swing.table.TableCellRenderer; import javax.swing.table.TableColumn; +import javax.swing.table.TableRowSorter; public class FeatureSettings extends JPanel implements FeatureSettingsControllerI { + private static final Font VERDANA_12 = new Font("Verdana", Font.PLAIN, 12); + private static final String SEQUENCE_FEATURE_COLOURS = MessageManager .getString("label.sequence_feature_colours"); @@ -181,6 +187,17 @@ public class FeatureSettings extends JPanel */ Map typeWidth = null; + /* + * if true, 'child' feature types are not displayed + */ + JCheckBox summaryView; + + /* + * those feature types that do not have a parent feature type present + * (as determined by an Ontology relationship) + */ + List topLevelTypes; + /** * Constructor * @@ -198,6 +215,8 @@ public class FeatureSettings extends JPanel originalFilters = new HashMap<>(fr.getFeatureFilters()); // shallow copy + topLevelTypes = new ArrayList<>(); + try { jbInit(); @@ -206,6 +225,73 @@ public class FeatureSettings extends JPanel ex.printStackTrace(); } + initTable(); + + scrollPane.setViewportView(table); + + dassourceBrowser = new DasSourceBrowser(this); + dasSettingsPane.add(dassourceBrowser, BorderLayout.CENTER); + + if (af.getViewport().isShowSequenceFeatures() || !fr.hasRenderOrder()) + { + fr.findAllFeatures(true); // display everything! + } + + discoverAllFeatureData(); + final PropertyChangeListener change; + final FeatureSettings fs = this; + fr.addPropertyChangeListener(change = new PropertyChangeListener() + { + @Override + public void propertyChange(PropertyChangeEvent evt) + { + if (!fs.resettingTable && !fs.handlingUpdate) + { + fs.handlingUpdate = true; + fs.resetTable(null); + // new groups may be added with new sequence feature types only + fs.handlingUpdate = false; + } + } + }); + + frame = new JInternalFrame(); + frame.setContentPane(this); + if (Platform.isAMac()) + { + Desktop.addInternalFrame(frame, + MessageManager.getString("label.sequence_feature_settings"), + 600, 480); + } + else + { + Desktop.addInternalFrame(frame, + MessageManager.getString("label.sequence_feature_settings"), + 600, 450); + } + frame.setMinimumSize(new Dimension(MIN_WIDTH, MIN_HEIGHT)); + + frame.addInternalFrameListener( + new javax.swing.event.InternalFrameAdapter() + { + @Override + public void internalFrameClosed( + javax.swing.event.InternalFrameEvent evt) + { + fr.removePropertyChangeListener(change); + dassourceBrowser.fs = null; + }; + }); + frame.setLayer(JLayeredPane.PALETTE_LAYER); + inConstruction = false; + } + + /** + * Constructs and configures the JTable which displays columns of data for + * each feature type + */ + protected void initTable() + { table = new JTable() { @Override @@ -216,7 +302,10 @@ public class FeatureSettings extends JPanel switch (column) { case TYPE_COLUMN: - tip = JvSwingUtils.wrapTooltip(true, MessageManager + tip = summaryView.isSelected() + ? MessageManager.getString( + "label.feature_settings_select_columns") + : JvSwingUtils.wrapTooltip(true, MessageManager .getString("label.feature_settings_click_drag")); break; case FILTER_COLUMN: @@ -233,12 +322,9 @@ public class FeatureSettings extends JPanel return tip; } }; - table.getTableHeader().setFont(new Font("Verdana", Font.PLAIN, 12)); - table.setFont(new Font("Verdana", Font.PLAIN, 12)); + table.getTableHeader().setFont(VERDANA_12); + table.setFont(VERDANA_12); - // table.setDefaultRenderer(Color.class, new ColorRenderer()); - // table.setDefaultEditor(Color.class, new ColorEditor(this)); - // table.setDefaultEditor(FeatureColour.class, new ColorEditor(this)); table.setDefaultRenderer(FeatureColour.class, new ColorRenderer()); @@ -265,8 +351,7 @@ public class FeatureSettings extends JPanel if (evt.isPopupTrigger()) { Object colour = table.getValueAt(selectedRow, COLOUR_COLUMN); - popupSort(selectedRow, type, colour, fr.getMinMax(), evt.getX(), - evt.getY()); + popupMenu(selectedRow, type, colour, evt.getX(), evt.getY()); } else if (evt.getClickCount() == 2) { @@ -287,8 +372,7 @@ public class FeatureSettings extends JPanel { String type = (String) table.getValueAt(selectedRow, TYPE_COLUMN); Object colour = table.getValueAt(selectedRow, COLOUR_COLUMN); - popupSort(selectedRow, type, colour, fr.getMinMax(), evt.getX(), - evt.getY()); + popupMenu(selectedRow, type, colour, evt.getX(), evt.getY()); } } }); @@ -299,93 +383,13 @@ public class FeatureSettings extends JPanel public void mouseDragged(MouseEvent evt) { int newRow = table.rowAtPoint(evt.getPoint()); - if (newRow != selectedRow && selectedRow != -1 && newRow != -1) - { - /* - * reposition 'selectedRow' to 'newRow' (the dragged to location) - * this could be more than one row away for a very fast drag action - * so just swap it with adjacent rows until we get it there - */ - Object[][] data = ((FeatureTableModel) table.getModel()) - .getData(); - int direction = newRow < selectedRow ? -1 : 1; - for (int i = selectedRow; i != newRow; i += direction) - { - Object[] temp = data[i]; - data[i] = data[i + direction]; - data[i + direction] = temp; - } - updateFeatureRenderer(data); - table.repaint(); - selectedRow = newRow; - } - } - }); - // table.setToolTipText(JvSwingUtils.wrapTooltip(true, - // MessageManager.getString("label.feature_settings_click_drag"))); - scrollPane.setViewportView(table); - - dassourceBrowser = new DasSourceBrowser(this); - dasSettingsPane.add(dassourceBrowser, BorderLayout.CENTER); - - if (af.getViewport().isShowSequenceFeatures() || !fr.hasRenderOrder()) - { - fr.findAllFeatures(true); // display everything! - } - - discoverAllFeatureData(); - final PropertyChangeListener change; - final FeatureSettings fs = this; - fr.addPropertyChangeListener(change = new PropertyChangeListener() - { - @Override - public void propertyChange(PropertyChangeEvent evt) - { - if (!fs.resettingTable && !fs.handlingUpdate) - { - fs.handlingUpdate = true; - fs.resetTable(null); - // new groups may be added with new sequence feature types only - fs.handlingUpdate = false; - } + dragRow(newRow); } - }); - - frame = new JInternalFrame(); - frame.setContentPane(this); - if (Platform.isAMac()) - { - Desktop.addInternalFrame(frame, - MessageManager.getString("label.sequence_feature_settings"), - 600, 480); - } - else - { - Desktop.addInternalFrame(frame, - MessageManager.getString("label.sequence_feature_settings"), - 600, 450); - } - frame.setMinimumSize(new Dimension(MIN_WIDTH, MIN_HEIGHT)); - - frame.addInternalFrameListener( - new javax.swing.event.InternalFrameAdapter() - { - @Override - public void internalFrameClosed( - javax.swing.event.InternalFrameEvent evt) - { - fr.removePropertyChangeListener(change); - dassourceBrowser.fs = null; - }; - }); - frame.setLayer(JLayeredPane.PALETTE_LAYER); - inConstruction = false; } - protected void popupSort(final int rowSelected, final String type, - final Object typeCol, final Map minmax, int x, - int y) + protected void popupMenu(final int rowSelected, final String type, + final Object typeCol, int x, int y) { final FeatureColourI featureColour = (FeatureColourI) typeCol; @@ -484,7 +488,6 @@ public class FeatureSettings extends JPanel } } } - }); JMenuItem selCols = new JMenuItem( @@ -641,6 +644,7 @@ public class FeatureSettings extends JPanel */ Set types = seq.getFeatures().getFeatureTypesForGroups(true, visibleGroups.toArray(new String[visibleGroups.size()])); + for (String type : types) { displayableTypes.add(type); @@ -659,6 +663,13 @@ public class FeatureSettings extends JPanel } } + /* + * enable 'Summary View' if some types are sub-types of others + */ + Set parents = SequenceOntologyFactory.getInstance() + .getParentTerms(displayableTypes); + summaryView.setEnabled(parents.size() < displayableTypes.size()); + Object[][] data = new Object[displayableTypes.size()][COLUMN_COUNT]; int dataIndex = 0; @@ -681,7 +692,6 @@ public class FeatureSettings extends JPanel { continue; } - data[dataIndex][TYPE_COLUMN] = type; data[dataIndex][COLOUR_COLUMN] = fr.getFeatureStyle(type); FeatureMatcherSetI featureFilter = fr.getFeatureFilter(type); @@ -733,7 +743,43 @@ public class FeatureSettings extends JPanel updateOriginalData(data); } - table.setModel(new FeatureTableModel(data)); + /* + * recreate the table model + */ + FeatureTableModel dataModel = new FeatureTableModel(data); + table.setModel(dataModel); + + /* + * we want to be able to filter out rows for sub-types, but not to sort + * rows, so have to add a RowFilter to a disabled TableRowSorter (!) + */ + final TableRowSorter sorter = new TableRowSorter<>( + dataModel); + for (int i = 0; i < table.getColumnCount(); i++) + { + sorter.setSortable(i, false); + } + + /* + * filter rows to only top-level Ontology types if requested + */ + sorter.setRowFilter(new RowFilter() + { + @Override + public boolean include( + Entry entry) + { + if (!summaryView.isSelected()) + { + return true; + } + int row = entry.getIdentifier(); // this is model, not view, row number + String featureType = (String) entry.getModel().getData()[row][TYPE_COLUMN]; + return parents.contains(featureType); + } + }); + table.setRowSorter(sorter); + table.getColumnModel().getColumn(0).setPreferredWidth(200); groupPanel.setLayout( @@ -1311,6 +1357,17 @@ public class FeatureSettings extends JPanel } }); + summaryView = new JCheckBox("Summary view"); + summaryView.setToolTipText("Show only top level ontology terms"); + summaryView.addActionListener(new ActionListener() + { + @Override + public void actionPerformed(ActionEvent e) + { + resetTable(null); + } + }); + transparency.setMaximum(70); transparency.setToolTipText( MessageManager.getString("label.transparency_tip")); @@ -1347,8 +1404,8 @@ public class FeatureSettings extends JPanel } }); - JPanel transPanel = new JPanel(new GridLayout(1, 2)); - bigPanel.add(transPanel, BorderLayout.SOUTH); + JPanel lowerPanel = new JPanel(new GridLayout(1, 2)); + bigPanel.add(lowerPanel, BorderLayout.SOUTH); JPanel transbuttons = new JPanel(new GridLayout(5, 1)); transbuttons.add(optimizeOrder); @@ -1356,8 +1413,12 @@ public class FeatureSettings extends JPanel transbuttons.add(sortByScore); transbuttons.add(sortByDens); transbuttons.add(help); + JPanel transPanel = new JPanel(new GridLayout(3, 1)); + transPanel.add(summaryView); + transPanel.add(new JLabel(" Colour transparency" + ":")); transPanel.add(transparency); - transPanel.add(transbuttons); + lowerPanel.add(transPanel); + lowerPanel.add(transbuttons); JPanel buttonPanel = new JPanel(); buttonPanel.add(ok); @@ -1531,6 +1592,59 @@ public class FeatureSettings extends JPanel JvOptionPane.DEFAULT_OPTION, JvOptionPane.INFORMATION_MESSAGE); } + /** + * Reorders features by 'dragging' selectedRow to 'newRow' + * + * @param newRow + */ + protected void dragRow(int newRow) + { + if (summaryView.isSelected()) + { + // no drag while in summary view + return; + } + + if (newRow != selectedRow && selectedRow != -1 && newRow != -1) + { + /* + * reposition 'selectedRow' to 'newRow' (the dragged to location) + * this could be more than one row away for a very fast drag action + * so just swap it with adjacent rows until we get it there + */ + Object[][] data = ((FeatureTableModel) table.getModel()) + .getData(); + int direction = newRow < selectedRow ? -1 : 1; + for (int i = selectedRow; i != newRow; i += direction) + { + Object[] temp = data[i]; + data[i] = data[i + direction]; + data[i + direction] = temp; + } + updateFeatureRenderer(data); + table.repaint(); + selectedRow = newRow; + } + } + + protected void refreshTable() + { + Object[][] data = ((FeatureTableModel) table.getModel()).getData(); + for (Object[] row : data) + { + String type = (String) row[TYPE_COLUMN]; + FeatureColourI colour = fr.getFeatureColours().get(type); + FeatureMatcherSetI filter = fr.getFeatureFilter(type); + if (filter == null) + { + filter = new FeatureMatcherSet(); + } + row[COLOUR_COLUMN] = colour; + row[FILTER_COLUMN] = filter; + } + repaint(); + } + // /////////////////////////////////////////////////////////////////////// // http://java.sun.com/docs/books/tutorial/uiswing/components/table.html // /////////////////////////////////////////////////////////////////////// @@ -1824,7 +1938,7 @@ public class FeatureSettings extends JPanel String type; - JButton button; + JButton colourButton; JColorChooser colorChooser; @@ -1841,13 +1955,13 @@ public class FeatureSettings extends JPanel // which is a button. // This button brings up the color chooser dialog, // which is the editor from the user's point of view. - button = new JButton(); - button.setActionCommand(EDIT); - button.addActionListener(this); - button.setBorderPainted(false); + colourButton = new JButton(); + colourButton.setActionCommand(EDIT); + colourButton.addActionListener(this); + colourButton.setBorderPainted(false); // Set up the dialog that the button brings up. colorChooser = new JColorChooser(); - dialog = JColorChooser.createDialog(button, + dialog = JColorChooser.createDialog(colourButton, MessageManager.getString("label.select_colour"), true, // modal colorChooser, this, // OK button handler null); // no CANCEL button handler @@ -1867,7 +1981,7 @@ public class FeatureSettings extends JPanel if (currentColor.isSimpleColour()) { // bring up simple color chooser - button.setBackground(currentColor.getColour()); + colourButton.setBackground(currentColor.getColour()); colorChooser.setColor(currentColor.getColour()); dialog.setVisible(true); } @@ -1882,7 +1996,6 @@ public class FeatureSettings extends JPanel } // Make the renderer reappear. fireEditingStopped(); - } else { @@ -1901,16 +2014,7 @@ public class FeatureSettings extends JPanel * (or filters!) are already set in FeatureRenderer, so just * update table data without triggering updateFeatureRenderer */ - currentColor = fr.getFeatureColours().get(type); - FeatureMatcherSetI currentFilter = me.fr.getFeatureFilter(type); - if (currentFilter == null) - { - currentFilter = new FeatureMatcherSet(); - } - Object[] data = ((FeatureTableModel) table.getModel()) - .getData()[rowSelected]; - data[COLOUR_COLUMN] = currentColor; - data[FILTER_COLUMN] = currentFilter; + refreshTable(); } fireEditingStopped(); me.table.validate(); @@ -1932,24 +2036,24 @@ public class FeatureSettings extends JPanel currentColor = (FeatureColourI) value; this.rowSelected = row; type = me.table.getValueAt(row, TYPE_COLUMN).toString(); - button.setOpaque(true); - button.setBackground(me.getBackground()); + colourButton.setOpaque(true); + colourButton.setBackground(me.getBackground()); if (!currentColor.isSimpleColour()) { JLabel btn = new JLabel(); - btn.setSize(button.getSize()); + btn.setSize(colourButton.getSize()); FeatureSettings.renderGraduatedColor(btn, currentColor); - button.setBackground(btn.getBackground()); - button.setIcon(btn.getIcon()); - button.setText(btn.getText()); + colourButton.setBackground(btn.getBackground()); + colourButton.setIcon(btn.getIcon()); + colourButton.setText(btn.getText()); } else { - button.setText(""); - button.setIcon(null); - button.setBackground(currentColor.getColour()); + colourButton.setText(""); + colourButton.setIcon(null); + colourButton.setBackground(currentColor.getColour()); } - return button; + return colourButton; } } @@ -1970,7 +2074,7 @@ public class FeatureSettings extends JPanel String type; - JButton button; + JButton filterButton; protected static final String EDIT = "edit"; @@ -1979,10 +2083,10 @@ public class FeatureSettings extends JPanel public FilterEditor(FeatureSettings me) { this.me = me; - button = new JButton(); - button.setActionCommand(EDIT); - button.addActionListener(this); - button.setBorderPainted(false); + filterButton = new JButton(); + filterButton.setActionCommand(EDIT); + filterButton.addActionListener(this); + filterButton.setBorderPainted(false); } /** @@ -1991,7 +2095,7 @@ public class FeatureSettings extends JPanel @Override public void actionPerformed(ActionEvent e) { - if (button == e.getSource()) + if (filterButton == e.getSource()) { FeatureTypeSettings chooser = new FeatureTypeSettings(me.fr, type); chooser.addActionListener(this); @@ -2009,22 +2113,12 @@ public class FeatureSettings extends JPanel } else if (e.getSource() instanceof Component) { - /* * after OK in variable colour dialog, any changes to filter * (or colours!) are already set in FeatureRenderer, so just * update table data without triggering updateFeatureRenderer */ - FeatureColourI currentColor = fr.getFeatureColours().get(type); - currentFilter = me.fr.getFeatureFilter(type); - if (currentFilter == null) - { - currentFilter = new FeatureMatcherSet(); - } - Object[] data = ((FeatureTableModel) table.getModel()) - .getData()[rowSelected]; - data[COLOUR_COLUMN] = currentColor; - data[FILTER_COLUMN] = currentFilter; + refreshTable(); fireEditingStopped(); me.table.validate(); } @@ -2043,18 +2137,20 @@ public class FeatureSettings extends JPanel currentFilter = (FeatureMatcherSetI) value; this.rowSelected = row; type = me.table.getValueAt(row, TYPE_COLUMN).toString(); - button.setOpaque(true); - button.setBackground(me.getBackground()); - button.setText(currentFilter.toString()); - button.setToolTipText(currentFilter.toString()); - button.setIcon(null); - return button; + filterButton.setOpaque(true); + filterButton.setBackground(me.getBackground()); + filterButton.setText(currentFilter.toString()); + filterButton.setToolTipText(currentFilter.toString()); + filterButton.setIcon(null); + return filterButton; } } } class FeatureIcon implements Icon { + private static final Font VERDANA_9 = new Font("Verdana", Font.PLAIN, 9); + FeatureColourI gcol; Color backg; @@ -2109,7 +2205,7 @@ class FeatureIcon implements Icon // need an icon here. g.setColor(gcol.getMaxColour()); - g.setFont(new Font("Verdana", Font.PLAIN, 9)); + g.setFont(VERDANA_9); // g.setFont(g.getFont().deriveFont( // AffineTransform.getScaleInstance( diff --git a/src/jalview/gui/FeatureTypeSettings.java b/src/jalview/gui/FeatureTypeSettings.java index e13f6ee..64b5c8c 100644 --- a/src/jalview/gui/FeatureTypeSettings.java +++ b/src/jalview/gui/FeatureTypeSettings.java @@ -29,6 +29,7 @@ import jalview.datamodel.features.FeatureMatcher; import jalview.datamodel.features.FeatureMatcherI; import jalview.datamodel.features.FeatureMatcherSet; import jalview.datamodel.features.FeatureMatcherSetI; +import jalview.io.gff.SequenceOntologyFactory; import jalview.schemes.FeatureColour; import jalview.util.ColorUtils; import jalview.util.MessageManager; @@ -49,7 +50,11 @@ import java.awt.event.MouseAdapter; import java.awt.event.MouseEvent; import java.text.DecimalFormat; import java.util.ArrayList; +import java.util.Collections; +import java.util.HashMap; import java.util.List; +import java.util.Map; +import java.util.Map.Entry; import javax.swing.BorderFactory; import javax.swing.BoxLayout; @@ -118,10 +123,11 @@ public class FeatureTypeSettings extends JalviewDialog /* * the colour and filters to reset to on Cancel + * (including feature sub-types if modified) */ - private final FeatureColourI originalColour; + private Map originalColours; - private final FeatureMatcherSetI originalFilter; + private Map originalFilters; /* * set flag to true when setting values programmatically, @@ -206,6 +212,24 @@ public class FeatureTypeSettings extends JalviewDialog private JTabbedPane tabbedPane; + /* + * feature types present in Feature Renderer which are + * sub-types of the one this editor is acting on + */ + private final List subTypes; + + /* + * if selected, filter settings are also applied to any + * feature sub-types in the Sequence Ontology + */ + private JCheckBox applyFiltersToSubtypes; + + /* + * if selected, colour settings are also applied to any + * feature sub-types in the Sequence Ontology + */ + private JCheckBox applyColourToChildren; + /** * Constructor * @@ -231,8 +255,27 @@ public class FeatureTypeSettings extends JalviewDialog this.fr = frender; this.featureType = theType; ap = fr.ap; - originalFilter = fr.getFeatureFilter(theType); - originalColour = fr.getFeatureColours().get(theType); + + /* + * determine sub-types (if any) of this feature type + */ + List types = fr.getRenderOrder(); + subTypes = Collections.unmodifiableList(SequenceOntologyFactory + .getInstance().getChildTerms(this.featureType, types)); + + /* + * save original colours and filters for this feature type + * and any sub-types, to restore on Cancel + */ + originalFilters = new HashMap<>(); + originalFilters.put(theType, fr.getFeatureFilter(theType)); + originalColours = new HashMap<>(); + originalColours.put(theType, fr.getFeatureColours().get(theType)); + for (String child : subTypes) + { + originalFilters.put(child, fr.getFeatureFilter(child)); + originalColours.put(child, fr.getFeatureColours().get(child)); + } adjusting = true; @@ -877,6 +920,7 @@ public class FeatureTypeSettings extends JalviewDialog * save the colour, and repaint stuff */ fr.setColour(featureType, acg); + refreshFeatureSettings(); ap.paintAlignment(updateStructsAndOverview, updateStructsAndOverview); updateColoursTab(); @@ -994,9 +1038,14 @@ public class FeatureTypeSettings extends JalviewDialog @Override protected void raiseClosed() { + refreshFeatureSettings(); + } + + protected void refreshFeatureSettings() + { if (this.featureSettings != null) { - featureSettings.actionPerformed(new ActionEvent(this, 0, "CLOSED")); + featureSettings.actionPerformed(new ActionEvent(this, 0, "REFRESH")); } } @@ -1011,13 +1060,22 @@ public class FeatureTypeSettings extends JalviewDialog /** * Action on Cancel is to restore colour scheme and filters as they were when - * the dialog was opened + * the dialog was opened (including any feature sub-types that may have been + * changed) */ @Override public void cancelPressed() { - fr.setColour(featureType, originalColour); - fr.setFeatureFilter(featureType, originalFilter); + for (Entry entry : originalColours.entrySet()) + { + fr.setColour(entry.getKey(), entry.getValue()); + } + for (Entry entry : originalFilters + .entrySet()) + { + fr.setFeatureFilter(entry.getKey(), entry.getValue()); + } + ap.paintAlignment(true, true); } @@ -1186,9 +1244,12 @@ public class FeatureTypeSettings extends JalviewDialog */ private JPanel initialiseAndOrPanel() { - JPanel andOrPanel = new JPanel(new FlowLayout(FlowLayout.LEFT)); + JPanel andOrPanel = new JPanel(new BorderLayout()); andOrPanel.setBackground(Color.white); - andOrPanel.setBorder(BorderFactory.createLineBorder(debugBorderColour)); + JPanel panel1 = new JPanel(new FlowLayout(FlowLayout.LEFT)); + andOrPanel.add(panel1, BorderLayout.WEST); + panel1.setBackground(Color.white); + panel1.setBorder(BorderFactory.createLineBorder(debugBorderColour)); andFilters = new JRadioButton(MessageManager.getString("label.and")); orFilters = new JRadioButton(MessageManager.getString("label.or")); ActionListener actionListener = new ActionListener() @@ -1205,10 +1266,32 @@ public class FeatureTypeSettings extends JalviewDialog andOr.add(andFilters); andOr.add(orFilters); andFilters.setSelected(true); - andOrPanel.add( + panel1.add( new JLabel(MessageManager.getString("label.join_conditions"))); - andOrPanel.add(andFilters); - andOrPanel.add(orFilters); + panel1.add(andFilters); + panel1.add(orFilters); + + /* + * add an 'Apply to child terms' checkbox if there are any child terms + */ + applyFiltersToSubtypes = new JCheckBox("Apply also to child terms"); + if (!subTypes.isEmpty()) + { + JPanel panel2 = new JPanel(new FlowLayout(FlowLayout.RIGHT)); + panel2.setBackground(Color.white); + andOrPanel.add(panel2, BorderLayout.EAST); + StringBuilder sb = new StringBuilder(20 * subTypes.size()); + sb.append("Apply filters also to child terms" + ":"); // todo i18n + Collections.sort(subTypes); + for (String child : subTypes) + { + sb.append("
").append(child); + } + String tooltip = JvSwingUtils.wrapTooltip(true, sb.toString()); + applyFiltersToSubtypes.setToolTipText(tooltip); + panel2.add(applyFiltersToSubtypes); + } + return andOrPanel; } @@ -1756,6 +1839,15 @@ public class FeatureTypeSettings extends JalviewDialog * (note this might now be an empty filter with no conditions) */ fr.setFeatureFilter(featureType, combined.isEmpty() ? null : combined); + if (applyFiltersToSubtypes.isSelected()) + { + for (String child : subTypes) + { + fr.setFeatureFilter(child, combined.isEmpty() ? null : combined); + } + } + + refreshFeatureSettings(); ap.paintAlignment(true, true); updateFiltersTab();