/*******************************************************************************
* 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.Dimension;
import java.awt.Font;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.Toolkit;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.awt.event.MouseMotionListener;
import java.util.ArrayList;
import java.util.List;
import javax.swing.JLabel;
import javax.swing.JPanel;
import edu.yu.einstein.genplay.gui.event.trackEvent.TrackEvent;
import edu.yu.einstein.genplay.gui.event.trackEvent.TrackEventType;
import edu.yu.einstein.genplay.gui.event.trackEvent.TrackEventsGenerator;
import edu.yu.einstein.genplay.gui.event.trackEvent.TrackListener;
import edu.yu.einstein.genplay.util.colors.Colors;
/**
* The handle of a track
* <br/><b>Warning:</b> Serialized objects of this class will not be compatible between different implementation of the JVM
* @author Julien Lajugie
*/
final class HandlePanel extends JPanel implements MouseListener, MouseMotionListener, TrackEventsGenerator {
private static final long serialVersionUID = -1942543548154386009L; // generated serial ID
private static final int MOVE_RESIZE_ZONE_HEIGHT = 10; // height of the resize zone
private static final String FONT_NAME = "ARIAL"; // name of the font
private static final int FONT_SIZE = 12; // size of the font
private final JLabel jlNumber; // label with the number of the track
private final List<TrackListener> trackListeners; // list of track listeners
private int startDragY = 0; // height of the mouse when start dragging
private int newHeight = 0; // seize of the track after resizing by dragging
private boolean isTrackDragged = false; // true if the user is dragging the track
private boolean isSelected = false; // true if the track is selected
private int number; // number of the track
/**
* Creates an instance of {@link HandlePanel}
* @param number number of the track
*/
HandlePanel(int number) {
this.number = number;
setBackground(Colors.TRACK_HANDLE_BACKGROUND);
setPreferredSize(new Dimension(TrackConstants.HANDLE_WIDTH, 0));
trackListeners = new ArrayList<TrackListener>();
addMouseListener(this);
addMouseMotionListener(this);
// Creates and add the number of the track
jlNumber = new JLabel(Integer.toString(number));
jlNumber.setFont(new Font(FONT_NAME, Font.PLAIN, FONT_SIZE));
setLayout(new GridBagLayout());
GridBagConstraints gbc = new GridBagConstraints();
gbc.anchor = GridBagConstraints.CENTER;
add(jlNumber, gbc);
}
@Override
public void addTrackListener(TrackListener trackListener) {
if (!trackListeners.contains(trackListener)) {
trackListeners.add(trackListener);
}
}
/**
* @return the height of the resizing when the handle is dragged
*/
int getNewHeight() {
return newHeight;
}
/**
* @return the number of the track
*/
int getNumber() {
return number;
}
@Override
public TrackListener[] getTrackListeners() {
TrackListener[] listeners = new TrackListener[trackListeners.size()];
return trackListeners.toArray(listeners);
}
/**
* @return true if the track is selected
*/
boolean isSelected() {
return isSelected;
}
/**
* Locks the handle
*/
void lock() {
setEnabled(false);
}
@Override
public void mouseClicked(MouseEvent arg0) {
if (isEnabled()) {
if (arg0.getButton() == MouseEvent.BUTTON1) {
boolean onEdge = (getHeight() - arg0.getY()) <= MOVE_RESIZE_ZONE_HEIGHT;
if (arg0.getClickCount() == 2) {
if (onEdge) {
notifyTrackListeners(TrackEventType.SIZE_SET_TO_DEFAULT);
} else {
setSelected(true);
notifyTrackListeners(TrackEventType.DOUBLE_CLICKED);
}
} else {
if (!onEdge) {
setSelected(!isSelected());
}
}
}
}
}
@Override
public void mouseDragged(MouseEvent arg0) {
if (startDragY != 0) {
// we compute the new size of the track
newHeight = (getHeight() + arg0.getY()) - startDragY;
// we make sure that the new size is not smaller than the minimum height
newHeight = Math.max(TrackConstants.MINIMUM_HEIGHT, newHeight);
// we notify the listeners that the size has been changed
notifyTrackListeners(TrackEventType.RESIZED);
// we reset the position where the dragging starts
startDragY = arg0.getY();
}
if (isTrackDragged) {
notifyTrackListeners(TrackEventType.DRAGGED);
}
}
@Override
public void mouseEntered(MouseEvent arg0) {}
/**
* Changes the background color
*/
@Override
public void mouseExited(MouseEvent arg0) {
if (isEnabled()) {
if (isSelected) {
setBackground(Colors.TRACK_HANDLE_SELECTED);
} else {
setBackground(Colors.TRACK_HANDLE_BACKGROUND);
}
}
}
@Override
public void mouseMoved(MouseEvent arg0) {
if (isEnabled()) {
if ((getHeight() - arg0.getY()) <= MOVE_RESIZE_ZONE_HEIGHT) {
if (arg0.getModifiers() == Toolkit.getDefaultToolkit().getMenuShortcutKeyMask()) {
setCursor(new Cursor(Cursor.MOVE_CURSOR));
} else {
setCursor(new Cursor(Cursor.N_RESIZE_CURSOR));
}
} else {
setCursor(new Cursor(Cursor.DEFAULT_CURSOR));
}
if ((!(arg0.getModifiers() == MouseEvent.MOUSE_DRAGGED))) {
setBackground(Colors.TRACK_HANDLE_ROLLOVER);
}
}
}
@Override
public void mousePressed(MouseEvent arg0) {
if (isEnabled()) {
if (arg0.isPopupTrigger()) {
setSelected(true);
notifyTrackListeners(TrackEventType.POPUP_TRIGGERED);
} else if (arg0.getButton() == MouseEvent.BUTTON1) {
if ((getHeight() - arg0.getY()) <= MOVE_RESIZE_ZONE_HEIGHT) {
startDragY = arg0.getY();
} else {
isTrackDragged = true;
}
}
}
}
@Override
public void mouseReleased(MouseEvent arg0) {
startDragY = 0;
if (isTrackDragged) {
isTrackDragged = false;
notifyTrackListeners(TrackEventType.RELEASED);
} else if (arg0.isPopupTrigger()) {
setSelected(true);
notifyTrackListeners(TrackEventType.POPUP_TRIGGERED);
}
}
/**
* Notify all the track listener that the track changed
* @param trackEventType track event type
*/
public void notifyTrackListeners(TrackEventType trackEventType) {
if (trackListeners != null) {
TrackEvent trackEvent = new TrackEvent(this, trackEventType);
for (TrackListener listener: trackListeners) {
listener.trackChanged(trackEvent);
}
}
}
@Override
public void removeTrackListener(TrackListener trackListener) {
trackListeners.remove(trackListener);
}
/**
* @param number the number of the track to set
*/
void setNumber(int number) {
this.number = number;
jlNumber.setText(Integer.toString(number));
}
/**
* @param selected the value to set
*/
void setSelected(boolean selected) {
if (selected != isSelected()) {
isSelected = selected;
if (selected) {
setBackground(Colors.TRACK_HANDLE_ROLLOVER);
notifyTrackListeners(TrackEventType.SELECTED);
} else {
setBackground(Colors.TRACK_HANDLE_BACKGROUND);
notifyTrackListeners(TrackEventType.UNSELECTED);
}
}
}
/**
* Unlocks the handle
*/
void unlock() {
setEnabled(true);
if (isSelected) {
setBackground(Colors.TRACK_HANDLE_ROLLOVER);
} else {
setBackground(Colors.TRACK_HANDLE_BACKGROUND);
}
}
}