package org.flexdock.docking.drag;
import java.awt.Component;
import java.awt.Container;
import java.awt.EventQueue;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Point;
import java.awt.Polygon;
import java.util.Map;
import javax.swing.JComponent;
import javax.swing.SwingUtilities;
import org.flexdock.docking.Dockable;
import org.flexdock.docking.DockingConstants;
import org.flexdock.docking.DockingManager;
import org.flexdock.docking.DockingPort;
import org.flexdock.docking.drag.effects.DragPreview;
import org.flexdock.docking.drag.effects.EffectsManager;
import org.flexdock.util.NestedComponents;
import org.flexdock.util.RootWindow;
public class DragGlasspane extends JComponent implements DockingConstants {
private NestedComponents currentDropTargets;
private Component cachedGlassPane;
private RootWindow rootWindow;
private Runnable postPainter;
private DragPreview previewDelegate;
private boolean previewInit;
private Polygon previewPoly;
private DragOperation currentDragToken;
public DragGlasspane() {
setLayout(null);
}
public Component getCachedGlassPane() {
return cachedGlassPane;
}
public RootWindow getRootWindow() {
return rootWindow;
}
public void setCachedGlassPane(Component cachedGlassPane) {
this.cachedGlassPane = cachedGlassPane;
}
public void setRootWindow(RootWindow rootWindow) {
this.rootWindow = rootWindow;
}
private NestedComponents getDropTargets(DragOperation token) {
Container c = rootWindow.getContentPane();
Point currMouse = token.getCurrentMouse(c);
Component deep = SwingUtilities.getDeepestComponentAt(c, currMouse.x, currMouse.y);
return NestedComponents.find(deep, Dockable.class, DockingPort.class);
}
public void processDragEvent(DragOperation token) {
currentDragToken = token;
NestedComponents dropTargets = getDropTargets(token);
// if there is no cover, and we're not transitioning away from one,
// then invoke postPaint() and return
if(currentDropTargets==null && dropTargets==null) {
deferPostPaint();
return;
}
String region = null;
// don't immediately redraw the rubberband when switching covers
// or regions
setPostPainter(null);
// now, assign the currentCover to the new one and repaint
currentDropTargets = dropTargets;
DockingPort port = dropTargets==null? null: (DockingPort)dropTargets.parent;
// this is the dockable we're currently hovered over, not the one
// being dragged
Dockable hover = getHoverDockable(dropTargets);
Point mousePoint = token.getCurrentMouse((Component)port);
region = findRegion(port, hover, mousePoint);
// set the target dockable
token.setTarget(port, region);
// create the preview-polygon
createPreviewPolygon(token, port, hover, region);
// repaint
repaint();
}
private String findRegion(DockingPort hoverPort, Dockable hoverDockable, Point mousePoint) {
if(hoverPort==null)
return UNKNOWN_REGION;
if(hoverDockable!=null)
return hoverPort.getRegion(mousePoint);
// apparently, we're not hovered over a valid dockable. either the dockingport
// is empty, or it already contains a non-dockable component. if it's empty, then
// we can dock into it. otherwise, we need to short-circuit the docking operation.
Component docked = hoverPort.getDockedComponent();
// if 'docked' is null, then the port is empty and we can dock
if(docked==null)
return hoverPort.getRegion(mousePoint);
// the port contains a non-dockable component. we can't dock
return UNKNOWN_REGION;
}
private Dockable getHoverDockable(NestedComponents nest) {
Component c = nest==null? null: nest.child;
if(c instanceof Dockable)
return (Dockable)c;
return DockingManager.getDockable(c);
}
protected void createPreviewPolygon(DragOperation token, DockingPort port, Dockable hover, String region) {
DragPreview preview = getPreviewDelegate(token.getDockable(), port);
if(preview==null)
previewPoly = null;
else {
Map dragContext = getDragContext(token);
previewPoly = preview.createPreviewPolygon(token.getDockable(), port, hover, region, this, dragContext);
}
}
public void clear() {
if(currentDropTargets!=null) {
currentDropTargets = null;
}
repaint();
}
public void paint(Graphics g) {
paintComponentImpl(g);
postPaint(g);
}
protected void postPaint(Graphics g) {
if(postPainter!=null)
postPainter.run();
postPainter = null;
}
protected DragPreview getPreviewDelegate(Component dockable, DockingPort port) {
if(!previewInit) {
Dockable d = DockingManager.getDockable(dockable);
previewDelegate = EffectsManager.getPreview(d, port);
previewInit = true;
}
return previewDelegate;
}
private void deferPostPaint() {
EventQueue.invokeLater(new Runnable() {
public void run() {
postPaint(getGraphics());
}
});
}
void setPostPainter(Runnable painter) {
postPainter = painter;
}
protected void paintComponentImpl(Graphics g) {
if(currentDragToken!=null && previewDelegate!=null && previewPoly!=null) {
Dockable dockable = currentDragToken.getDockableReference();
Map dragInfo = getDragContext(currentDragToken);
previewDelegate.drawPreview((Graphics2D)g, previewPoly, dockable, dragInfo);
}
}
// private boolean match(Object o1, Object o2) {
// if(o1==o2)
// return true;
// return o1==null? false: o1.equals(o2);
// }
private Map getDragContext(DragOperation token) {
if(token==null)
return null;
Dockable dockable = token.getDockableReference();
return DragManager.getDragContext(dockable);
}
}