import jalview.analysis.AlignmentAnnotationUtils;
import jalview.analysis.AlignmentUtils;
import jalview.analysis.Conservation;
+import jalview.api.AlignViewportI;
import jalview.bin.Cache;
import jalview.commands.ChangeCaseCommand;
import jalview.commands.EditCommand;
import jalview.commands.EditCommand.Action;
import jalview.datamodel.AlignmentAnnotation;
import jalview.datamodel.AlignmentI;
-import jalview.datamodel.Annotation;
import jalview.datamodel.DBRefEntry;
import jalview.datamodel.HiddenColumns;
+import jalview.datamodel.MappedFeatures;
import jalview.datamodel.PDBEntry;
import jalview.datamodel.SequenceFeature;
import jalview.datamodel.SequenceGroup;
import jalview.schemes.ColourSchemes;
import jalview.schemes.PIDColourScheme;
import jalview.schemes.ResidueColourScheme;
+import jalview.util.Comparison;
import jalview.util.GroupUrlLink;
import jalview.util.GroupUrlLink.UrlStringTooLongException;
import jalview.util.MessageManager;
import jalview.util.Platform;
import jalview.util.StringUtils;
import jalview.util.UrlLink;
+import jalview.viewmodel.seqfeatures.FeatureRendererModel;
import java.awt.BorderLayout;
import java.awt.Color;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
+import java.util.Objects;
import java.util.SortedMap;
import java.util.TreeMap;
import java.util.Vector;
*/
public class PopupMenu extends JPopupMenu implements ColourChangeListener
{
+ /*
+ * true for ID Panel menu, false for alignment panel menu
+ */
+ private final boolean forIdPanel;
+
+ private final AlignmentPanel ap;
+
+ /*
+ * the sequence under the cursor when clicked
+ * (additional sequences may be selected)
+ */
+ private final SequenceI sequence;
+
JMenu groupMenu = new JMenu();
JMenuItem groupName = new JMenuItem();
protected JMenuItem modifyConservation = new JMenuItem();
- AlignmentPanel ap;
-
JMenu sequenceMenu = new JMenu();
- JMenuItem sequenceName = new JMenuItem();
-
- JMenuItem sequenceDetails = new JMenuItem();
-
- JMenuItem sequenceSelDetails = new JMenuItem();
-
JMenuItem makeReferenceSeq = new JMenuItem();
- JMenuItem chooseAnnotations = new JMenuItem();
-
- SequenceI sequence;
-
JMenuItem createGroupMenuItem = new JMenuItem();
JMenuItem unGroupMenuItem = new JMenuItem();
- JMenuItem outline = new JMenuItem();
-
JMenu colourMenu = new JMenu();
JCheckBoxMenuItem showBoxes = new JCheckBoxMenuItem();
JMenu editMenu = new JMenu();
- JMenuItem cut = new JMenuItem();
-
- JMenuItem copy = new JMenuItem();
-
JMenuItem upperCase = new JMenuItem();
JMenuItem lowerCase = new JMenuItem();
JMenuItem toggle = new JMenuItem();
- JMenu pdbMenu = new JMenu();
-
JMenu outputMenu = new JMenu();
JMenu seqShowAnnotationsMenu = new JMenu();
JMenuItem groupAddReferenceAnnotations = new JMenuItem(
MessageManager.getString("label.add_reference_annotations"));
- JMenuItem sequenceFeature = new JMenuItem();
-
JMenuItem textColour = new JMenuItem();
- JMenu jMenu1 = new JMenu();
+ JMenu editGroupMenu = new JMenu();
- JMenuItem pdbStructureDialog = new JMenuItem();
+ JMenuItem chooseStructure = new JMenuItem();
JMenu rnaStructureMenu = new JMenu();
- JMenuItem editSequence = new JMenuItem();
-
- JMenu groupLinksMenu;
-
- JMenuItem hideInsertions = new JMenuItem();
-
/**
* Constructs a menu with sub-menu items for any hyperlinks for the sequence
* and/or features provided. Hyperlinks may include a lookup by sequence id,
* @param features
* @return
*/
- static JMenu buildLinkMenu(final SequenceI seq,
+ protected static JMenu buildLinkMenu(final SequenceI seq,
List<SequenceFeature> features)
{
JMenu linkMenu = new JMenu(MessageManager.getString("action.link"));
}
/**
- * Creates a new PopupMenu object.
+ * Constructor for a PopupMenu for a click in the alignment panel (on a residue)
*
* @param ap
+ * the panel in which the mouse is clicked
* @param seq
- * @param features
- * non-positional features (for seq not null), or positional features
- * at residue (for seq equal to null)
+ * the sequence under the mouse
+ * @throws NullPointerException
+ * if seq is null
*/
- public PopupMenu(final AlignmentPanel ap, SequenceI seq,
- List<SequenceFeature> features)
+ public PopupMenu(final AlignmentPanel ap, SequenceI seq, int column)
{
- this(ap, seq, features, null);
+ this(false, ap, seq, column, null);
}
/**
- * Constructor
+ * Constructor for a PopupMenu for a click in the sequence id panel
*
* @param alignPanel
+ * the panel in which the mouse is clicked
* @param seq
- * the sequence under the cursor if in the Id panel, null if in the
- * sequence panel
- * @param features
- * non-positional features if in the Id panel, features at the
- * clicked residue if in the sequence panel
+ * the sequence under the mouse click
* @param groupLinks
+ * templates for sequence external links
+ * @throws NullPointerException
+ * if seq is null
*/
public PopupMenu(final AlignmentPanel alignPanel, final SequenceI seq,
- List<SequenceFeature> features, List<String> groupLinks)
+ List<String> groupLinks)
{
- // /////////////////////////////////////////////////////////
- // If this is activated from the sequence panel, the user may want to
- // edit or annotate a particular residue. Therefore display the residue menu
- //
- // If from the IDPanel, we must display the sequence menu
- // ////////////////////////////////////////////////////////
+ this(true, alignPanel, seq, -1, groupLinks);
+ }
+
+ /**
+ * Private constructor that constructs a popup menu for either sequence ID
+ * Panel, or alignment context
+ *
+ * @param fromIdPanel
+ * @param alignPanel
+ * @param seq
+ * @param column
+ * aligned column position (0...)
+ * @param groupLinks
+ */
+ private PopupMenu(boolean fromIdPanel,
+ final AlignmentPanel alignPanel,
+ final SequenceI seq, final int column, List<String> groupLinks)
+ {
+ Objects.requireNonNull(seq);
+ this.forIdPanel = fromIdPanel;
this.ap = alignPanel;
sequence = seq;
* 'reference annotations' that may be added to the alignment. First for the
* currently selected sequence (if there is one):
*/
- final List<SequenceI> selectedSequence = (seq == null
- ? Collections.<SequenceI> emptyList()
- : Arrays.asList(seq));
+ final List<SequenceI> selectedSequence = (forIdPanel && seq != null
+ ? Arrays.asList(seq)
+ : Collections.<SequenceI> emptyList());
buildAnnotationTypesMenus(seqShowAnnotationsMenu,
seqHideAnnotationsMenu, selectedSequence);
configureReferenceAnnotationsMenu(seqAddReferenceAnnotations,
e.printStackTrace();
}
- JMenuItem menuItem;
- if (seq != null)
+ if (forIdPanel)
{
+ JMenuItem menuItem;
sequenceMenu.setText(sequence.getName());
if (seq == alignPanel.av.getAlignment().getSeqrep())
{
}
if (addOption)
{
- menuItem = new JMenuItem(
+ JMenuItem menuItem = new JMenuItem(
MessageManager.getString("action.reveal_all"));
menuItem.addActionListener(new ActionListener()
{
{
createGroupMenuItem.setVisible(true);
unGroupMenuItem.setVisible(false);
- jMenu1.setText(MessageManager.getString("action.edit_new_group"));
+ editGroupMenu.setText(MessageManager.getString("action.edit_new_group"));
}
else
{
createGroupMenuItem.setVisible(false);
unGroupMenuItem.setVisible(true);
- jMenu1.setText(MessageManager.getString("action.edit_group"));
+ editGroupMenu.setText(MessageManager.getString("action.edit_group"));
}
- if (seq == null)
+ if (!forIdPanel)
{
sequenceMenu.setVisible(false);
- pdbStructureDialog.setVisible(false);
+ chooseStructure.setVisible(false);
rnaStructureMenu.setVisible(false);
}
+ addLinksAndFeatures(seq, column);
+ }
+
+ /**
+ * Adds
+ * <ul>
+ * <li>configured sequence database links (ID panel popup menu)</li>
+ * <li>non-positional feature links (ID panel popup menu)</li>
+ * <li>positional feature links (alignment panel popup menu)</li>
+ * <li>feature details links (alignment panel popup menu)</li>
+ * </ul>
+ * If this panel is also showed complementary (CDS/protein) features, then links
+ * to their feature details are also added.
+ *
+ * @param seq
+ * @param column
+ */
+ void addLinksAndFeatures(final SequenceI seq, final int column)
+ {
+ List<SequenceFeature> features = null;
+ if (forIdPanel)
+ {
+ features = sequence.getFeatures().getNonPositionalFeatures();
+ }
+ else
+ {
+ features = ap.getFeatureRenderer().findFeaturesAtColumn(sequence,
+ column + 1);
+ }
+
addLinks(seq, features);
- if (seq == null)
+ if (!forIdPanel)
{
- addFeatureDetails(features);
+ addFeatureDetails(features, seq, column);
}
}
* Add a link to show feature details for each sequence feature
*
* @param features
+ * @param column
+ * @param seq
*/
- protected void addFeatureDetails(List<SequenceFeature> features)
+ protected void addFeatureDetails(List<SequenceFeature> features,
+ SequenceI seq, int column)
{
- if (features == null || features.isEmpty())
+ /*
+ * add features in CDS/protein complement at the corresponding
+ * position if configured to do so
+ */
+ MappedFeatures mf = null;
+ if (ap.av.isShowComplementFeatures())
+ {
+ if (!Comparison.isGap(sequence.getCharAt(column)))
+ {
+ AlignViewportI complement = ap.getAlignViewport()
+ .getCodingComplement();
+ AlignFrame af = Desktop.getAlignFrameFor(complement);
+ FeatureRendererModel fr2 = af.getFeatureRenderer();
+ int seqPos = sequence.findPosition(column);
+ mf = fr2.findComplementFeaturesAtResidue(sequence, seqPos);
+ }
+ }
+
+ if (features.isEmpty() && mf == null)
{
+ /*
+ * no features to show at this position
+ */
return;
}
+
JMenu details = new JMenu(
MessageManager.getString("label.feature_details"));
add(details);
+ String name = seq.getName();
for (final SequenceFeature sf : features)
{
- int start = sf.getBegin();
- int end = sf.getEnd();
- String desc = null;
- if (start == end)
+ addFeatureDetailsMenuItem(details, name, sf);
+ }
+
+ if (mf != null)
+ {
+ name = mf.fromSeq == seq ? mf.mapping.getTo().getName()
+ : mf.fromSeq.getName();
+ for (final SequenceFeature sf : mf.features)
{
- desc = String.format("%s %d", sf.getType(), start);
+ addFeatureDetailsMenuItem(details, name, sf);
}
- else
+ }
+ }
+
+ /**
+ * A helper method to add one menu item whose action is to show details for one
+ * feature
+ *
+ * @param details
+ * @param seqName
+ * @param sf
+ */
+ void addFeatureDetailsMenuItem(JMenu details, final String seqName,
+ final SequenceFeature sf)
+ {
+ int start = sf.getBegin();
+ int end = sf.getEnd();
+ String desc = null;
+ if (start == end)
+ {
+ desc = String.format("%s %d", sf.getType(), start);
+ }
+ else
+ {
+ desc = String.format("%s %d-%d", sf.getType(), start, end);
+ }
+ String tooltip = desc;
+ String description = sf.getDescription();
+ if (description != null)
+ {
+ description = StringUtils.stripHtmlTags(description);
+ if (description.length() > 12)
{
- desc = String.format("%s %d-%d", sf.getType(), start, end);
+ desc = desc + " " + description.substring(0, 12) + "..";
}
- String tooltip = desc;
- String description = sf.getDescription();
- if (description != null)
+ else
{
- description = StringUtils.stripHtmlTags(description);
- if (description.length() > 12)
- {
- desc = desc + " " + description.substring(0, 12) + "..";
- }
- else
- {
- desc = desc + " " + description;
- }
- tooltip = tooltip + " " + description;
+ desc = desc + " " + description;
}
- if (sf.getFeatureGroup() != null)
+ tooltip = tooltip + " " + description;
+ }
+ if (sf.getFeatureGroup() != null)
+ {
+ tooltip = tooltip + (" (" + sf.getFeatureGroup() + ")");
+ }
+ JMenuItem item = new JMenuItem(desc);
+ item.setToolTipText(tooltip);
+ item.addActionListener(new ActionListener()
+ {
+ @Override
+ public void actionPerformed(ActionEvent e)
{
- tooltip = tooltip + (" (" + sf.getFeatureGroup() + ")");
+ showFeatureDetails(seqName, sf);
}
- JMenuItem item = new JMenuItem(desc);
- item.setToolTipText(tooltip);
- item.addActionListener(new ActionListener()
- {
- @Override
- public void actionPerformed(ActionEvent e)
- {
- showFeatureDetails(sf);
- }
- });
- details.add(item);
- }
+ });
+ details.add(item);
}
/**
* Opens a panel showing a text report of feature dteails
*
+ * @param seqName
+ *
* @param sf
*/
- protected void showFeatureDetails(SequenceFeature sf)
+ protected void showFeatureDetails(String seqName, SequenceFeature sf)
{
JInternalFrame details;
if (Platform.isJS())
// TODO JAL-3026 set style of table correctly for feature details
JLabel reprt = new JLabel(MessageManager
.formatMessage("label.html_content", new Object[]
- { sf.getDetailsReport() }));
+ { sf.getDetailsReport(seqName) }));
reprt.setBackground(Color.WHITE);
reprt.setOpaque(true);
panel.add(reprt, BorderLayout.CENTER);
/**
* Java only
*
- * @j2sNative
+ * @j2sIgnore
*/
{
CutAndPasteHtmlTransfer cap = new CutAndPasteHtmlTransfer();
// it appears Java's CSS does not support border-collaps :-(
cap.addStylesheetRule("table { border-collapse: collapse;}");
cap.addStylesheetRule("table, td, th {border: 1px solid black;}");
- cap.setText(sf.getDetailsReport());
+ cap.setText(sf.getDetailsReport(seqName));
details = cap;
}
Desktop.addInternalFrame(details,
*/
void addLinks(final SequenceI seq, List<SequenceFeature> features)
{
- JMenu linkMenu = buildLinkMenu(seq, features);
+ JMenu linkMenu = buildLinkMenu(forIdPanel ? seq : null, features);
// only add link menu if it has entries
if (linkMenu.getItemCount() > 0)
{
- if (sequence != null)
+ if (forIdPanel)
{
sequenceMenu.add(linkMenu);
}
// menu appears asap
// sequence only URLs
// ID/regex match URLs
- groupLinksMenu = new JMenu(
+ JMenu groupLinksMenu = new JMenu(
MessageManager.getString("action.group_link"));
// three types of url that might be created.
JMenu[] linkMenus = new JMenu[] { null,
Cache.log.error("Exception for GroupURLLink '" + link + "'", foo);
continue;
}
- ;
if (!urlLink.isValid())
{
Cache.log.error(urlLink.getInvalidMessage());
}
});
sequenceMenu.setText(MessageManager.getString("label.sequence"));
- sequenceName.setText(
+
+ JMenuItem sequenceName = new JMenuItem(
MessageManager.getString("label.edit_name_description"));
sequenceName.addActionListener(new ActionListener()
{
sequenceName_actionPerformed();
}
});
- chooseAnnotations
- .setText(MessageManager.getString("action.choose_annotations"));
+ JMenuItem chooseAnnotations = new JMenuItem(
+ MessageManager.getString("action.choose_annotations"));
chooseAnnotations.addActionListener(new ActionListener()
{
@Override
chooseAnnotations_actionPerformed(e);
}
});
- sequenceDetails
- .setText(MessageManager.getString("label.sequence_details"));
+ JMenuItem sequenceDetails = new JMenuItem(
+ MessageManager.getString("label.sequence_details"));
sequenceDetails.addActionListener(new ActionListener()
{
@Override
public void actionPerformed(ActionEvent e)
{
- sequenceDetails_actionPerformed();
+ createSequenceDetailsReport(new SequenceI[] { sequence });
}
});
- sequenceSelDetails
- .setText(MessageManager.getString("label.sequence_details"));
+ JMenuItem sequenceSelDetails = new JMenuItem(
+ MessageManager.getString("label.sequence_details"));
sequenceSelDetails.addActionListener(new ActionListener()
{
@Override
public void actionPerformed(ActionEvent e)
{
- sequenceSelectionDetails_actionPerformed();
+ createSequenceDetailsReport(ap.av.getSequenceSelection());
}
});
}
});
- outline.setText(MessageManager.getString("action.border_colour"));
+ JMenuItem outline = new JMenuItem(
+ MessageManager.getString("action.border_colour"));
outline.addActionListener(new ActionListener()
{
@Override
}
});
editMenu.setText(MessageManager.getString("action.edit"));
- cut.setText(MessageManager.getString("action.cut"));
+ JMenuItem cut = new JMenuItem(MessageManager.getString("action.cut"));
cut.addActionListener(new ActionListener()
{
@Override
changeCase(e);
}
});
- copy.setText(MessageManager.getString("action.copy"));
+ JMenuItem copy = new JMenuItem(MessageManager.getString("action.copy"));
copy.addActionListener(new ActionListener()
{
@Override
.setText(MessageManager.getString("label.show_annotations"));
groupHideAnnotationsMenu
.setText(MessageManager.getString("label.hide_annotations"));
- sequenceFeature.setText(
+ JMenuItem sequenceFeature = new JMenuItem(
MessageManager.getString("label.create_sequence_feature"));
sequenceFeature.addActionListener(new ActionListener()
{
sequenceFeature_actionPerformed();
}
});
- jMenu1.setText(MessageManager.getString("label.group"));
- pdbStructureDialog.setText(
+ editGroupMenu.setText(MessageManager.getString("label.group"));
+ chooseStructure.setText(
MessageManager.getString("label.show_pdbstruct_dialog"));
- pdbStructureDialog.addActionListener(new ActionListener()
+ chooseStructure.addActionListener(new ActionListener()
{
@Override
public void actionPerformed(ActionEvent actionEvent)
.setText(MessageManager.getString("label.view_rna_structure"));
// colStructureMenu.setText("Colour By Structure");
- editSequence.setText(
+ JMenuItem editSequence = new JMenuItem(
MessageManager.getString("label.edit_sequence") + "...");
editSequence.addActionListener(new ActionListener()
{
}
});
- hideInsertions
- .setText(MessageManager.getString("label.hide_insertions"));
- hideInsertions.addActionListener(new ActionListener()
- {
-
- @Override
- public void actionPerformed(ActionEvent e)
- {
- hideInsertions_actionPerformed(e);
- }
- });
groupMenu.add(sequenceSelDetails);
add(groupMenu);
add(sequenceMenu);
add(rnaStructureMenu);
- add(pdbStructureDialog);
- if (sequence != null)
+ add(chooseStructure);
+ if (forIdPanel)
{
+ JMenuItem hideInsertions = new JMenuItem(
+ MessageManager.getString("label.hide_insertions"));
+ hideInsertions.addActionListener(new ActionListener()
+ {
+
+ @Override
+ public void actionPerformed(ActionEvent e)
+ {
+ hideInsertions_actionPerformed(e);
+ }
+ });
add(hideInsertions);
}
// annotations configuration panel suppressed for now
groupMenu.add(sequenceFeature);
groupMenu.add(createGroupMenuItem);
groupMenu.add(unGroupMenuItem);
- groupMenu.add(jMenu1);
+ groupMenu.add(editGroupMenu);
sequenceMenu.add(sequenceName);
sequenceMenu.add(sequenceDetails);
sequenceMenu.add(makeReferenceSeq);
editMenu.add(upperCase);
editMenu.add(lowerCase);
editMenu.add(toggle);
- // JBPNote: These shouldn't be added here - should appear in a generic
- // 'apply web service to this sequence menu'
- // pdbMenu.add(RNAFold);
- // pdbMenu.add(ContraFold);
- jMenu1.add(groupName);
- jMenu1.add(colourMenu);
- jMenu1.add(showBoxes);
- jMenu1.add(showText);
- jMenu1.add(showColourText);
- jMenu1.add(outline);
- jMenu1.add(displayNonconserved);
+ editGroupMenu.add(groupName);
+ editGroupMenu.add(colourMenu);
+ editGroupMenu.add(showBoxes);
+ editGroupMenu.add(showText);
+ editGroupMenu.add(showColourText);
+ editGroupMenu.add(outline);
+ editGroupMenu.add(displayNonconserved);
}
/**
createSequenceDetailsReport(ap.av.getSequenceSelection());
}
- protected void sequenceDetails_actionPerformed()
- {
- createSequenceDetailsReport(new SequenceI[] { sequence });
- }
-
public void createSequenceDetailsReport(SequenceI[] sequences)
{
StringBuilder contents = new StringBuilder(128);
/**
* Java only
*
- * @j2sNative
+ * @j2sIgnore
*/
{
CutAndPasteHtmlTransfer cap = new CutAndPasteHtmlTransfer();
}
/**
- * Shows a dialog where sequence name and description may be edited
+ * Shows a dialog where the sequence name and description may be edited. If a
+ * name containing spaces is entered, these are converted to underscores, with a
+ * warning message.
*/
void sequenceName_actionPerformed()
{
{
getGroup().setOutlineColour(c);
refresh();
- };
+ }
};
JalviewColourChooser.showColourChooser(Desktop.getDesktop(),
title, Color.BLUE, listener);
}
}
- public void colourByStructure(String pdbid)
- {
- Annotation[] anots = ap.av.getStructureSelectionManager()
- .colourSequenceFromStructure(sequence, pdbid);
-
- AlignmentAnnotation an = new AlignmentAnnotation("Structure",
- "Coloured by " + pdbid, anots);
-
- ap.av.getAlignment().addAnnotation(an);
- an.createSequenceMapping(sequence, 0, true);
- // an.adjustForAlignment();
- ap.av.getAlignment().setAnnotationIndex(an, 0);
-
- ap.adjustAnnotationHeight();
-
- sequence.addAlignmentAnnotation(an);
-
- }
-
/**
* Shows a dialog where sequence characters may be edited. Any changes are
* applied, and added as an available 'Undo' item in the edit commands
{
SequenceGroup sg = ap.av.getSelectionGroup();
+ SequenceI seq = sequence;
if (sg != null)
{
- if (sequence == null)
+ if (seq == null)
{
- sequence = sg.getSequenceAt(0);
+ seq = sg.getSequenceAt(0);
}
EditNameDialog dialog = new EditNameDialog(
- sequence.getSequenceAsString(sg.getStartRes(),
- sg.getEndRes() + 1),
+ seq.getSequenceAsString(sg.getStartRes(), sg.getEndRes() + 1),
null, MessageManager.getString("label.edit_sequence"), null);
dialog.showDialog(ap.alignFrame,
MessageManager.getString("label.edit_sequence"),