/* * Jalview - A Sequence Alignment Editor and Viewer ($$Version-Rel$$) * Copyright (C) $$Year-Rel$$ The Jalview Authors * * This file is part of Jalview. * * Jalview is free software: you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation, either version 3 * of the License, or (at your option) any later version. * * Jalview is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty * of MERCHANTABILITY or FITNESS FOR A PARTICULAR * PURPOSE. See the GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with Jalview. If not, see . * The Jalview Authors are detailed in the 'AUTHORS' file. */ package jalview.appletgui; import jalview.api.FeatureColourI; import jalview.datamodel.SearchResults; import jalview.datamodel.SearchResultsI; import jalview.datamodel.SequenceFeature; import jalview.datamodel.SequenceI; import jalview.io.FeaturesFile; import jalview.schemes.FeatureColour; import jalview.util.ColorUtils; import jalview.util.MessageManager; import jalview.viewmodel.AlignmentViewport; import java.awt.BorderLayout; 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; import java.awt.Panel; import java.awt.ScrollPane; import java.awt.TextArea; import java.awt.TextField; 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; /** * DOCUMENT ME! * * @author $author$ * @version $Revision$ */ public class FeatureRenderer extends jalview.renderer.seqfeatures.FeatureRenderer { /* * creating a new feature defaults to the type and group as * the last one created */ static String lastFeatureAdded = "feature_1"; static String lastFeatureGroupAdded = "Jalview"; // Holds web links for feature groups and feature types // in the form label|link Hashtable featureLinks = null; /** * Creates a new FeatureRenderer object. * * @param av */ public FeatureRenderer(AlignmentViewport av) { super(av); } int featureIndex = 0; boolean deleteFeature = false; FeatureColourPanel colourPanel; class FeatureColourPanel extends Panel { String label = ""; private Color maxCol; private boolean isColourByLabel, isGcol; /** * render a feature style in the amend feature dialog box */ public void updateColor(FeatureColourI newcol) { Color bg = null; String vlabel = ""; if (newcol.isSimpleColour()) { bg = newcol.getColour(); setBackground(bg); } else { if (newcol.isAboveThreshold()) { vlabel += " (>)"; } else if (newcol.isBelowThreshold()) { vlabel += " (<)"; } if (isColourByLabel = newcol.isColourByLabel()) { setBackground(bg = Color.white); vlabel += " (by Label)"; } else { setBackground(bg = newcol.getMinColour()); maxCol = newcol.getMaxColour(); } } label = vlabel; setBackground(bg); repaint(); } FeatureColourPanel() { super(null); } @Override public void paint(Graphics g) { Dimension d = getSize(); if (isGcol) { if (isColourByLabel) { g.setColor(Color.white); g.fillRect(d.width / 2, 0, d.width / 2, d.height); g.setColor(Color.black); Font f = new Font("Verdana", Font.PLAIN, 10); g.setFont(f); g.drawString(MessageManager.getString("label.label"), 0, 0); } else { g.setColor(maxCol); g.fillRect(d.width / 2, 0, d.width / 2, d.height); } } } } /** * Shows a dialog allowing the user to create, or amend or delete, sequence * features. If null in the supplied feature(s), feature type and group * default to those for the last feature created (with initial defaults of * "feature_1" and "Jalview"). * * @param sequences * @param features * @param create * @param ap * @return */ boolean amendFeatures(final SequenceI[] sequences, final SequenceFeature[] features, boolean create, final AlignmentPanel ap) { final Panel bigPanel = new Panel(new BorderLayout()); final TextField name = 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); final Choice overlaps; 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; Panel panel = new Panel(new GridLayout(3, 1)); featureIndex = 0; // feature to be amended. Panel tmp; // ///////////////////////////////////// // /MULTIPLE FEATURES AT SELECTED RESIDUE if (!create && features.length > 1) { panel = new Panel(new GridLayout(4, 1)); tmp = new Panel(); tmp.add(new Label("Select Feature: ")); overlaps = new Choice(); for (int i = 0; i < features.length; i++) { String item = features[i].getType() + "/" + features[i].getBegin() + "-" + features[i].getEnd(); if (features[i].getFeatureGroup() != null) { item += " (" + features[i].getFeatureGroup() + ")"; } overlaps.addItem(item); } tmp.add(overlaps); overlaps.addItemListener(new java.awt.event.ItemListener() { @Override public void itemStateChanged(java.awt.event.ItemEvent e) { int index = overlaps.getSelectedIndex(); if (index != -1) { featureIndex = index; name.setText(features[index].getType()); description.setText(features[index].getDescription()); group.setText(features[index].getFeatureGroup()); start.setText(features[index].getBegin() + ""); end.setText(features[index].getEnd() + ""); SearchResultsI highlight = new SearchResults(); highlight.addResult(sequences[0], features[index].getBegin(), features[index].getEnd()); ap.seqPanel.seqCanvas.highlightSearchResults(highlight); } FeatureColourI col = getFeatureStyle(name.getText()); if (col == null) { Color generatedColour = ColorUtils .createColourFromName(name.getText()); col = new FeatureColour(generatedColour); } colourPanel.updateColor(col); } }); panel.add(tmp); } // //////// // //////////////////////////////////// tmp = new Panel(); panel.add(tmp); tmp.add(new Label(MessageManager.getString("label.name:"), Label.RIGHT)); tmp.add(name); tmp = new Panel(); panel.add(tmp); tmp.add(new Label(MessageManager.getString("label.group:"), Label.RIGHT)); tmp.add(group); tmp = new Panel(); panel.add(tmp); tmp.add(new Label(MessageManager.getString("label.colour"), Label.RIGHT)); tmp.add(colourPanel); bigPanel.add(panel, BorderLayout.NORTH); panel = new Panel(); panel.add(new Label(MessageManager.getString("label.description:"), Label.RIGHT)); panel.add(new ScrollPane().add(description)); if (!create) { bigPanel.add(panel, BorderLayout.SOUTH); panel = new Panel(); panel.add(new Label(MessageManager.getString("label.start"), Label.RIGHT)); panel.add(start); panel.add(new Label(MessageManager.getString("label.end"), Label.RIGHT)); panel.add(end); bigPanel.add(panel, BorderLayout.CENTER); } else { bigPanel.add(panel, BorderLayout.CENTER); } /* * use defaults for type and group (and update them on Confirm) only * if feature type has not been supplied by the caller * (e.g. for Amend, or create features from Find) */ boolean useLastDefaults = features[0].getType() == null; String featureType = useLastDefaults ? lastFeatureAdded : features[0] .getType(); String featureGroup = useLastDefaults ? lastFeatureGroupAdded : features[0].getFeatureGroup(); String title = create ? MessageManager .getString("label.create_new_sequence_features") : MessageManager.formatMessage("label.amend_delete_features", new String[] { sequences[0].getName() }); final JVDialog dialog = new JVDialog(ap.alignFrame, title, true, 385, 240); dialog.setMainPanel(bigPanel); name.setText(featureType); group.setText(featureGroup); if (!create) { dialog.ok.setLabel(MessageManager.getString("label.amend")); dialog.buttonPanel.add(deleteButton, 1); deleteButton.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent evt) { deleteFeature = true; dialog.setVisible(false); } }); } start.setText(features[0].getBegin() + ""); end.setText(features[0].getEnd() + ""); description.setText(features[0].getDescription()); // lookup (or generate) the feature colour FeatureColourI fcol = getFeatureStyle(name.getText()); // simply display the feature color in a box colourPanel.updateColor(fcol); dialog.setResizable(true); // TODO: render the graduated color in the box. colourPanel.addMouseListener(new MouseAdapter() { @Override public void mousePressed(MouseEvent evt) { if (!colourPanel.isGcol) { new UserDefinedColours(fr, ap.alignFrame); } else { new FeatureColourChooser(ap.alignFrame, name.getText()); dialog.transferFocus(); } } }); dialog.setVisible(true); FeaturesFile ffile = new FeaturesFile(); /* * only update default type and group if we used defaults */ if (dialog.accept && useLastDefaults) { lastFeatureAdded = name.getText().trim(); lastFeatureGroupAdded = group.getText().trim(); } if (!create) { SequenceFeature sf = features[featureIndex]; if (dialog.accept) { sf.type = name.getText().trim(); sf.featureGroup = group.getText().trim(); if (sf.featureGroup != null && sf.featureGroup.length() < 1) { sf.featureGroup = null; } sf.description = description.getText().replace('\n', ' '); if (!colourPanel.isGcol) { // update colour - otherwise its already done. setColour(sf.type, new FeatureColour(colourPanel.getBackground())); } try { sf.begin = Integer.parseInt(start.getText()); sf.end = Integer.parseInt(end.getText()); } catch (NumberFormatException ex) { // } boolean typeOrGroupChanged = (!featureType.equals(sf.type) || !featureGroup .equals(sf.featureGroup)); ffile.parseDescriptionHTML(sf, false); 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++) { features[i].type = name.getText().trim(); features[i].featureGroup = group.getText().trim(); features[i].description = description.getText() .replace('\n', ' '); sequences[i].addSequenceFeature(features[i]); ffile.parseDescriptionHTML(features[i], false); } Color newColour = colourPanel.getBackground(); // setColour(lastFeatureAdded, fcol); setColour(lastFeatureAdded, new FeatureColour(newColour)); // was fcol featuresAdded(); } else { // no update to the alignment return false; } } // refresh the alignment and the feature settings dialog if (((jalview.appletgui.AlignViewport) av).featureSettings != null) { ((jalview.appletgui.AlignViewport) av).featureSettings.refreshTable(); } // findAllFeatures(); ap.paintAlignment(true); 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); } }