/* 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; } } }