X-Git-Url: http://source.jalview.org/gitweb/?a=blobdiff_plain;f=src%2Fjalview%2Fgui%2FFeatureSettings.java;h=cdca96a97b2a1b7eb0d47b834fdbc03227c4e3c2;hb=9fcb12165750b20f8a73d0bb976b22be5fda94a2;hp=78c1cac854f5768fa2aef23a49ed877b74eacd69;hpb=b483c2012e40cab4b38f650dc049c94efe7e27c2;p=jalview.git diff --git a/src/jalview/gui/FeatureSettings.java b/src/jalview/gui/FeatureSettings.java index 78c1cac..cdca96a 100644 --- a/src/jalview/gui/FeatureSettings.java +++ b/src/jalview/gui/FeatureSettings.java @@ -24,19 +24,23 @@ import jalview.api.FeatureColourI; import jalview.api.FeatureSettingsControllerI; 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.datamodel.ontology.OntologyI; import jalview.gui.Help.HelpId; import jalview.io.JalviewFileChooser; import jalview.io.JalviewFileView; -import jalview.schemabinding.version2.Filter; -import jalview.schemabinding.version2.JalviewUserColours; -import jalview.schemabinding.version2.MatcherSet; +import jalview.io.gff.SequenceOntologyFactory; import jalview.schemes.FeatureColour; import jalview.util.MessageManager; import jalview.util.Platform; import jalview.viewmodel.seqfeatures.FeatureRendererModel.FeatureSettingsBean; +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; @@ -62,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; @@ -78,7 +83,6 @@ import javax.swing.BorderFactory; import javax.swing.Icon; import javax.swing.JButton; import javax.swing.JCheckBox; -import javax.swing.JCheckBoxMenuItem; import javax.swing.JColorChooser; import javax.swing.JDialog; import javax.swing.JInternalFrame; @@ -91,17 +95,28 @@ 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.border.Border; import javax.swing.event.ChangeEvent; import javax.swing.event.ChangeListener; import javax.swing.table.AbstractTableModel; +import javax.swing.table.JTableHeader; import javax.swing.table.TableCellEditor; import javax.swing.table.TableCellRenderer; import javax.swing.table.TableColumn; +import javax.swing.table.TableRowSorter; +import javax.xml.bind.JAXBContext; +import javax.xml.bind.JAXBElement; +import javax.xml.bind.Marshaller; +import javax.xml.stream.XMLInputFactory; +import javax.xml.stream.XMLStreamReader; 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"); @@ -122,6 +137,8 @@ public class FeatureSettings extends JPanel private static final int MIN_HEIGHT = 400; + private final static String BASE_TOOLTIP = MessageManager.getString("label.click_to_edit"); + final FeatureRenderer fr; public final AlignFrame af; @@ -152,12 +169,6 @@ public class FeatureSettings extends JPanel int selectedRow = -1; - JButton fetchDAS = new JButton(); - - JButton saveDAS = new JButton(); - - JButton cancelDAS = new JButton(); - boolean resettingTable = false; /* @@ -170,6 +181,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 * @@ -187,6 +209,8 @@ public class FeatureSettings extends JPanel originalFilters = new HashMap<>(fr.getFeatureFilters()); // shallow copy + topLevelTypes = new ArrayList<>(); + try { jbInit(); @@ -195,6 +219,69 @@ public class FeatureSettings extends JPanel ex.printStackTrace(); } + initTable(); + + scrollPane.setViewportView(table); + + 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); + }; + }); + 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 @@ -202,18 +289,30 @@ public class FeatureSettings extends JPanel { String tip = null; int column = table.columnAtPoint(e.getPoint()); + int row = table.rowAtPoint(e.getPoint()); switch (column) { case TYPE_COLUMN: - tip = JvSwingUtils.wrapTooltip(true, MessageManager + /* + * drag to reorder not enabled in Summary View + */ + tip = summaryView.isSelected() + ? MessageManager.getString( + "label.feature_settings_select_columns") + : JvSwingUtils.wrapTooltip(true, MessageManager .getString("label.feature_settings_click_drag")); break; + case COLOUR_COLUMN: + FeatureColourI colour = (FeatureColourI) table.getValueAt(row, + column); + tip = getColorTooltip(colour, true); + break; case FILTER_COLUMN: - int row = table.rowAtPoint(e.getPoint()); FeatureMatcherSet o = (FeatureMatcherSet) table.getValueAt(row, column); tip = o.isEmpty() - ? MessageManager.getString("label.filters_tooltip") + ? MessageManager + .getString("label.configure_feature_tooltip") : o.toString(); break; default: @@ -221,13 +320,28 @@ public class FeatureSettings extends JPanel } return tip; } + + /** + * Position the tooltip near the bottom edge of, and half way across, the + * current cell + */ + @Override + public Point getToolTipLocation(MouseEvent e) + { + Point point = e.getPoint(); + int column = table.columnAtPoint(point); + int row = table.rowAtPoint(point); + Rectangle r = getCellRect(row, column, false); + Point loc = new Point(r.x + r.width / 2, r.y + r.height - 3); + return loc; + } }; - table.getTableHeader().setFont(new Font("Verdana", Font.PLAIN, 12)); - table.setFont(new Font("Verdana", Font.PLAIN, 12)); - // table.setDefaultRenderer(Color.class, new ColorRenderer()); - // table.setDefaultEditor(Color.class, new ColorEditor(this)); - // + JTableHeader tableHeader = table.getTableHeader(); + tableHeader.setFont(VERDANA_12); + tableHeader.setReorderingAllowed(false); + table.setFont(VERDANA_12); + table.setDefaultEditor(FeatureColour.class, new ColorEditor(this)); table.setDefaultRenderer(FeatureColour.class, new ColorRenderer()); @@ -253,17 +367,16 @@ public class FeatureSettings extends JPanel String type = (String) table.getValueAt(selectedRow, TYPE_COLUMN); if (evt.isPopupTrigger()) { - Object colour = table.getValueAt(selectedRow, COLOUR_COLUMN); - popupSort(selectedRow, type, colour, fr.getMinMax(), evt.getX(), - evt.getY()); + popupMenu(selectedRow, type, evt.getX(), evt.getY()); } else if (evt.getClickCount() == 2) { boolean invertSelection = evt.isAltDown(); boolean toggleSelection = Platform.isControlDown(evt); boolean extendSelection = evt.isShiftDown(); + String[] terms = getTermsInScope(type); fr.ap.alignFrame.avc.markColumnsContainingFeatures( - invertSelection, extendSelection, toggleSelection, type); + invertSelection, extendSelection, toggleSelection, terms); } } @@ -275,9 +388,7 @@ public class FeatureSettings extends JPanel if (evt.isPopupTrigger()) { 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, evt.getX(), evt.getY()); } } }); @@ -288,92 +399,46 @@ 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; - } + dragRow(newRow); } }); - // table.setToolTipText(JvSwingUtils.wrapTooltip(true, - // MessageManager.getString("label.feature_settings_click_drag"))); - scrollPane.setViewportView(table); + } - if (af.getViewport().isShowSequenceFeatures() || !fr.hasRenderOrder()) + /** + * Answers an array consisting of the given type, and also (if 'Summary View' + * is selected), any feature types which are child terms of it in the Sequence + * Ontology + * + * @param type + * @return + */ + protected String[] getTermsInScope(String type) + { + if (!summaryView.isSelected()) { - fr.findAllFeatures(true); // display everything! + return new String[] { type }; } - 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; - } - } + List terms = new ArrayList<>(); + terms.add(type); - }); + OntologyI so = SequenceOntologyFactory.getInstance(); - frame = new JInternalFrame(); - frame.setContentPane(this); - if (Platform.isAMac()) - { - Desktop.addInternalFrame(frame, - MessageManager.getString("label.sequence_feature_settings"), - 600, 480); - } - else + Object[][] data = ((FeatureTableModel) table.getModel()).getData(); + for (Object[] row : data) { - Desktop.addInternalFrame(frame, - MessageManager.getString("label.sequence_feature_settings"), - 600, 450); + String type2 = (String) row[TYPE_COLUMN]; + if (!type2.equals(type) && so.isA(type2, type)) + { + terms.add(type2); + } } - 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); - }; - }); - frame.setLayer(JLayeredPane.PALETTE_LAYER); - inConstruction = false; + return terms.toArray(new String[terms.size()]); } - protected void popupSort(final int rowSelected, final String type, - final Object typeCol, final Map minmax, int x, + protected void popupMenu(final int rowSelected, final String type, int x, int y) { - final FeatureColourI featureColour = (FeatureColourI) typeCol; - JPopupMenu men = new JPopupMenu(MessageManager .formatMessage("label.settings_for_param", new String[] { type })); @@ -383,95 +448,26 @@ public class FeatureSettings extends JPanel final FeatureSettings me = this; scr.addActionListener(new ActionListener() { - @Override public void actionPerformed(ActionEvent e) { - me.af.avc - .sortAlignmentByFeatureScore(Arrays.asList(new String[] - { type })); + String[] types = getTermsInScope(type); + me.af.avc.sortAlignmentByFeatureScore(Arrays.asList(types)); } - }); JMenuItem dens = new JMenuItem( MessageManager.getString("label.sort_by_density")); dens.addActionListener(new ActionListener() { - @Override public void actionPerformed(ActionEvent e) { - me.af.avc - .sortAlignmentByFeatureDensity(Arrays.asList(new String[] - { type })); + String[] types = getTermsInScope(type); + me.af.avc.sortAlignmentByFeatureDensity(Arrays.asList(types)); } - }); men.add(dens); - /* - * variable colour options include colour by label, by score, - * by selected attribute text, or attribute value - */ - final JCheckBoxMenuItem mxcol = new JCheckBoxMenuItem( - MessageManager.getString("label.variable_colour")); - mxcol.setSelected(!featureColour.isSimpleColour()); - men.add(mxcol); - mxcol.addActionListener(new ActionListener() - { - JColorChooser colorChooser; - - @Override - public void actionPerformed(ActionEvent e) - { - if (e.getSource() == mxcol) - { - if (featureColour.isSimpleColour()) - { - FeatureTypeSettings fc = new FeatureTypeSettings(me.fr, type); - fc.addActionListener(this); - } - else - { - // bring up simple color chooser - colorChooser = new JColorChooser(); - String title = MessageManager - .getString("label.select_colour"); - JDialog dialog = JColorChooser.createDialog(me, - title, true, // modal - colorChooser, this, // OK button handler - null); // no CANCEL button handler - colorChooser.setColor(featureColour.getMaxColour()); - dialog.setVisible(true); - } - } - else - { - if (e.getSource() instanceof FeatureTypeSettings) - { - /* - * update after OK in feature colour dialog; the updated - * colour will have already been set in the FeatureRenderer - */ - FeatureColourI fci = fr.getFeatureColours().get(type); - table.setValueAt(fci, rowSelected, 1); - table.validate(); - } - else - { - // probably the color chooser! - table.setValueAt(new FeatureColour(colorChooser.getColor()), - rowSelected, 1); - table.validate(); - me.updateFeatureRenderer( - ((FeatureTableModel) table.getModel()).getData(), - false); - } - } - } - - }); - JMenuItem selCols = new JMenuItem( MessageManager.getString("label.select_columns_containing")); selCols.addActionListener(new ActionListener() @@ -479,8 +475,9 @@ public class FeatureSettings extends JPanel @Override public void actionPerformed(ActionEvent arg0) { + String[] types = getTermsInScope(type); fr.ap.alignFrame.avc.markColumnsContainingFeatures(false, false, - false, type); + false, types); } }); JMenuItem clearCols = new JMenuItem(MessageManager @@ -490,8 +487,9 @@ public class FeatureSettings extends JPanel @Override public void actionPerformed(ActionEvent arg0) { + String[] types = getTermsInScope(type); fr.ap.alignFrame.avc.markColumnsContainingFeatures(true, false, - false, type); + false, types); } }); JMenuItem hideCols = new JMenuItem( @@ -501,7 +499,8 @@ public class FeatureSettings extends JPanel @Override public void actionPerformed(ActionEvent arg0) { - fr.ap.alignFrame.hideFeatureColumns(type, true); + String[] types = getTermsInScope(type); + fr.ap.alignFrame.hideFeatureColumns(true, types); } }); JMenuItem hideOtherCols = new JMenuItem( @@ -511,7 +510,8 @@ public class FeatureSettings extends JPanel @Override public void actionPerformed(ActionEvent arg0) { - fr.ap.alignFrame.hideFeatureColumns(type, false); + String[] types = getTermsInScope(type); + fr.ap.alignFrame.hideFeatureColumns(false, types); } }); men.add(selCols); @@ -626,6 +626,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); @@ -644,6 +645,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; @@ -666,7 +674,6 @@ public class FeatureSettings extends JPanel { continue; } - data[dataIndex][TYPE_COLUMN] = type; data[dataIndex][COLOUR_COLUMN] = fr.getFeatureStyle(type); FeatureMatcherSetI featureFilter = fr.getFeatureFilter(type); @@ -718,7 +725,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( @@ -874,30 +917,39 @@ public class FeatureSettings extends JPanel InputStreamReader in = new InputStreamReader( new FileInputStream(file), "UTF-8"); - JalviewUserColours jucs = JalviewUserColours.unmarshal(in); + JAXBContext jc = JAXBContext + .newInstance("jalview.xml.binding.jalview"); + javax.xml.bind.Unmarshaller um = jc.createUnmarshaller(); + XMLStreamReader streamReader = XMLInputFactory.newInstance() + .createXMLStreamReader(in); + JAXBElement jbe = um.unmarshal(streamReader, + JalviewUserColours.class); + JalviewUserColours jucs = jbe.getValue(); + + // JalviewUserColours jucs = JalviewUserColours.unmarshal(in); /* * load feature colours */ - for (int i = jucs.getColourCount() - 1; i >= 0; i--) + for (int i = jucs.getColour().size() - 1; i >= 0; i--) { - jalview.schemabinding.version2.Colour newcol = jucs.getColour(i); - FeatureColourI colour = Jalview2XML.unmarshalColour(newcol); + Colour newcol = jucs.getColour().get(i); + FeatureColourI colour = jalview.project.Jalview2XML + .parseColour(newcol); fr.setColour(newcol.getName(), colour); - fr.setOrder(newcol.getName(), i / (float) jucs.getColourCount()); + fr.setOrder(newcol.getName(), i / (float) jucs.getColour().size()); } /* * load feature filters; loaded filters will replace any that are * currently defined, other defined filters are left unchanged */ - for (int i = 0; i < jucs.getFilterCount(); i++) + for (int i = 0; i < jucs.getFilter().size(); i++) { - jalview.schemabinding.version2.Filter filterModel = jucs - .getFilter(i); + Filter filterModel = jucs.getFilter().get(i); String featureType = filterModel.getFeatureType(); - FeatureMatcherSetI filter = Jalview2XML.unmarshalFilter(featureType, - filterModel.getMatcherSet()); + FeatureMatcherSetI filter = jalview.project.Jalview2XML + .parseFilter(featureType, filterModel.getMatcherSet()); if (!filter.isEmpty()) { fr.setFeatureFilter(featureType, filter); @@ -979,9 +1031,9 @@ public class FeatureSettings extends JPanel for (String featureType : sortedTypes) { FeatureColourI fcol = fr.getFeatureStyle(featureType); - jalview.schemabinding.version2.Colour col = Jalview2XML.marshalColour( - featureType, fcol); - ucs.addColour(col); + Colour col = jalview.project.Jalview2XML.marshalColour(featureType, + fcol); + ucs.getColour().add(col); } /* @@ -994,16 +1046,26 @@ public class FeatureSettings extends JPanel { Iterator iterator = filter.getMatchers().iterator(); FeatureMatcherI firstMatcher = iterator.next(); - MatcherSet ms = Jalview2XML.marshalFilter(firstMatcher, iterator, + jalview.xml.binding.jalview.FeatureMatcherSet ms = jalview.project.Jalview2XML + .marshalFilter(firstMatcher, iterator, filter.isAnded()); Filter filterModel = new Filter(); filterModel.setFeatureType(featureType); filterModel.setMatcherSet(ms); - ucs.addFilter(filterModel); + ucs.getFilter().add(filterModel); } } + JAXBContext jaxbContext = JAXBContext + .newInstance(JalviewUserColours.class); + Marshaller jaxbMarshaller = jaxbContext.createMarshaller(); + jaxbMarshaller.marshal( + new ObjectFactory().createJalviewUserColours(ucs), out); - ucs.marshal(out); + // jaxbMarshaller.marshal(object, pout); + // marshaller.marshal(object); + out.flush(); + + // ucs.marshal(out); out.close(); } catch (Exception ex) { @@ -1212,22 +1274,6 @@ public class FeatureSettings extends JPanel } } }); - help.setFont(JvSwingUtils.getLabelFont()); - help.setText(MessageManager.getString("action.help")); - help.addActionListener(new ActionListener() - { - @Override - public void actionPerformed(ActionEvent e) - { - try - { - Help.showHelpWindow(HelpId.SequenceFeatureSettings); - } catch (HelpSetException e1) - { - e1.printStackTrace(); - } - } - }); JButton cancel = new JButton(MessageManager.getString("action.cancel")); cancel.setFont(JvSwingUtils.getLabelFont()); @@ -1294,12 +1340,26 @@ public class FeatureSettings extends JPanel } }); + summaryView = new JCheckBox( + MessageManager.getString("label.summary_view")); + summaryView + .setToolTipText( + MessageManager.getString("label.summary_view_tip")); + summaryView.addActionListener(new ActionListener() + { + @Override + public void actionPerformed(ActionEvent e) + { + resetTable(null); + } + }); + transparency.setMaximum(70); transparency.setToolTipText( MessageManager.getString("label.transparency_tip")); - 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); @@ -1307,8 +1367,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); @@ -1321,6 +1385,143 @@ public class FeatureSettings extends JPanel this.add(settingsPane); } + /** + * 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(); + } + + /* + * Answers a suitable tooltip to show on the colour cell of the table + * + * @param fcol + * @param withHint + * if true include 'click to edit' and similar text + * @return + */ + public static String getColorTooltip(FeatureColourI fcol, + boolean withHint) + { + if (fcol == null) + { + return null; + } + if (fcol.isSimpleColour()) + { + return withHint ? BASE_TOOLTIP : null; + } + String description = fcol.getDescription(); + description = description.replaceAll("<", "<"); + description = description.replaceAll(">", ">"); + StringBuilder tt = new StringBuilder(description); + if (withHint) + { + tt.append("
").append(BASE_TOOLTIP).append("
"); + } + return JvSwingUtils.wrapTooltip(true, tt.toString()); + } + + public static void renderGraduatedColor(JLabel comp, FeatureColourI gcol, + int w, int h) + { + boolean thr = false; + StringBuilder tx = new StringBuilder(); + + if (gcol.isColourByAttribute()) + { + tx.append(FeatureMatcher + .toAttributeDisplayName(gcol.getAttributeName())); + } + else if (!gcol.isColourByLabel()) + { + tx.append(MessageManager.getString("label.score")); + } + tx.append(" "); + if (gcol.isAboveThreshold()) + { + thr = true; + tx.append(">"); + } + if (gcol.isBelowThreshold()) + { + thr = true; + tx.append("<"); + } + if (gcol.isColourByLabel()) + { + if (thr) + { + tx.append(" "); + } + if (!gcol.isColourByAttribute()) + { + tx.append("Label"); + } + comp.setIcon(null); + } + else + { + Color newColor = gcol.getMaxColour(); + comp.setBackground(newColor); + // System.err.println("Width is " + w / 2); + Icon ficon = new FeatureIcon(gcol, comp.getBackground(), w, h, thr); + comp.setIcon(ficon); + // tt+="RGB value: Max (" + newColor.getRed() + ", " + // + newColor.getGreen() + ", " + newColor.getBlue() + // + ")\nMin (" + minCol.getRed() + ", " + minCol.getGreen() + // + ", " + minCol.getBlue() + ")"); + } + comp.setHorizontalAlignment(SwingConstants.CENTER); + comp.setText(tx.toString()); + } + // /////////////////////////////////////////////////////////////////////// // http://java.sun.com/docs/books/tutorial/uiswing/components/table.html // /////////////////////////////////////////////////////////////////////// @@ -1329,7 +1530,7 @@ public class FeatureSettings extends JPanel private String[] columnNames = { MessageManager.getString("label.feature_type"), MessageManager.getString("action.colour"), - MessageManager.getString("label.filter"), + MessageManager.getString("label.configuration"), MessageManager.getString("label.show") }; private Object[][] data; @@ -1379,38 +1580,82 @@ public class FeatureSettings extends JPanel } /** - * Answers the class of the object in column c of the first row of the table + * Answers the class of column c of the table */ @Override public Class getColumnClass(int c) { - Object v = getValueAt(0, c); - return v == null ? null : v.getClass(); + switch (c) + { + case TYPE_COLUMN: + return String.class; + case COLOUR_COLUMN: + return FeatureColour.class; + case FILTER_COLUMN: + return FeatureMatcherSet.class; + default: + return Boolean.class; + } } + /** + * Answers true for all columns except Feature Type + */ @Override public boolean isCellEditable(int row, int col) { - return col == 0 ? false : true; + return col != TYPE_COLUMN; } + /** + * Sets the value in the model for a given row and column. If Visibility + * (Show/Hide) is being set, and the table is in Summary View, then it is + * set also on any sub-types of the row's feature type. + */ @Override public void setValueAt(Object value, int row, int col) { data[row][col] = value; fireTableCellUpdated(row, col); + if (summaryView.isSelected() && col == SHOW_COLUMN) + { + setSubtypesVisibility(row, (Boolean) value); + } updateFeatureRenderer(data); } + /** + * Sets the visibility of any feature types which are sub-types of the type + * in the given row of the table + * + * @param row + * @param value + */ + protected void setSubtypesVisibility(int row, Boolean value) + { + String type = (String) data[row][TYPE_COLUMN]; + OntologyI so = SequenceOntologyFactory.getInstance(); + + for (int r = 0; r < data.length; r++) + { + if (r != row) + { + String type2 = (String) data[r][TYPE_COLUMN]; + if (so.isA(type2, type)) + { + data[r][SHOW_COLUMN] = value; + fireTableCellUpdated(r, SHOW_COLUMN); + } + } + } + } } class ColorRenderer extends JLabel implements TableCellRenderer { - javax.swing.border.Border unselectedBorder = null; - - javax.swing.border.Border selectedBorder = null; + Border unselectedBorder = null; - final String baseTT = "Click to edit, right/apple click for menu."; + Border selectedBorder = null; public ColorRenderer() { @@ -1425,7 +1670,6 @@ public class FeatureSettings extends JPanel { FeatureColourI cellColour = (FeatureColourI) color; setOpaque(true); - setToolTipText(baseTT); setBackground(tbl.getBackground()); if (!cellColour.isSimpleColour()) { @@ -1532,77 +1776,6 @@ public class FeatureSettings extends JPanel renderGraduatedColor(comp, gcol, w, h); } - public static void renderGraduatedColor(JLabel comp, FeatureColourI gcol, - int w, int h) - { - boolean thr = false; - StringBuilder tt = new StringBuilder(); - StringBuilder tx = new StringBuilder(); - - if (gcol.isColourByAttribute()) - { - tx.append(String.join(":", gcol.getAttributeName())); - } - else if (!gcol.isColourByLabel()) - { - tx.append(MessageManager.getString("label.score")); - } - tx.append(" "); - if (gcol.isAboveThreshold()) - { - thr = true; - tx.append(">"); - tt.append("Thresholded (Above ").append(gcol.getThreshold()) - .append(") "); - } - if (gcol.isBelowThreshold()) - { - thr = true; - tx.append("<"); - tt.append("Thresholded (Below ").append(gcol.getThreshold()) - .append(") "); - } - if (gcol.isColourByLabel()) - { - tt.append("Coloured by label text. ").append(tt); - if (thr) - { - tx.append(" "); - } - if (!gcol.isColourByAttribute()) - { - tx.append("Label"); - } - comp.setIcon(null); - } - else - { - Color newColor = gcol.getMaxColour(); - comp.setBackground(newColor); - // System.err.println("Width is " + w / 2); - Icon ficon = new FeatureIcon(gcol, comp.getBackground(), w, h, thr); - comp.setIcon(ficon); - // tt+="RGB value: Max (" + newColor.getRed() + ", " - // + newColor.getGreen() + ", " + newColor.getBlue() - // + ")\nMin (" + minCol.getRed() + ", " + minCol.getGreen() - // + ", " + minCol.getBlue() + ")"); - } - comp.setHorizontalAlignment(SwingConstants.CENTER); - comp.setText(tx.toString()); - if (tt.length() > 0) - { - if (comp.getToolTipText() == null) - { - comp.setToolTipText(tt.toString()); - } - else - { - comp.setToolTipText( - tt.append(" ").append(comp.getToolTipText()).toString()); - } - } - } - class ColorEditor extends AbstractCellEditor implements TableCellEditor, ActionListener { @@ -1614,7 +1787,7 @@ public class FeatureSettings extends JPanel String type; - JButton button; + JButton colourButton; JColorChooser colorChooser; @@ -1631,13 +1804,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 @@ -1657,7 +1830,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); } @@ -1668,11 +1841,9 @@ public class FeatureSettings extends JPanel chooser.setRequestFocusEnabled(true); chooser.requestFocus(); chooser.addActionListener(this); - chooser.showTab(true); + // Make the renderer reappear. + fireEditingStopped(); } - // Make the renderer reappear. - fireEditingStopped(); - } else { @@ -1691,16 +1862,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(); @@ -1722,24 +1884,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; } } @@ -1760,7 +1922,7 @@ public class FeatureSettings extends JPanel String type; - JButton button; + JButton filterButton; protected static final String EDIT = "edit"; @@ -1769,10 +1931,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); } /** @@ -1781,7 +1943,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); @@ -1794,27 +1956,16 @@ public class FeatureSettings extends JPanel chooser.getWidth(), chooser.getHeight()); chooser.validate(); } - chooser.showTab(false); fireEditingStopped(); } 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(); } @@ -1833,18 +1984,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; @@ -1899,7 +2052,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(