From: James Procter Date: Sat, 15 Apr 2023 09:52:09 +0000 (+0100) Subject: Merge branch 'develop' into spike/JAL-4047/JAL-4048_columns_in_sequenceID X-Git-Url: http://source.jalview.org/gitweb/?a=commitdiff_plain;h=a79849ceb618568ed1b0ed2b400e1cf8e6d1ea81;hp=4c2789fc5d5f3ccc8ef55d833d3c87dcb45956c2;p=jalview.git Merge branch 'develop' into spike/JAL-4047/JAL-4048_columns_in_sequenceID --- diff --git a/src/jalview/api/AlignViewportI.java b/src/jalview/api/AlignViewportI.java index 03efec5..3c266e5 100644 --- a/src/jalview/api/AlignViewportI.java +++ b/src/jalview/api/AlignViewportI.java @@ -20,6 +20,13 @@ */ package jalview.api; +import java.awt.Color; +import java.awt.Font; +import java.util.Hashtable; +import java.util.Iterator; +import java.util.List; +import java.util.Map; + import jalview.analysis.Conservation; import jalview.analysis.TreeModel; import jalview.datamodel.AlignmentAnnotation; @@ -37,13 +44,7 @@ import jalview.datamodel.SequenceI; import jalview.renderer.ResidueShaderI; import jalview.schemes.ColourSchemeI; import jalview.viewmodel.ViewportRanges; - -import java.awt.Color; -import java.awt.Font; -import java.util.Hashtable; -import java.util.Iterator; -import java.util.List; -import java.util.Map; +import jalview.viewmodel.seqfeatures.IdColumns; /** * @author jimp @@ -557,5 +558,7 @@ public interface AlignViewportI extends ViewStyleI */ Iterator getViewAsVisibleContigs(boolean selectedRegionOnly); + IdColumns getIdColumns(); + ContactMatrixI getContactMatrix(AlignmentAnnotation alignmentAnnotation); } diff --git a/src/jalview/gui/IdCanvas.java b/src/jalview/gui/IdCanvas.java index c94dee0..68a7a1e 100755 --- a/src/jalview/gui/IdCanvas.java +++ b/src/jalview/gui/IdCanvas.java @@ -36,6 +36,9 @@ import javax.swing.JPanel; import jalview.datamodel.SequenceI; import jalview.viewmodel.ViewportListenerI; import jalview.viewmodel.ViewportRanges; +import jalview.viewmodel.seqfeatures.IdColumn; +import jalview.viewmodel.seqfeatures.IdColumns; +import jalview.viewmodel.seqfeatures.IdColumns.ColumnCell; /** * DOCUMENT ME! @@ -308,19 +311,27 @@ public class IdCanvas extends JPanel implements ViewportListenerI } // Now draw the id strings - int panelWidth = getWidth(); - int xPos = 0; + int fullPanelWidth = getWidth(); + + IdColumns id_cols = alignViewport.getIdColumns(); + List visible = id_cols.getVisible(); + /** + * width of an idColumn + */ + int colWid = 20; + int panelWidth = Math.max(fullPanelWidth / 2, + fullPanelWidth - (colWid * visible.size())); // Now draw the id strings for (int i = startSeq; i <= endSeq; i++) { + int xPos = 0; SequenceI sequence = alignViewport.getAlignment().getSequenceAt(i); if (sequence == null) { continue; } - if (hasHiddenRows || alignViewport.isDisplayReferenceSeq()) { g.setFont(getHiddenFont(sequence, alignViewport)); @@ -364,6 +375,37 @@ public class IdCanvas extends JPanel implements ViewportListenerI (((i - startSeq) * charHeight) + charHeight) - (charHeight / 5)); + if (visible != null && visible.size() > 0) + { + try + { + xPos = panelWidth + 2; + for (IdColumn col : visible) + { + ColumnCell col_cell = id_cols.getCellFor(sequence, col); + if (col_cell == null) + { + g.setColor(Color.gray); + g.fillRect(xPos + 1, (i - startSeq) * charHeight, + xPos + colWid - 3, charHeight); + } + else + { + g.setColor(col_cell.bg); + g.fillRect(xPos + 1, (i - startSeq) * charHeight, + xPos + colWid - 3, charHeight); + g.setColor(col_cell.fg); + g.drawString(col_cell.label, xPos, + (((i - startSeq) * charHeight) + charHeight) + - (charHeight / 5)); + } + xPos += colWid; + g.setColor(currentTextColor); + } + } catch (Exception q) + { + } + } if (hasHiddenRows && av.getShowHiddenMarkers()) { drawMarker(g, alignViewport, i, startSeq, 0); diff --git a/src/jalview/gui/IdPanel.java b/src/jalview/gui/IdPanel.java index 7b491e4..fdca723 100755 --- a/src/jalview/gui/IdPanel.java +++ b/src/jalview/gui/IdPanel.java @@ -46,6 +46,9 @@ import jalview.util.MessageManager; import jalview.util.Platform; import jalview.viewmodel.AlignmentViewport; import jalview.viewmodel.ViewportRanges; +import jalview.viewmodel.seqfeatures.IdColumn; +import jalview.viewmodel.seqfeatures.IdColumns; +import jalview.viewmodel.seqfeatures.IdColumns.ColumnCell; /** * This panel hosts alignment sequence ids and responds to mouse clicks on them, @@ -125,8 +128,17 @@ public class IdPanel extends JPanel SequenceI sequence = av.getAlignment().getSequenceAt(seq); StringBuilder tip = new StringBuilder(64); tip.append(sequence.getDisplayId(true)).append(" "); - seqAnnotReport.createTooltipAnnotationReport(tip, sequence, - av.isShowDBRefs(), av.isShowNPFeats(), sp.seqCanvas.fr); + IdColumn col = locateColumnFor(e); + if (col != null) + { + // tooltip for column + tip.append(getTooltipFor(col, sequence)); + } + else + { + seqAnnotReport.createTooltipAnnotationReport(tip, sequence, + av.isShowDBRefs(), av.isShowNPFeats(), sp.seqCanvas.fr); + } setToolTipText(JvSwingUtils.wrapTooltip(true, tip.toString())); StringBuilder text = new StringBuilder(); @@ -137,6 +149,40 @@ public class IdPanel extends JPanel } } + private Object getTooltipFor(IdColumn col, SequenceI seq) + { + ColumnCell cell = av.getIdColumns().getCellFor(seq, col); + if (cell != null) + { + return "" + col.getLabel() + ": " + cell.label; + } + return ""; + } + + private IdColumn locateColumnFor(MouseEvent e) + { + // TODO COMBINE SAME CODE IN IDCANVAS!!! + + IdColumns id_cols = av.getIdColumns(); + List visible = id_cols.getVisible(); + /** + * width of an idColumn + */ + int colWid = 20; + int panelWidth = Math.max(idCanvas.getWidth() / 2, + idCanvas.getWidth() - (colWid * visible.size())); + int p = 0; + while (panelWidth < idCanvas.getWidth() && p < visible.size()) + { + + if (e.getX() >= panelWidth && e.getX() < panelWidth + colWid) + return visible.get(p); + p++; + panelWidth += colWid; + } + return null; + } + /** * Responds to a mouse drag by selecting the sequences under the dragged * region. diff --git a/src/jalview/gui/PopupMenu.java b/src/jalview/gui/PopupMenu.java index 1c03d6a..47da7fc 100644 --- a/src/jalview/gui/PopupMenu.java +++ b/src/jalview/gui/PopupMenu.java @@ -87,6 +87,8 @@ import jalview.util.Platform; import jalview.util.StringUtils; import jalview.util.UrlLink; import jalview.viewmodel.seqfeatures.FeatureRendererModel; +import jalview.viewmodel.seqfeatures.IdColumn; +import jalview.viewmodel.seqfeatures.IdColumns; /** * The popup menu that is displayed on right-click on a sequence id, or in the @@ -726,9 +728,37 @@ public class PopupMenu extends JPopupMenu implements ColourChangeListener rnaStructureMenu.setVisible(false); } + if (forIdPanel) + { + addDisplayColumnsMenu(); + } + addLinksAndFeatures(seq, column); } + void addDisplayColumnsMenu() + { + JMenu dis_cols = new JMenu( + MessageManager.getString("action.displayed_columns")); + final IdColumns id_cols = ap.av.getIdColumns(); + for (final IdColumn col : id_cols.getIdColumns()) + { + JMenuItem col_entry = new JCheckBoxMenuItem(col.getLabel(), + col.isVisible()); + col_entry.addActionListener(new ActionListener() + { + + @Override + public void actionPerformed(ActionEvent e) + { + id_cols.toggleVisible(col.getLabel()); + } + }); + dis_cols.add(col_entry); + } + add(dis_cols); + } + /** * Adds *
    diff --git a/src/jalview/viewmodel/AlignmentViewport.java b/src/jalview/viewmodel/AlignmentViewport.java index 36b0851..d41a5be 100644 --- a/src/jalview/viewmodel/AlignmentViewport.java +++ b/src/jalview/viewmodel/AlignmentViewport.java @@ -72,6 +72,7 @@ import jalview.util.Comparison; import jalview.util.MapList; import jalview.util.MappingUtils; import jalview.util.MessageManager; +import jalview.viewmodel.seqfeatures.IdColumns; import jalview.viewmodel.styles.ViewStyle; import jalview.workers.AlignCalcManager; import jalview.workers.ComplementConsensusThread; @@ -3123,6 +3124,28 @@ public abstract class AlignmentViewport false)); } + /** + * ordered list of annotation values displayed per sequence in ID panel + */ + private IdColumns id_columns = null; + + /** + * available and currently visible columns for this view + */ + @Override + public IdColumns getIdColumns() + { + if (alignment == null) + { + return null; + } + if (id_columns == null) + { + id_columns = new IdColumns(alignment); + } + return id_columns; + } + public void setSavedUpToDate(boolean s) { setSavedUpToDate(s, QuitHandler.Message.UNSAVED_CHANGES); diff --git a/src/jalview/viewmodel/seqfeatures/IdColumn.java b/src/jalview/viewmodel/seqfeatures/IdColumn.java new file mode 100644 index 0000000..4b1cfa1 --- /dev/null +++ b/src/jalview/viewmodel/seqfeatures/IdColumn.java @@ -0,0 +1,49 @@ +package jalview.viewmodel.seqfeatures; + +public class IdColumn +{ + String name; + + String descr; + + boolean visible; + + /** + * name of the feature this column shows + */ + String featureTypeName = null; + + /** + * group to select feature(s) + */ + String featureGroupName = null; + + /** + * Label string for annotation row + */ + String annotationTypeName = null; + + /** + * calcId for annotation row + */ + String annotationTypeCalcId = null; + + public String DbRefName = null; + + public IdColumn(String string, String description, boolean b) + { + name = string; + descr = description; + visible = b; + } + + public String getLabel() + { + return name; + } + + public boolean isVisible() + { + return visible; + } +} \ No newline at end of file diff --git a/src/jalview/viewmodel/seqfeatures/IdColumns.java b/src/jalview/viewmodel/seqfeatures/IdColumns.java new file mode 100644 index 0000000..5b16b1a --- /dev/null +++ b/src/jalview/viewmodel/seqfeatures/IdColumns.java @@ -0,0 +1,205 @@ +package jalview.viewmodel.seqfeatures; + +import java.awt.Color; +import java.util.ArrayList; +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Vector; + +import jalview.api.DBRefEntryI; +import jalview.datamodel.AlignmentI; +import jalview.datamodel.SequenceFeature; +import jalview.datamodel.SequenceI; +import jalview.datamodel.features.SequenceFeaturesI; + +public class IdColumns +{ + + AlignmentI alignment = null; + + public IdColumns(AlignmentI al) + { + alignment = al; + columns.put(STRUCTURES_NUM.getLabel(), STRUCTURES_NUM); + updateTypeList(); + } + + public final static IdColumn STRUCTURES_NUM; + static + { + STRUCTURES_NUM = new IdColumn("3D Structures", + "Number of associated structure files", false); + } + + LinkedHashMap columns = new LinkedHashMap(); + + /** + * register a feature on the columnset + * + * @param sf + * @return true if feature was not seen before + */ + boolean updateListForFeature(SequenceFeature sf) + { + String colname = sf.getType(); + if (columns.get(colname) != null) + { + return false; + } + + IdColumn col = new IdColumn(colname, + "Nonpositional feature: " + colname, false); + col.featureTypeName = sf.getType(); + // col.featureGroupName = sf.getFeatureGroup(); + columns.put(colname, col); + return true; + } + + boolean updateListForDbxref(DBRefEntryI dbref) + { + String colname = dbref.getSource(); + if (columns.get(colname) != null) + { + return false; + } + + IdColumn col = new IdColumn(colname, + "Database CrossReference: " + colname, false); + col.DbRefName = colname; + // col.featureGroupName = sf.getFeatureGroup(); + columns.put(colname, col); + return true; + } + + public void updateTypeList() + { + for (SequenceI sq : alignment.getSequences()) + { + SequenceI seq = sq; + while (seq.getDatasetSequence() != null) + { + seq = seq.getDatasetSequence(); + } + + SequenceFeaturesI sqf = seq.getFeatures(); + List nonpos = sqf.getNonPositionalFeatures(); + if (nonpos != null) + { + for (SequenceFeature sf : nonpos) + { + updateListForFeature(sf); + } + } + for (DBRefEntryI dbr : seq.getDBRefs()) + { + updateListForDbxref(dbr); + } + } + } + + public void toggleVisible(String column) + { + IdColumn col = columns.get(column); + if (col != null) + { + col.visible = !col.visible; + } + } + + public List getVisible() + { + // probably want to cache this + ArrayList vis = new ArrayList(); + for (IdColumn col : columns.values()) + { + if (col.visible) + { + vis.add(col); + } + } + return vis; + } + + public final class ColumnCell + { + public final String label; + + public final Color bg; + + public final Color fg; + + public ColumnCell(final String label, final Color bg, final Color fg) + { + this.label = label; + this.bg = bg; + this.fg = fg; + } + } + + /** + * render the column value for this sequence + * + * @param seq + * @param col + * @return + */ + public ColumnCell getCellFor(SequenceI seq, IdColumn col) + { + ColumnCell cell = null; + if (col != null) + { + SequenceI dseq = seq; + while (dseq.getDatasetSequence() != null) + { + dseq = dseq.getDatasetSequence(); + } + if (col == STRUCTURES_NUM) + { + Vector pdbE = dseq.getAllPDBEntries(); + if (pdbE == null) + { + return null; + } + return new ColumnCell("" + pdbE.size(), Color.red, Color.white); + } + if (col.featureTypeName != null) + { + List np = dseq.getFeatures() + .getNonPositionalFeatures(col.featureTypeName); + if (np != null) + { + for (SequenceFeature npfeat : np) + { + // nb deal with multiplicities! + if (col.featureGroupName == null || (npfeat.featureGroup != null + && npfeat.featureGroup.equals(col.featureGroupName))) + { + Color fg = Color.black; + Color bg = Color.white; + + return new ColumnCell(npfeat.description, fg, bg); + } + } + } + } + if (col.DbRefName != null) + { + for (DBRefEntryI dbr : dseq.getDBRefs()) + { + if (dbr.getSource().equals(col.DbRefName)) + { + return new ColumnCell(dbr.getAccessionId(), Color.black, + Color.white); + } + } + } + } + // no value for this sequence in given column + return null; + } + + public IdColumn[] getIdColumns() + { + return columns.values().toArray(new IdColumn[0]); + } +}