/* * The MIT License (MIT) * * Copyright (c) 2007-2015 Fred Hutchinson Cancer Research Center and Broad Institute * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ package org.broad.igv.sam; import org.apache.log4j.Logger; import org.broad.igv.Globals; import org.broad.igv.event.IGVEventBus; import org.broad.igv.feature.SpliceJunctionFeature; import org.broad.igv.prefs.Constants; import org.broad.igv.prefs.PreferencesManager; import org.broad.igv.renderer.DataRange; import org.broad.igv.renderer.SpliceJunctionRenderer; import org.broad.igv.track.*; import org.broad.igv.ui.IGV; import org.broad.igv.ui.SashimiPlot; import org.broad.igv.ui.panel.IGVPopupMenu; import org.broad.igv.ui.panel.ReferenceFrame; import org.broad.igv.ui.util.UIUtilities; import org.broad.igv.util.ResourceLocator; import javax.swing.*; import java.awt.*; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.util.ArrayList; import java.util.Collections; import java.util.List; /** * @author dhmay * Finds splice junctions in real time and renders them as Features */ public class SpliceJunctionTrack extends FeatureTrack { private static Logger log = Logger.getLogger(SpliceJunctionTrack.class); private AlignmentTrack.RenderOptions renderOptions; public void setRenderOptions(AlignmentTrack.RenderOptions renderOptions) { this.renderOptions = renderOptions; } public enum StrandOption {COMBINE, FORWARD, REVERSE, BOTH} // Strand option is shared by all tracks private static StrandOption strandOption; private AlignmentTrack alignmentTrack; private AlignmentDataManager dataManager; private boolean removed = false; /** * The "DataPanel" containing this track. This field might be null at any given time. It is updated each repaint. */ private JComponent dataPanel; public static void setStrandOption(StrandOption so) { strandOption = so; } public static StrandOption getStrandOption() { return strandOption; } public SpliceJunctionTrack(ResourceLocator locator, String name, AlignmentDataManager dataManager, AlignmentTrack alignmentTrack, StrandOption ignoreStrand) { super(locator, locator.getPath() + "_junctions", name); super.setDataRange(new DataRange(0, 0, 60)); setRendererClass(SpliceJunctionRenderer.class); this.dataManager = dataManager; this.alignmentTrack = alignmentTrack; this.strandOption = ignoreStrand; // Register track } protected boolean isShowFeatures(ReferenceFrame frame) { float maxRange = PreferencesManager.getPreferences().getAsFloat(Constants.SAM_MAX_VISIBLE_RANGE); float minVisibleScale = (maxRange * 1000) / 700; return frame.getScale() < minVisibleScale; } public boolean isRemoved() { return removed; } public void clear() { this.packedFeaturesMap.clear(); } @Override public void dispose() { super.dispose(); removed = true; if(dataManager != null) { dataManager.dumpAlignments(); IGVEventBus.getInstance().unsubscribe(dataManager); } dataManager = null; alignmentTrack = null; setVisible(false); } @Override public void setVisible(boolean visible) { if(visible != isVisible()) { super.setVisible(visible); if (visible) { dataManager.initLoadOptions(); } if(IGV.hasInstance()) { IGV.getInstance().getMainPanel().revalidate(); } } } /** * Override to return a specialized popup menu * * @return */ @Override public IGVPopupMenu getPopupMenu(TrackClickEvent te) { IGVPopupMenu popupMenu = new IGVPopupMenu(); JLabel popupTitle = new JLabel(" " + getName(), JLabel.CENTER); Font newFont = popupMenu.getFont().deriveFont(Font.BOLD, 12); popupTitle.setFont(newFont); if (popupTitle != null) { popupMenu.add(popupTitle); } popupMenu.addSeparator(); ArrayList<Track> tmp = new ArrayList(); tmp.add(this); TrackMenuUtils.addStandardItems(popupMenu, tmp, te); popupMenu.addSeparator(); popupMenu.add(getChangeAutoScale()); popupMenu.addSeparator(); JMenuItem sashimi = new JMenuItem("Sashimi Plot"); sashimi.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { SashimiPlot.getSashimiPlot(null); } }); popupMenu.add(sashimi); if (alignmentTrack != null) { popupMenu.addSeparator(); final JMenuItem alignmentItem = new JCheckBoxMenuItem("Show Alignment Track"); alignmentItem.setSelected(alignmentTrack.isVisible()); alignmentItem.setEnabled(!alignmentTrack.isRemoved()); alignmentItem.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { alignmentTrack.setVisible(alignmentItem.isSelected()); } }); popupMenu.add(alignmentItem); final CoverageTrack coverageTrack = alignmentTrack.getCoverageTrack(); if (coverageTrack != null) { final JMenuItem coverageItem = new JCheckBoxMenuItem("Show Coverage Track"); coverageItem.setSelected(coverageTrack.isVisible()); coverageItem.setEnabled(!coverageTrack.isRemoved()); coverageItem.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { UIUtilities.invokeOnEventThread(new Runnable() { public void run() { coverageTrack.setVisible(coverageItem.isSelected()); IGV.getInstance().getMainPanel().revalidate(); } }); } }); popupMenu.add(coverageItem); } final JMenuItem junctionItem = new JMenuItem("Hide Track"); junctionItem.setEnabled(!isRemoved()); junctionItem.addActionListener(e -> { setVisible(false); }); popupMenu.add(junctionItem); } return popupMenu; } public boolean isLogNormalized() { return false; } public float getRegionScore(String chr, int start, int end, int zoom, RegionScoreType type, String frameName) { return 0; } @Override protected String getZoomInMessage(String chr) { return "Zoom in to see junctions."; } public void load(ReferenceFrame frame) { dataManager.load(frame, renderOptions, true); } @Override public boolean isReadyToPaint(ReferenceFrame frame) { if (frame.getChrName().equals(Globals.CHR_ALL) || frame.getScale() > dataManager.getMinVisibleScale()) { return true; // Nothing to paint } else { if(!dataManager.isLoaded(frame)) { packedFeaturesMap.clear(); return false; } else { AlignmentInterval loadedInterval = dataManager.getLoadedInterval(frame); if (packedFeaturesMap.get(frame.getChrName()) == null) { SpliceJunctionHelper helper = loadedInterval.getSpliceJunctionHelper(); List<SpliceJunctionFeature> features = helper.getFilteredJunctions(strandOption); if (features == null) { features = Collections.emptyList(); } int intervalStart = loadedInterval.getStart(); int intervalEnd = loadedInterval.getEnd(); PackedFeatures pf = new PackedFeaturesSpliceJunctions(frame.getChrName(), intervalStart, intervalEnd, features.iterator(), getName()); packedFeaturesMap.put(frame.getName(), pf); } return true; } } } @Override public String getExportTrackLine() { return "track graphType=junctions"; } @Override public boolean handleDataClick(TrackClickEvent te) { boolean result = super.handleDataClick(te); if (dataPanel != null) dataPanel.repaint(); return result; } // Start of Roche-Tessella modification private JMenuItem getChangeAutoScale() { final JCheckBoxMenuItem autoscaleItem = new JCheckBoxMenuItem("Autoscale"); boolean autoScale = getAutoScale(); autoscaleItem.setSelected(autoScale); autoscaleItem.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent evt) { boolean autoScale = getAutoScale(); TrackProperties tp = new TrackProperties(); if (autoScale) { tp.setAutoScale(false); autoscaleItem.setSelected(false); } else { tp.setAutoScale(true); autoscaleItem.setSelected(true); } tp.setRendererClass(SpliceJunctionRenderer.class); setProperties(tp); if (dataPanel != null) dataPanel.repaint(); } }); return autoscaleItem; } // End of Roche-Tessella modification }