/* Copyright (C) 2003-2011 JabRef contributors.
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 2 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, write to the Free Software Foundation, Inc.,
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
package net.sf.jabref.gui;
import java.awt.AlphaComposite;
import java.awt.Component;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Image;
import java.awt.Point;
import java.awt.Rectangle;
import java.awt.Toolkit;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.event.MouseMotionAdapter;
import javax.swing.JPanel;
import javax.swing.JTabbedPane;
import javax.swing.SwingUtilities;
import net.sf.jabref.GUIGlobals;
/**
* Extends the JTabbedPane class to support Drag&Drop of Tabs.
*
* @author kleinms, strassfn
*/
public class DragDropPane extends JTabbedPane {
private boolean draggingState = false; // State var if we are at dragging or not
private int indexDraggedTab; // The index of the tab we drag at the moment
MarkerPane markerPane; // The glass panel for painting the position marker
public DragDropPane() {
super();
indexDraggedTab = -1;
markerPane = new MarkerPane();
markerPane.setVisible(false);
// -------------------------------------------
// Adding listeners for Drag&Drop Actions
// -------------------------------------------
addMouseMotionListener(new MouseMotionAdapter() {
public void mouseDragged(MouseEvent e) { // Mouse is dragging
// Calculates the tab index based on the mouse position
int indexActTab = getUI().tabForCoordinate(DragDropPane.this,
e.getX(), e.getY());
if (!draggingState) { // We are not at tab dragging
if (indexActTab >= 0) { // Mouse is above a tab, otherwise tabNumber would be -1
// -->Now we are at tab tragging
draggingState = true; // Mark now we are at dragging
indexDraggedTab = indexActTab; // Set draggedTabIndex to the tabNumber where we are now
repaint();
}
} else { //We are at tab tragging
if (indexDraggedTab >= 0 && indexActTab >= 0) { //Is it a valid scenario?
boolean toTheLeft = e.getX() <= getUI().getTabBounds(DragDropPane.this, indexActTab).getCenterX(); //Go to the left or to the right of the actual Tab
DragDropPane.this.getRootPane().setGlassPane(markerPane); //Set the MarkerPane as glass Pane
Rectangle actTabRect = SwingUtilities.convertRectangle(DragDropPane.this, getBoundsAt(indexActTab),
DragDropPane.this.markerPane); //Rectangle with the same dimensions as the tab at the mouse position
if (toTheLeft)
markerPane.setPicLocation(new Point(actTabRect.x, actTabRect.y
+ actTabRect.height)); //Set pic to the left of the tab at the mouse position
else
markerPane.setPicLocation(new Point(actTabRect.x + actTabRect.width, actTabRect.y
+ actTabRect.height)); //Set pic to the right of the tab at the mouse position
markerPane.setVisible(true);
markerPane.repaint();
repaint();
} else { //We have no valid tab tragging scenario
markerPane.setVisible(false);
markerPane.repaint();
}
}
super.mouseDragged(e);
}
});
addMouseListener(new MouseAdapter() {
public void mouseReleased(MouseEvent e) {
DragDropPane.this.markerPane.setVisible(false); //Set MarkerPane invisible
int indexActTab = getUI().tabForCoordinate(DragDropPane.this,
e.getX(), e.getY());
if (indexDraggedTab >= 0 && indexActTab >= 0 && indexDraggedTab != indexActTab) { //Is it a valid scenario?
if (draggingState) { //We are at tab tragging
boolean toTheLeft = e.getX() <= getUI().getTabBounds(DragDropPane.this, indexActTab).getCenterX(); //Go to the left or to the right of the actual Tab
DragDropPane.this.markerPane.setVisible(false);
Component actTab = getComponentAt(indexDraggedTab); //Save dragged tab
String actTabTitle = getTitleAt(indexDraggedTab); //Save Title of the dragged tab
removeTabAt(indexDraggedTab); //Remove dragged tab
int newTabPos;
if(indexActTab < indexDraggedTab) { //We are dragging the tab to the left of its the position
if(toTheLeft && indexActTab<(DragDropPane.this.getTabCount())) // The mouse is at the left side of a tab except the last one
newTabPos = indexActTab;
else
newTabPos = indexActTab+1;
}
else { //We are dragging the tab to the right of the old position
if(toTheLeft && indexActTab>0) // The mouse is at the left side of a tab except the first one
newTabPos = indexActTab-1;
else
newTabPos = indexActTab;
}
insertTab(actTabTitle, null, actTab, null, newTabPos); //Insert dragged tab at new position
DragDropPane.this.setSelectedIndex(newTabPos); //Set selection back to the tab (at the new tab position
}
}
draggingState = false;
}
});
}
/**
* A glass panel which sets the marker for Dragging of Tabs.
*
*/
class MarkerPane extends JPanel {
private Point locationP;
private Image markerImg;
public MarkerPane() {
setOpaque(false);
markerImg = Toolkit.getDefaultToolkit().getImage(
GUIGlobals.getIconUrl("dragNdropArrow")); // Sets the marker image
}
@Override
public void paintComponent(Graphics g) {
((Graphics2D) g).setComposite(AlphaComposite.getInstance(
AlphaComposite.SRC_OVER, 0.9f)); // Set transparency
g.drawImage(markerImg, locationP.x - (markerImg.getWidth(null) / 2),
locationP.y, null); // draw the image at the middle of the given location
}
/**
* Sets the new location, where the marker should be placed.
*
* @param pt the point for the marker
*/
public void setPicLocation(Point pt) {
this.locationP = pt;
}
}
}