tags:

views:

2479

answers:

4

How do I implement a draggable tab using Java Swing? Instead of the static JTabbedPane I would like to drag-and-drop a tab to different position to rearrange the tabs.

EDIT: The Java Tutorials - Drag and Drop and Data Transfer.

+4  A: 

Found this code out there on the tubes:

class DnDTabbedPane extends JTabbedPane {
  private static final int LINEWIDTH = 3;
  private static final String NAME = "test";
  private final GhostGlassPane glassPane = new GhostGlassPane();
  private final Rectangle2D lineRect   = new Rectangle2D.Double();
  private final Color     lineColor  = new Color(0, 100, 255);
  //private final DragSource dragSource  = new DragSource();
  //private final DropTarget dropTarget;
  private int dragTabIndex = -1;

  public DnDTabbedPane() {
    super();
    final DragSourceListener dsl = new DragSourceListener() {
      public void dragEnter(DragSourceDragEvent e) {
        e.getDragSourceContext().setCursor(DragSource.DefaultMoveDrop);
      }
      public void dragExit(DragSourceEvent e) {
        e.getDragSourceContext().setCursor(DragSource.DefaultMoveNoDrop);
        lineRect.setRect(0,0,0,0);
        glassPane.setPoint(new Point(-1000,-1000));
        glassPane.repaint();
      }
      public void dragOver(DragSourceDragEvent e) {
        //e.getLocation()
        //This method returns a Point indicating the cursor location in screen coordinates at the moment
        Point tabPt = e.getLocation();
        SwingUtilities.convertPointFromScreen(tabPt, DnDTabbedPane.this);
        Point glassPt = e.getLocation();
        SwingUtilities.convertPointFromScreen(glassPt, glassPane);
        int targetIdx = getTargetTabIndex(glassPt);
        if(getTabAreaBound().contains(tabPt) && targetIdx>=0 &&
           targetIdx!=dragTabIndex && targetIdx!=dragTabIndex+1) {
          e.getDragSourceContext().setCursor(DragSource.DefaultMoveDrop);
        }else{
          e.getDragSourceContext().setCursor(DragSource.DefaultMoveNoDrop);
        }
      }
      public void dragDropEnd(DragSourceDropEvent e) {
        lineRect.setRect(0,0,0,0);
        dragTabIndex = -1;
        if(hasGhost()) {
          glassPane.setVisible(false);
          glassPane.setImage(null);
        }
      }
      public void dropActionChanged(DragSourceDragEvent e) {}
    };
    final Transferable t = new Transferable() {
      private final DataFlavor FLAVOR = new DataFlavor(DataFlavor.javaJVMLocalObjectMimeType, NAME);
      public Object getTransferData(DataFlavor flavor) {
        return DnDTabbedPane.this;
      }
      public DataFlavor[] getTransferDataFlavors() {
        DataFlavor[] f = new DataFlavor[1];
        f[0] = this.FLAVOR;
        return f;
      }
      public boolean isDataFlavorSupported(DataFlavor flavor) {
        return flavor.getHumanPresentableName().equals(NAME);
      }
    };
    final DragGestureListener dgl = new DragGestureListener() {
      public void dragGestureRecognized(DragGestureEvent e) {
        Point tabPt = e.getDragOrigin();
        dragTabIndex = indexAtLocation(tabPt.x, tabPt.y);
        if(dragTabIndex<0) return;
        initGlassPane(e.getComponent(), e.getDragOrigin());
        try{
          e.startDrag(DragSource.DefaultMoveDrop, t, dsl);
        }catch(InvalidDnDOperationException idoe) {
          idoe.printStackTrace();
        }
      }
    };
    //dropTarget =
    new DropTarget(glassPane, DnDConstants.ACTION_COPY_OR_MOVE, new CDropTargetListener(), true);
    new DragSource().createDefaultDragGestureRecognizer(this, DnDConstants.ACTION_COPY_OR_MOVE, dgl);
  }

  class CDropTargetListener implements DropTargetListener{
    public void dragEnter(DropTargetDragEvent e) {
      if(isDragAcceptable(e)) e.acceptDrag(e.getDropAction());
      else e.rejectDrag();
    }
    public void dragExit(DropTargetEvent e) {}
    public void dropActionChanged(DropTargetDragEvent e) {}
    public void dragOver(final DropTargetDragEvent e) {
      if(getTabPlacement()==JTabbedPane.TOP || getTabPlacement()==JTabbedPane.BOTTOM) {
        initTargetLeftRightLine(getTargetTabIndex(e.getLocation()));
      }else{
        initTargetTopBottomLine(getTargetTabIndex(e.getLocation()));
      }
      repaint();
      if(hasGhost()) {
        glassPane.setPoint(e.getLocation());
        glassPane.repaint();
      }
    }

    public void drop(DropTargetDropEvent e) {
      if(isDropAcceptable(e)) {
        convertTab(dragTabIndex, getTargetTabIndex(e.getLocation()));
        e.dropComplete(true);
      }else{
        e.dropComplete(false);
      }
      repaint();
    }
    public boolean isDragAcceptable(DropTargetDragEvent e) {
      Transferable t = e.getTransferable();
      if(t==null) return false;
      DataFlavor[] f = e.getCurrentDataFlavors();
      if(t.isDataFlavorSupported(f[0]) && dragTabIndex>=0) {
        return true;
      }
      return false;
    }
    public boolean isDropAcceptable(DropTargetDropEvent e) {
      Transferable t = e.getTransferable();
      if(t==null) return false;
      DataFlavor[] f = t.getTransferDataFlavors();
      if(t.isDataFlavorSupported(f[0]) && dragTabIndex>=0) {
        return true;
      }
      return false;
    }
  }

  private boolean hasGhost = true;
  public void setPaintGhost(boolean flag) {
    hasGhost = flag;
  }
  public boolean hasGhost() {
    return hasGhost;
  }
  private int getTargetTabIndex(Point glassPt) {
    Point tabPt = SwingUtilities.convertPoint(glassPane, glassPt, DnDTabbedPane.this);
    boolean isTB = getTabPlacement()==JTabbedPane.TOP || getTabPlacement()==JTabbedPane.BOTTOM;
    for(int i=0;i<getTabCount();i++) {
      Rectangle r = getBoundsAt(i);
      if(isTB) r.setRect(r.x-r.width/2, r.y,  r.width, r.height);
      else   r.setRect(r.x, r.y-r.height/2, r.width, r.height);
      if(r.contains(tabPt)) return i;
    }
    Rectangle r = getBoundsAt(getTabCount()-1);
    if(isTB) r.setRect(r.x+r.width/2, r.y,  r.width, r.height);
    else   r.setRect(r.x, r.y+r.height/2, r.width, r.height);
    return   r.contains(tabPt)?getTabCount():-1;
  }
  private void convertTab(int prev, int next) {
    if(next<0 || prev==next) {
      //System.out.println("press="+prev+" next="+next);
      return;
    }
    Component cmp = getComponentAt(prev);
    String str = getTitleAt(prev);
    if(next==getTabCount()) {
      //System.out.println("last: press="+prev+" next="+next);
      remove(prev);
      addTab(str, cmp);
      setSelectedIndex(getTabCount()-1);
    }else if(prev>next) {
      //System.out.println("   >: press="+prev+" next="+next);
      remove(prev);
      insertTab(str, null, cmp, null, next);
      setSelectedIndex(next);
    }else{
      //System.out.println("   <: press="+prev+" next="+next);
      remove(prev);
      insertTab(str, null, cmp, null, next-1);
      setSelectedIndex(next-1);
    }
  }

  private void initTargetLeftRightLine(int next) {
    if(next<0 || dragTabIndex==next || next-dragTabIndex==1) {
      lineRect.setRect(0,0,0,0);
    }else if(next==getTabCount()) {
      Rectangle rect = getBoundsAt(getTabCount()-1);
      lineRect.setRect(rect.x+rect.width-LINEWIDTH/2,rect.y,LINEWIDTH,rect.height);
    }else if(next==0) {
      Rectangle rect = getBoundsAt(0);
      lineRect.setRect(-LINEWIDTH/2,rect.y,LINEWIDTH,rect.height);
    }else{
      Rectangle rect = getBoundsAt(next-1);
      lineRect.setRect(rect.x+rect.width-LINEWIDTH/2,rect.y,LINEWIDTH,rect.height);
    }
  }
  private void initTargetTopBottomLine(int next) {
    if(next<0 || dragTabIndex==next || next-dragTabIndex==1) {
      lineRect.setRect(0,0,0,0);
    }else if(next==getTabCount()) {
      Rectangle rect = getBoundsAt(getTabCount()-1);
      lineRect.setRect(rect.x,rect.y+rect.height-LINEWIDTH/2,rect.width,LINEWIDTH);
    }else if(next==0) {
      Rectangle rect = getBoundsAt(0);
      lineRect.setRect(rect.x,-LINEWIDTH/2,rect.width,LINEWIDTH);
    }else{
      Rectangle rect = getBoundsAt(next-1);
      lineRect.setRect(rect.x,rect.y+rect.height-LINEWIDTH/2,rect.width,LINEWIDTH);
    }
  }

  private void initGlassPane(Component c, Point tabPt) {
    //Point p = (Point) pt.clone();
    getRootPane().setGlassPane(glassPane);
    if(hasGhost()) {
      Rectangle rect = getBoundsAt(dragTabIndex);
      BufferedImage image = new BufferedImage(c.getWidth(), c.getHeight(), BufferedImage.TYPE_INT_ARGB);
      Graphics g = image.getGraphics();
      c.paint(g);
      image = image.getSubimage(rect.x,rect.y,rect.width,rect.height);
      glassPane.setImage(image);
    }
    Point glassPt = SwingUtilities.convertPoint(c, tabPt, glassPane);
    glassPane.setPoint(glassPt);
    glassPane.setVisible(true);
  }

  private Rectangle getTabAreaBound() {
    Rectangle lastTab  = getUI().getTabBounds(this, getTabCount()-1);
    return new Rectangle(0,0,getWidth(),lastTab.y+lastTab.height);
  }

  public void paintComponent(Graphics g) {
    super.paintComponent(g);
    if(dragTabIndex>=0) {
      Graphics2D g2 = (Graphics2D)g;
      g2.setPaint(lineColor);
      g2.fill(lineRect);
    }
  }
}

class GhostGlassPane extends JPanel {
  private final AlphaComposite composite;
  private Point location = new Point(0, 0);
  private BufferedImage draggingGhost = null;
  public GhostGlassPane() {
    setOpaque(false);
    composite = AlphaComposite.getInstance(AlphaComposite.SRC_OVER, 0.5f);
  }
  public void setImage(BufferedImage draggingGhost) {
    this.draggingGhost = draggingGhost;
  }
  public void setPoint(Point location) {
    this.location = location;
  }
  public void paintComponent(Graphics g) {
    if(draggingGhost == null) return;
    Graphics2D g2 = (Graphics2D) g;
    g2.setComposite(composite);
    double xx = location.getX() - (draggingGhost.getWidth(this) /2d);
    double yy = location.getY() - (draggingGhost.getHeight(this)/2d);
    g2.drawImage(draggingGhost, (int)xx, (int)yy , null);
  }
}
jodonnell
Could you add link to the source? http://java-swing-tips.blogspot.com/2008/04/drag-and-drop-tabs-in-jtabbedpane.html
eed3si9n
Done. You're right, good to cite the source.
jodonnell
I actually knew about this one, and I was curious about the alternatives. For now, I'll accept your answer.
eed3si9n
+11  A: 
Tom Martin
You deserve a +1 for the effort :)
eed3si9n
+1! It worked, but it's a little buggy. If you drag the tab too it makes a mess.
Marcio Aguiar
+1  A: 

I liked Terai Atsuhiro san's DnDTabbedPane, but I wanted more from it. The original Terai implementation transfered tabs within the TabbedPane, but it would be nicer if I could drag from one TabbedPane to another.

Inspired by @Tom's effort, I decided to modify the code myself. There are some details I added. For example, the ghost tab now slides along the tabbed pane instead of moving together with the mouse.

setAcceptor(TabAcceptor a_acceptor) should let the consumer code decide whether to let one tab transfer from one tabbed pane to another. The default acceptor always returns true.

/** Modified DnDTabbedPane.java
 * http://java-swing-tips.blogspot.com/2008/04/drag-and-drop-tabs-in-jtabbedpane.html
 * originally written by Terai Atsuhiro.
 * so that tabs can be transfered from one pane to another.
 * eed3si9n.
 */

import java.awt.*;
import java.awt.datatransfer.*;
import java.awt.dnd.*;
import java.awt.geom.*;
import java.awt.image.*;
import javax.swing.*;

public class DnDTabbedPane extends JTabbedPane {
 public static final long serialVersionUID = 1L;
 private static final int LINEWIDTH = 3;
 private static final String NAME = "TabTransferData";
 private final DataFlavor FLAVOR = new DataFlavor(
   DataFlavor.javaJVMLocalObjectMimeType, NAME);
 private static GhostGlassPane s_glassPane = new GhostGlassPane();

 private boolean m_isDrawRect = false;
 private final Rectangle2D m_lineRect = new Rectangle2D.Double();

 private final Color m_lineColor = new Color(0, 100, 255);
 private TabAcceptor m_acceptor = null;

 public DnDTabbedPane() {
  super();
  final DragSourceListener dsl = new DragSourceListener() {
   public void dragEnter(DragSourceDragEvent e) {
    e.getDragSourceContext().setCursor(DragSource.DefaultMoveDrop);
   }

   public void dragExit(DragSourceEvent e) {
    e.getDragSourceContext()
      .setCursor(DragSource.DefaultMoveNoDrop);
    m_lineRect.setRect(0, 0, 0, 0);
    m_isDrawRect = false;
    s_glassPane.setPoint(new Point(-1000, -1000));
    s_glassPane.repaint();
   }

   public void dragOver(DragSourceDragEvent e) {
    //e.getLocation()
    //This method returns a Point indicating the cursor location in screen coordinates at the moment

    TabTransferData data = getTabTransferData(e);
    if (data == null) {
     e.getDragSourceContext().setCursor(
       DragSource.DefaultMoveNoDrop);
     return;
    } // if

    /*
    Point tabPt = e.getLocation();
    SwingUtilities.convertPointFromScreen(tabPt, DnDTabbedPane.this);
    if (DnDTabbedPane.this.contains(tabPt)) {
     int targetIdx = getTargetTabIndex(tabPt);
     int sourceIndex = data.getTabIndex();
     if (getTabAreaBound().contains(tabPt)
       && (targetIdx >= 0)
       && (targetIdx != sourceIndex)
       && (targetIdx != sourceIndex + 1)) {
      e.getDragSourceContext().setCursor(
        DragSource.DefaultMoveDrop);

      return;
     } // if

     e.getDragSourceContext().setCursor(
       DragSource.DefaultMoveNoDrop);
     return;
    } // if
    */

    e.getDragSourceContext().setCursor(
      DragSource.DefaultMoveDrop);
   }

   public void dragDropEnd(DragSourceDropEvent e) {
    m_isDrawRect = false;
    m_lineRect.setRect(0, 0, 0, 0);
    // m_dragTabIndex = -1;

    if (hasGhost()) {
     s_glassPane.setVisible(false);
     s_glassPane.setImage(null);
    }
   }

   public void dropActionChanged(DragSourceDragEvent e) {
   }
  };

  final DragGestureListener dgl = new DragGestureListener() {
   public void dragGestureRecognized(DragGestureEvent e) {
    // System.out.println("dragGestureRecognized");

    Point tabPt = e.getDragOrigin();
    int dragTabIndex = indexAtLocation(tabPt.x, tabPt.y);
    if (dragTabIndex < 0) {
     return;
    } // if

    initGlassPane(e.getComponent(), e.getDragOrigin(), dragTabIndex);
    try {
     e.startDrag(DragSource.DefaultMoveDrop, 
       new TabTransferable(DnDTabbedPane.this, dragTabIndex), dsl);
    } catch (InvalidDnDOperationException idoe) {
     idoe.printStackTrace();
    }
   }
  };

  //dropTarget =
  new DropTarget(this, DnDConstants.ACTION_COPY_OR_MOVE,
    new CDropTargetListener(), true);
  new DragSource().createDefaultDragGestureRecognizer(this,
    DnDConstants.ACTION_COPY_OR_MOVE, dgl);
  m_acceptor = new TabAcceptor() {
   public boolean isDropAcceptable(DnDTabbedPane a_component, int a_index) {
    return true;
   }
  };
 }

 public TabAcceptor getAcceptor() {
  return m_acceptor;
 }

 public void setAcceptor(TabAcceptor a_value) {
  m_acceptor = a_value;
 }

 private TabTransferData getTabTransferData(DropTargetDropEvent a_event) {  
  try {
   TabTransferData data = (TabTransferData) a_event.getTransferable().getTransferData(FLAVOR);    
   return data;
  } catch (Exception e) {
   e.printStackTrace();
  }

  return null;
 }

 private TabTransferData getTabTransferData(DropTargetDragEvent a_event) {
  try {
   TabTransferData data = (TabTransferData) a_event.getTransferable().getTransferData(FLAVOR);    
   return data;
  } catch (Exception e) {
   e.printStackTrace();
  }

  return null;
 }

 private TabTransferData getTabTransferData(DragSourceDragEvent a_event) {
  try {
   TabTransferData data = (TabTransferData) a_event.getDragSourceContext()
    .getTransferable().getTransferData(FLAVOR);    
   return data;
  } catch (Exception e) {
   e.printStackTrace();
  }

  return null;  
 }

 class TabTransferable implements Transferable {
  private TabTransferData m_data = null;

  public TabTransferable(DnDTabbedPane a_tabbedPane, int a_tabIndex) {
   m_data = new TabTransferData(DnDTabbedPane.this, a_tabIndex);
  }

  public Object getTransferData(DataFlavor flavor) {
   return m_data;
   // return DnDTabbedPane.this;
  }

  public DataFlavor[] getTransferDataFlavors() {
   DataFlavor[] f = new DataFlavor[1];
   f[0] = FLAVOR;
   return f;
  }

  public boolean isDataFlavorSupported(DataFlavor flavor) {
   return flavor.getHumanPresentableName().equals(NAME);
  }  
 }

 class TabTransferData {
  private DnDTabbedPane m_tabbedPane = null;
  private int m_tabIndex = -1;

  public TabTransferData() {
  }

  public TabTransferData(DnDTabbedPane a_tabbedPane, int a_tabIndex) {
   m_tabbedPane = a_tabbedPane;
   m_tabIndex = a_tabIndex;
  }

  public DnDTabbedPane getTabbedPane() {
   return m_tabbedPane;
  }

  public void setTabbedPane(DnDTabbedPane pane) {
   m_tabbedPane = pane;
  }

  public int getTabIndex() {
   return m_tabIndex;
  }

  public void setTabIndex(int index) {
   m_tabIndex = index;
  }
 }

 private Point buildGhostLocation(Point a_location) {
  Point retval = new Point(a_location);

  switch (getTabPlacement()) {
   case JTabbedPane.TOP: {
    retval.y = 1;
    retval.x -= s_glassPane.getGhostWidth() / 2;
   } break;

   case JTabbedPane.BOTTOM: {
    retval.y = getHeight() - 1 - s_glassPane.getGhostHeight();
    retval.x -= s_glassPane.getGhostWidth() / 2;
   } break;

   case JTabbedPane.LEFT: {
    retval.x = 1;
    retval.y -= s_glassPane.getGhostHeight() / 2;
   } break;

   case JTabbedPane.RIGHT: {
    retval.x = getWidth() - 1 - s_glassPane.getGhostWidth();
    retval.y -= s_glassPane.getGhostHeight() / 2;
   } break;
  } // switch

  retval = SwingUtilities.convertPoint(DnDTabbedPane.this,
    retval, s_glassPane);
  return retval;
 }

 class CDropTargetListener implements DropTargetListener {
  public void dragEnter(DropTargetDragEvent e) {
   // System.out.println("DropTarget.dragEnter: " + DnDTabbedPane.this);

   if (isDragAcceptable(e)) {
    e.acceptDrag(e.getDropAction());
   } else {
    e.rejectDrag();
   } // if
  }

  public void dragExit(DropTargetEvent e) {
   // System.out.println("DropTarget.dragExit: " + DnDTabbedPane.this);
   m_isDrawRect = false;
  }

  public void dropActionChanged(DropTargetDragEvent e) {
  }

  public void dragOver(final DropTargetDragEvent e) {
   TabTransferData data = getTabTransferData(e);

   if (getTabPlacement() == JTabbedPane.TOP
     || getTabPlacement() == JTabbedPane.BOTTOM) {
    initTargetLeftRightLine(getTargetTabIndex(e.getLocation()), data);
   } else {
    initTargetTopBottomLine(getTargetTabIndex(e.getLocation()), data);
   } // if-else

   repaint();
   if (hasGhost()) {
    s_glassPane.setPoint(buildGhostLocation(e.getLocation()));
    s_glassPane.repaint();
   }
  }

  public void drop(DropTargetDropEvent a_event) {
   // System.out.println("DropTarget.drop: " + DnDTabbedPane.this);

   if (isDropAcceptable(a_event)) {
    convertTab(getTabTransferData(a_event),
     getTargetTabIndex(a_event.getLocation()));
    a_event.dropComplete(true);
   } else {
    a_event.dropComplete(false);
   } // if-else

   m_isDrawRect = false;
   repaint();
  }

  public boolean isDragAcceptable(DropTargetDragEvent e) {
   Transferable t = e.getTransferable();
   if (t == null) {
    return false;
   } // if

   DataFlavor[] flavor = e.getCurrentDataFlavors();
   if (!t.isDataFlavorSupported(flavor[0])) {
    return false;
   } // if

   TabTransferData data = getTabTransferData(e);

   if (DnDTabbedPane.this == data.getTabbedPane()
     && data.getTabIndex() >= 0) {
    return true;
   } // if

   if (DnDTabbedPane.this != data.getTabbedPane()) {
    if (m_acceptor != null) {
     return m_acceptor.isDropAcceptable(data.getTabbedPane(), data.getTabIndex());
    } // if
   } // if

   return false;
  }

  public boolean isDropAcceptable(DropTargetDropEvent e) {
   Transferable t = e.getTransferable();
   if (t == null) {
    return false;
   } // if

   DataFlavor[] flavor = e.getCurrentDataFlavors();
   if (!t.isDataFlavorSupported(flavor[0])) {
    return false;
   } // if

   TabTransferData data = getTabTransferData(e);

   if (DnDTabbedPane.this == data.getTabbedPane()
     && data.getTabIndex() >= 0) {
    return true;
   } // if

   if (DnDTabbedPane.this != data.getTabbedPane()) {
    if (m_acceptor != null) {
     return m_acceptor.isDropAcceptable(data.getTabbedPane(), data.getTabIndex());
    } // if
   } // if

   return false;
  }
 }

 private boolean m_hasGhost = true;

 public void setPaintGhost(boolean flag) {
  m_hasGhost = flag;
 }

 public boolean hasGhost() {
  return m_hasGhost;
 }

 /**
  * returns potential index for drop.
  * @param a_point point given in the drop site component's coordinate
  * @return returns potential index for drop.
  */
 private int getTargetTabIndex(Point a_point) {
  boolean isTopOrBottom = getTabPlacement() == JTabbedPane.TOP
    || getTabPlacement() == JTabbedPane.BOTTOM;

  // if the pane is empty, the target index is always zero.
  if (getTabCount() == 0) {
   return 0;
  } // if

  for (int i = 0; i < getTabCount(); i++) {
   Rectangle r = getBoundsAt(i);
   if (isTopOrBottom) {
    r.setRect(r.x - r.width / 2, r.y, r.width, r.height);
   } else {
    r.setRect(r.x, r.y - r.height / 2, r.width, r.height);
   } // if-else

   if (r.contains(a_point)) {
    return i;
   } // if
  } // for

  Rectangle r = getBoundsAt(getTabCount() - 1);
  if (isTopOrBottom) {
   int x = r.x + r.width / 2;
   r.setRect(x, r.y, getWidth() - x, r.height);
  } else {
   int y = r.y + r.height / 2;
   r.setRect(r.x, y, r.width, getHeight() - y);
  } // if-else

  return r.contains(a_point) ? getTabCount() : -1;
 }

 private void convertTab(TabTransferData a_data, int a_targetIndex) {
  DnDTabbedPane source = a_data.getTabbedPane();
  int sourceIndex = a_data.getTabIndex();
  if (sourceIndex < 0) {
   return;
  } // if

  Component cmp = source.getComponentAt(sourceIndex);
  String str = source.getTitleAt(sourceIndex);
  if (this != source) {
   source.remove(sourceIndex);

   if (a_targetIndex == getTabCount()) {
    addTab(str, cmp);
   } else {
    if (a_targetIndex < 0) {
     a_targetIndex = 0;
    } // if

    insertTab(str, null, cmp, null, a_targetIndex);

   } // if

   setSelectedComponent(cmp);
   // System.out.println("press="+sourceIndex+" next="+a_targetIndex);
   return;
  } // if

  if (a_targetIndex < 0 || sourceIndex == a_targetIndex) {
   //System.out.println("press="+prev+" next="+next);
   return;
  } // if

  if (a_targetIndex == getTabCount()) {
   //System.out.println("last: press="+prev+" next="+next);
   source.remove(sourceIndex);
   addTab(str, cmp);
   setSelectedIndex(getTabCount() - 1);
  } else if (sourceIndex > a_targetIndex) {
   //System.out.println("   >: press="+prev+" next="+next);
   source.remove(sourceIndex);
   insertTab(str, null, cmp, null, a_targetIndex);
   setSelectedIndex(a_targetIndex);
  } else {
   //System.out.println("   <: press="+prev+" next="+next);
   source.remove(sourceIndex);
   insertTab(str, null, cmp, null, a_targetIndex - 1);
   setSelectedIndex(a_targetIndex - 1);
  }
 }

 private void initTargetLeftRightLine(int next, TabTransferData a_data) {  
  if (next < 0) {
   m_lineRect.setRect(0, 0, 0, 0);
   m_isDrawRect = false;
   return;
  } // if

  if ((a_data.getTabbedPane() == this)
    && (a_data.getTabIndex() == next
    || next - a_data.getTabIndex() == 1)) {
   m_lineRect.setRect(0, 0, 0, 0);
   m_isDrawRect = false;
  } else if (getTabCount() == 0) {
   m_lineRect.setRect(0, 0, 0, 0);
   m_isDrawRect = false;
   return;
  } else if (next == 0) {
   Rectangle rect = getBoundsAt(0);
   m_lineRect.setRect(-LINEWIDTH / 2, rect.y, LINEWIDTH, rect.height);
   m_isDrawRect = true;
  } else if (next == getTabCount()) {
   Rectangle rect = getBoundsAt(getTabCount() - 1);
   m_lineRect.setRect(rect.x + rect.width - LINEWIDTH / 2, rect.y,
     LINEWIDTH, rect.height);
   m_isDrawRect = true;
  } else {
   Rectangle rect = getBoundsAt(next - 1);
   m_lineRect.setRect(rect.x + rect.width - LINEWIDTH / 2, rect.y,
     LINEWIDTH, rect.height);
   m_isDrawRect = true;
  }
 }

 private void initTargetTopBottomLine(int next, TabTransferData a_data) {
  if (next < 0) {
   m_lineRect.setRect(0, 0, 0, 0);
   m_isDrawRect = false;
   return;
  } // if

  if ((a_data.getTabbedPane() == this)
    && (a_data.getTabIndex() == next
    || next - a_data.getTabIndex() == 1)) {
   m_lineRect.setRect(0, 0, 0, 0);
   m_isDrawRect = false;
  } else if (getTabCount() == 0) {
   m_lineRect.setRect(0, 0, 0, 0);
   m_isDrawRect = false;
   return;
  } else if (next == getTabCount()) {
   Rectangle rect = getBoundsAt(getTabCount() - 1);
   m_lineRect.setRect(rect.x, rect.y + rect.height - LINEWIDTH / 2,
     rect.width, LINEWIDTH);
   m_isDrawRect = true;
  } else if (next == 0) {
   Rectangle rect = getBoundsAt(0);
   m_lineRect.setRect(rect.x, -LINEWIDTH / 2, rect.width, LINEWIDTH);
   m_isDrawRect = true;
  } else {
   Rectangle rect = getBoundsAt(next - 1);
   m_lineRect.setRect(rect.x, rect.y + rect.height - LINEWIDTH / 2,
     rect.width, LINEWIDTH);
   m_isDrawRect = true;
  }
 }

 private void initGlassPane(Component c, Point tabPt, int a_tabIndex) {
  //Point p = (Point) pt.clone();
  getRootPane().setGlassPane(s_glassPane);
  if (hasGhost()) {
   Rectangle rect = getBoundsAt(a_tabIndex);
   BufferedImage image = new BufferedImage(c.getWidth(),
     c.getHeight(), BufferedImage.TYPE_INT_ARGB);
   Graphics g = image.getGraphics();
   c.paint(g);
   image = image.getSubimage(rect.x, rect.y, rect.width, rect.height);
   s_glassPane.setImage(image);   
  } // if

  s_glassPane.setPoint(buildGhostLocation(tabPt));
  s_glassPane.setVisible(true);
 }

 private Rectangle getTabAreaBound() {
  Rectangle lastTab = getUI().getTabBounds(this, getTabCount() - 1);
  return new Rectangle(0, 0, getWidth(), lastTab.y + lastTab.height);
 }

 public void paintComponent(Graphics g) {
  super.paintComponent(g);

  if (m_isDrawRect) {
   Graphics2D g2 = (Graphics2D) g;
   g2.setPaint(m_lineColor);
   g2.fill(m_lineRect);
  } // if
 }

 public interface TabAcceptor {
  boolean isDropAcceptable(DnDTabbedPane a_component, int a_index);
 }
}

class GhostGlassPane extends JPanel {
 public static final long serialVersionUID = 1L;
 private final AlphaComposite m_composite;

 private Point m_location = new Point(0, 0);

 private BufferedImage m_draggingGhost = null;

 public GhostGlassPane() {
  setOpaque(false);
  m_composite = AlphaComposite.getInstance(AlphaComposite.SRC_OVER, 0.7f);
 }

 public void setImage(BufferedImage draggingGhost) {
  m_draggingGhost = draggingGhost;
 }

 public void setPoint(Point a_location) {
  m_location.x = a_location.x;
  m_location.y = a_location.y;
 }

 public int getGhostWidth() {
  if (m_draggingGhost == null) {
   return 0;
  } // if

  return m_draggingGhost.getWidth(this);
 }

 public int getGhostHeight() {
  if (m_draggingGhost == null) {
   return 0;
  } // if

  return m_draggingGhost.getHeight(this);
 }

 public void paintComponent(Graphics g) {
  if (m_draggingGhost == null) {
   return;
  } // if 

  Graphics2D g2 = (Graphics2D) g;
  g2.setComposite(m_composite);

  g2.drawImage(m_draggingGhost, (int) m_location.getX(), (int) m_location.getY(), null);
 }
}
eed3si9n
A: 

This solution works very well for regular tabbed panes, but how do you make this work when you have a custom tab class? In my case I have implemented a closeable tab (extends JPanel) and the draggable tabs no longer work.

Is there something that I need to enable on these closeable tabs?

Tony