package org.jabref.gui; import java.awt.AlphaComposite; import java.awt.Component; import java.awt.Font; import java.awt.Graphics; import java.awt.Graphics2D; import java.awt.Point; import java.awt.Rectangle; 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; /** * Extends the JTabbedPane class to support Drag&Drop of Tabs. * * @author kleinms, strassfn */ class DragDropPane extends JTabbedPane { private boolean draggingState; // State var if we are at dragging or not private int indexDraggedTab; // The index of the tab we drag at the moment private final MarkerPane markerPane; // The glass panel for painting the position marker DragDropPane() { super(); indexDraggedTab = -1; markerPane = new MarkerPane(); markerPane.setVisible(false); // ------------------------------------------- // Adding listeners for Drag&Drop Actions // ------------------------------------------- addMouseMotionListener(new MouseMotionAdapter() { @Override 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 at tab dragging 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(); } } else { //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(); } } super.mouseDragged(e); } }); addMouseListener(new MouseAdapter() { @Override 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 dragging 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()))) { newTabPos = indexActTab; } else { newTabPos = indexActTab + 1; } } else { //We are dragging the tab to the right of the old position if (toTheLeft && (indexActTab > 0)) { 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. * */ static class MarkerPane extends JPanel { private Point locationP; private final IconTheme.JabRefIcon moveTabArrow; public MarkerPane() { setOpaque(false); // Sets the marker fontIcon moveTabArrow = IconTheme.JabRefIcon.MOVE_TAB_ARROW; } @Override public void paintComponent(Graphics g) { super.paintComponent(g); Graphics2D g2 = (Graphics2D) g; g2.setComposite(AlphaComposite.getInstance( AlphaComposite.SRC_OVER, 0.9f)); // Set transparency g.setFont(IconTheme.FONT.deriveFont(Font.BOLD, 24f)); g.drawString(moveTabArrow.getCode(), locationP.x - (moveTabArrow.getIcon().getIconWidth() / 2), locationP.y + (moveTabArrow.getIcon().getIconHeight() / 2)); } /** * 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; } } }