/*******************************************************************************
* GenPlay, Einstein Genome Analyzer
* Copyright (C) 2009, 2014 Albert Einstein College of Medicine
*
* This program 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.
*
* This program 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 this program. If not, see <http://www.gnu.org/licenses/>.
* Authors: Julien Lajugie <julien.lajugie@einstein.yu.edu>
* Nicolas Fourel <nicolas.fourel@einstein.yu.edu>
* Eric Bouhassira <eric.bouhassira@einstein.yu.edu>
*
* Website: <http://genplay.einstein.yu.edu>
******************************************************************************/
package edu.yu.einstein.genplay.gui.track;
import java.awt.Cursor;
import java.awt.Graphics;
import java.awt.MouseInfo;
import java.awt.Point;
import java.awt.event.ComponentEvent;
import java.awt.event.ComponentListener;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.awt.event.MouseMotionListener;
import java.awt.event.MouseWheelEvent;
import java.awt.event.MouseWheelListener;
import java.io.Serializable;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;
import javax.swing.ToolTipManager;
import edu.yu.einstein.genplay.core.manager.project.ProjectChromosomes;
import edu.yu.einstein.genplay.core.manager.project.ProjectManager;
import edu.yu.einstein.genplay.core.manager.project.ProjectWindow;
import edu.yu.einstein.genplay.core.manager.project.ProjectZoom;
import edu.yu.einstein.genplay.dataStructure.chromosome.Chromosome;
import edu.yu.einstein.genplay.dataStructure.genomeWindow.SimpleGenomeWindow;
import edu.yu.einstein.genplay.util.colors.Colors;
/**
* Panel that defines mouse listeners that modifies the genomic position.
* A list of drawers can be registered an instance of this class in order
* to draw on the {@link Graphics} context of this panel.
* The first elements of the list of drawers draw first.
* <br/><b>Warning:</b> Serialized objects of this class will not be compatible between different implementation of the JVM
* @author Julien Lajugie
*/
public final class GraphicsPanel extends JPanel implements Serializable, ComponentListener, MouseListener, MouseMotionListener, MouseWheelListener {
private static final long serialVersionUID = 4936439650634531249L;
private int mouseStartDragX = -1; // position of the mouse when start dragging
private Drawer[] drawers; // drawers that can draw on this panel
/**
* Creates an instance of {@link GraphicsPanel}
*/
public GraphicsPanel() {
super();
setBackground(Colors.TRACK_BACKGROUND);
addComponentListener(this);
addMouseListener(this);
addMouseMotionListener(this);
addMouseWheelListener(this);
}
@Override
public void componentHidden(ComponentEvent e) {}
@Override
public void componentMoved(ComponentEvent e) {}
@Override
public void componentResized(ComponentEvent e) {
// tells the project window manager that the track width changed
ProjectManager.getInstance().getProjectWindow().setTrackWidth(getWidth());
repaint();
}
@Override
public void componentShown(ComponentEvent e) {}
/**
* @return the drawers registered to this panel
*/
public Drawer[] getDrawer() {
return drawers;
}
@Override
public void mouseClicked(MouseEvent e) {
ScrollingManager scrollingManager = ScrollingManager.getInstance();
// double click on left button -> we center the track to the position where the double click occured
if (!scrollingManager.isScrollingEnabled() && SwingUtilities.isLeftMouseButton(e) && (e.getClickCount() == 2)) {
ProjectWindow projectWindow = ProjectManager.getInstance().getProjectWindow();
// distance between the cursor and the middle of the track
int screenWidth = e.getX() - (getWidth() / 2);
// compute the corresponding genomic distance
int genomeWidth = projectWindow.screenToGenomeWidth(screenWidth);
Chromosome chromo = projectWindow.getGenomeWindow().getChromosome();
int start = projectWindow.getGenomeWindow().getStart() + genomeWidth;
int stop = projectWindow.getGenomeWindow().getStop() + genomeWidth;
SimpleGenomeWindow newWindow = new SimpleGenomeWindow(chromo, start, stop);
if (((newWindow.getMiddlePosition()) >= 0) && (newWindow.getMiddlePosition() <= newWindow.getChromosome().getLength())) {
projectWindow.setGenomeWindow(newWindow);
}
} else if (SwingUtilities.isMiddleMouseButton(e)) { // wheel click -> we toggle the scrolling mode
scrollingManager.setScrollingEnabled(!scrollingManager.isScrollingEnabled());
if (scrollingManager.isScrollingEnabled()) {
// width between the cursor and the middle of the track
int screenWidth = e.getX() - (getWidth() / 2);
scrollingManager.setScrollingIntensity(screenWidth);
}
setCursor(null);
}
}
@Override
public void mouseDragged(MouseEvent e) {
// mouse dragged -> we scroll the track
if (SwingUtilities.isLeftMouseButton(e)) {
ProjectWindow projectWindow = ProjectManager.getInstance().getProjectWindow();
// distance between the current position of the cursor and the position where the dragging started
int screenWidth = mouseStartDragX - e.getX();
// compute the corresponding genomic distance
double genomeWidth = projectWindow.screenToGenomeWidth(Math.abs(screenWidth));
if (screenWidth < 0) {
genomeWidth *= -1;
}
if ((genomeWidth >= 1) || (genomeWidth <= -1)) {
Chromosome chromo = projectWindow.getGenomeWindow().getChromosome();
int start = projectWindow.getGenomeWindow().getStart() + (int) genomeWidth;
int stop = projectWindow.getGenomeWindow().getStop() + (int) genomeWidth;
SimpleGenomeWindow newWindow = new SimpleGenomeWindow(chromo, start, stop);
if (newWindow.getMiddlePosition() < ProjectChromosomes.FIRST_BASE_POSITION) {
start = ProjectChromosomes.FIRST_BASE_POSITION - (projectWindow.getGenomeWindow().getSize() / 2);
stop = start + projectWindow.getGenomeWindow().getSize();
newWindow = new SimpleGenomeWindow(chromo, start, stop);
} else if (newWindow.getMiddlePosition() > newWindow.getChromosome().getLength()) {
stop = newWindow.getChromosome().getLength() + (projectWindow.getGenomeWindow().getSize() / 2);
start = stop - projectWindow.getGenomeWindow().getSize();
newWindow = new SimpleGenomeWindow(chromo, start, stop);
}
projectWindow.setGenomeWindow(newWindow);
mouseStartDragX = e.getX();
}
}
}
@Override
public void mouseEntered(MouseEvent e) {
// set the cursor when the mouse enter a track
setCursor(TrackConstants.DEFAULT_CURSOR);
}
@Override
public void mouseExited(MouseEvent e) {}
@Override
public void mouseMoved(MouseEvent e) {
// if the scrolling mode is enable we update the intensity of the scrolling
// depending on how far the mouse is from the center of the track
ScrollingManager scrollingManager = ScrollingManager.getInstance();
if (scrollingManager.isScrollingEnabled()) {
// width between the cursor and the middle of the track
int screenWidth = e.getX() - (getWidth() / 2);
scrollingManager.setScrollingIntensity(screenWidth);
setCursor(null);
}
}
@Override
public void mousePressed(MouseEvent e) {
// we memorize the position of the mouse in case the user drag the track
if (SwingUtilities.isLeftMouseButton(e)) {
mouseStartDragX = e.getX();
}
}
@Override
public void mouseReleased(MouseEvent e) {}
/**
* Update the {@link SimpleGenomeWindow} when the mouse wheel is used
*/
@Override
public void mouseWheelMoved(MouseWheelEvent e) {
// mouse wheel rotated (without modifier) -> zoom in or out
if (e.getModifiers() == 0) {
ProjectWindow projectWindow = ProjectManager.getInstance().getProjectWindow();
ProjectZoom projectZoom = ProjectManager.getInstance().getProjectZoom();
int newZoom = 0;
int weelRotation = Math.abs(e.getWheelRotation());
boolean isZoomIn = e.getWheelRotation() < 0;
for (int i = 0; i < weelRotation; i++) {
if (isZoomIn) {
newZoom = projectZoom.getNextZoomIn(projectWindow.getGenomeWindow().getSize());
} else {
newZoom = projectZoom.getNextZoomOut(projectWindow.getGenomeWindow().getSize());
}
newZoom = Math.min(projectWindow.getGenomeWindow().getChromosome().getLength() * 2, newZoom);
}
Chromosome chromo = projectWindow.getGenomeWindow().getChromosome();
int start = (int)(projectWindow.getGenomeWindow().getMiddlePosition() - (newZoom / 2));
int stop = start + newZoom;
SimpleGenomeWindow newWindow = new SimpleGenomeWindow(chromo, start, stop);
projectWindow.setGenomeWindow(newWindow);
}
}
@Override
public void paintComponent(Graphics g) {
super.paintComponent(g);
if (drawers != null) {
// tell the drawers to draw
for (Drawer currentDrawer: drawers) {
g.setFont(TrackConstants.FONT_DEFAULT);
currentDrawer.draw(g, getWidth(), getHeight());
}
}
}
@Override
public void setCursor(Cursor cursor) {
ScrollingManager scrollingManager = ScrollingManager.getInstance();
if (scrollingManager.isScrollingLeft()) {
super.setCursor(TrackConstants.CURSOR_SCROLL_LEFT);
} else if (scrollingManager.isScrollingRight()) {
super.setCursor(TrackConstants.CURSOR_SCROLL_RIGHT);
} else {
super.setCursor(cursor);
}
}
/**
* Sets the drawers that will draw on this panel
* @param drawers drawers to set
*/
public void setDrawers(Drawer[] drawers) {
this.drawers = drawers;
}
@Override
public void setToolTipText(String text) {
super.setToolTipText(text);
Point locationOnScreen = MouseInfo.getPointerInfo().getLocation();
Point locationOnComponent = new Point(locationOnScreen);
SwingUtilities.convertPointFromScreen(locationOnComponent, this);
if (this.contains(locationOnComponent)) {
ToolTipManager.sharedInstance().mouseMoved(
new MouseEvent(this, -1, System.currentTimeMillis(), 0, locationOnComponent.x, locationOnComponent.y,
locationOnScreen.x, locationOnScreen.y, 0, false, 0));
}
}
}