/* * Bibliothek - DockingFrames * Library built on Java/Swing, allows the user to "drag and drop" * panels containing any Swing-Component the developer likes to add. * * Copyright (C) 2012 Herve Guillaume, Benjamin Sigg * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library 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 * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA * * Herve Guillaume * rvguillaume@hotmail.com * FR - France * * Benjamin Sigg * benjamin_sigg@gmx.ch * CH - Switzerland */ package bibliothek.gui.dock.station.toolbar; import java.awt.Component; import java.awt.Point; import javax.swing.SwingUtilities; import bibliothek.gui.DockStation; import bibliothek.gui.Dockable; import bibliothek.gui.Orientation; import bibliothek.gui.Position; import bibliothek.gui.dock.ToolbarContainerDockStation; import bibliothek.gui.dock.displayer.DisplayerCombinerTarget; import bibliothek.gui.dock.station.StationChildHandle; import bibliothek.gui.dock.station.StationDropOperation; import bibliothek.gui.dock.station.support.CombinerTarget; import bibliothek.gui.dock.station.support.DockablePlaceholderList; /** * This class contains and computes information about a drag and drop action. * Especially, where the {@link Dockable} should be inserted into which * {@link ToolbarContainerDockStation} * * @author Herve Guillaume */ public abstract class ToolbarContainerDropInfo implements StationDropOperation{ /** The {@link Dockable} which is inserted */ private final Dockable dragDockable; /** * The {@link DockStation} which received the dockable (WARNING: this can be * different to the original dock parent of the dockable!) */ private final ToolbarContainerDockStation stationHost; /** the drag dockable will be insert inside this {@link Dockable}s */ private final DockablePlaceholderList<StationChildHandle> associateToolbars; /** Location of the mouse */ private final int mouseX, mouseY; /** closest dockable beneath the mouse with regards to the mouse coordinates */ private Dockable dockableBeneathMouse = null; /** * closest side of the the closest component with regards to the mouse * coordinates */ private Position sideDockableBeneathMouse = null; /** * Position of the drag dockable with regards to the closest component above * the mouse */ private Position dragDockablePosition; /** * Constructs a new info to know where drop a dockable * * @param dockable * the dockable to drop * @param stationHost * the station where drop the dockable * @param associateToolbars * the other dockables in the station * @param mouseX * the mouse position on X axis * @param mouseY * the mouse position on Y axis */ public ToolbarContainerDropInfo( Dockable dockable, ToolbarContainerDockStation stationHost, DockablePlaceholderList<StationChildHandle> associateToolbars, int mouseX, int mouseY ){ dragDockable = dockable; this.stationHost = stationHost; this.associateToolbars = associateToolbars; this.mouseX = mouseX; this.mouseY = mouseY; } @Override public Dockable getItem(){ return dragDockable; } @Override public DockStation getTarget(){ return stationHost; } @Override public CombinerTarget getCombination(){ // not supported by this kind of station return null; } @Override public DisplayerCombinerTarget getDisplayerCombination(){ // not supported by this kind of station return null; } @Override public boolean isMove(){ return getItem().getDockParent() == getTarget(); } /** * Gets the index of {@link #getDockableBeneathMouse()} in the parent {@link DockStation}. * @return the index or -1 if not available */ public abstract int getIndex(); /** * Gets the <code>index</code> of the component beneath the mouse * * @return the index */ public Dockable getDockableBeneathMouse(){ if (dockableBeneathMouse == null){ dockableBeneathMouse = computeDockableBeneathMouse(); } return dockableBeneathMouse; } /** * Gets the closest <code>side</code> of the component beneath the mouse. * Example: if the mouse is over a button, near the top of the button, this * return NORTH position * * @return the side */ public Position getSideDockableBeneathMouse(){ if (sideDockableBeneathMouse == null){ sideDockableBeneathMouse = computeSideDockableBeneathMouse(); } return sideDockableBeneathMouse; } /** * Gets the relative position of drag dockable with the closest dockable * above the mouse. * * @return the position */ public Position getItemPositionVSBeneathDockable(){ if (dragDockablePosition == null){ dragDockablePosition = computeItemPositionVSBeneathDockable(); } return dragDockablePosition; } /** * compute the closest <code>side</code> of the closest component with * regards to the mouse * * @return the side or null if there's no dockable beneath mouse */ private Position computeSideDockableBeneathMouse(){ // the dockable the closest of the mouse final Dockable dockableBeneathMouse = getDockableBeneathMouse(); if (dockableBeneathMouse == null){ return null; } // mouse coordinate final Point mouseCoordinate = new Point(mouseX, mouseY); switch (stationHost.getOrientation()) { case VERTICAL: // The mouse is now in the frame of reference of the area beneath // mouse SwingUtilities.convertPointFromScreen(mouseCoordinate, dockableBeneathMouse.getComponent()); final double middleY = (dockableBeneathMouse.getComponent() .getBounds().getMinY() + dockableBeneathMouse .getComponent().getBounds().getMaxY()) / 2.0; if (Math.abs(mouseCoordinate.getY()) <= middleY){ return Position.NORTH; } else{ return Position.SOUTH; } case HORIZONTAL: // The mouse is now in the frame of reference of the area beneath // mouse SwingUtilities.convertPointFromScreen(mouseCoordinate, dockableBeneathMouse.getComponent()); final double middleX = (dockableBeneathMouse.getComponent() .getBounds().getMinX() + dockableBeneathMouse .getComponent().getBounds().getMaxX()) / 2.0; if (Math.abs(mouseCoordinate.getX()) <= middleX){ return Position.WEST; } else{ return Position.EAST; } } throw new IllegalArgumentException(); } /** * identify the dockable component beneath the mouse * * @return the dockable beneath mouse and null if none */ private Dockable computeDockableBeneathMouse(){ final DockablePlaceholderList.Filter<StationChildHandle> associateToolbars = this.associateToolbars .dockables(); final int dockableCount = associateToolbars.size(); if (dockableCount <= 0){ return null; } final Point mouseCoordinate = new Point(mouseX, mouseY); // This component stands for the panel beneath the mouse. This // rectangle will be the frame of reference of component inside this // panel. final Component panelBeneathMouse = stationHost.getContainerPanel(); // The mouse is now in the frame of reference of the area beneath // mouse SwingUtilities.convertPointFromScreen(mouseCoordinate, panelBeneathMouse); Component componentBeneathMouse; double formerDistance; final Orientation orientation = stationHost.getOrientation(); switch (orientation) { case VERTICAL: componentBeneathMouse = associateToolbars.get(0).getDisplayer() .getComponent(); double middleY = (componentBeneathMouse.getBounds().getMinY() + componentBeneathMouse .getBounds().getMaxY()) / 2.0; formerDistance = Math.abs(mouseCoordinate.getY() - middleY); // loop on dockables too see which of them is closer of the // mouse for (int i = 1; i < dockableCount; i++){ componentBeneathMouse = associateToolbars.get(i).getDisplayer() .getComponent(); middleY = (componentBeneathMouse.getBounds().getMinY() + componentBeneathMouse .getBounds().getMaxY()) / 2.0; if (Math.abs(mouseCoordinate.getY() - middleY) >= formerDistance){ // the mouse is closer of the former dockable return associateToolbars.get(i - 1).getDockable(); } formerDistance = Math.abs(mouseCoordinate.getY() - middleY); } return associateToolbars.get(dockableCount - 1).getDockable(); case HORIZONTAL: componentBeneathMouse = associateToolbars.get(0).getDisplayer() .getComponent(); double middleX = (componentBeneathMouse.getBounds().getMinX() + componentBeneathMouse .getBounds().getMaxX()) / 2.0; formerDistance = Math.abs(mouseCoordinate.getX() - middleX); // loop on dockables too see which of them is closer of the // mouse for (int i = 1; i < dockableCount; i++){ componentBeneathMouse = associateToolbars.get(i).getDisplayer() .getComponent(); middleX = (componentBeneathMouse.getBounds().getMinX() + componentBeneathMouse .getBounds().getMaxX()) / 2.0; if (Math.abs(mouseCoordinate.getX() - middleX) >= formerDistance){ // the mouse is closer of the former dockable return associateToolbars.get(i - 1).getDockable(); } formerDistance = Math.abs(mouseCoordinate.getX() - middleX); } return associateToolbars.get(dockableCount - 1).getDockable(); } throw new IllegalArgumentException(); } /** * Compute the relative position of drag dockable and the closest dockable * above the mouse * * @return the position and null if there's no dockable beneath mouse */ private Position computeItemPositionVSBeneathDockable(){ final Point coordDockableDragged = getItem().getComponent() .getLocation(); if (getDockableBeneathMouse() != null){ final Point coordDockableBeneathMouse = getDockableBeneathMouse() .getComponent().getLocation(); // The dockable is now in the frame of reference of the dockable // beneath mouse SwingUtilities.convertPointFromScreen(coordDockableDragged, getDockableBeneathMouse().getComponent()); if (getDockableBeneathMouse() == null){ return null; } if (getItem() == getDockableBeneathMouse()){ return Position.CENTER; } else{ switch (stationHost.getOrientation()) { case VERTICAL: if (coordDockableDragged.getY() <= coordDockableBeneathMouse .getY()){ return Position.NORTH; } else{ return Position.SOUTH; } case HORIZONTAL: if (coordDockableDragged.getX() <= coordDockableBeneathMouse .getX()){ return Position.EAST; } else{ return Position.WEST; } } } throw new IllegalArgumentException(); } else{ return null; } } @Override public String toString(){ return this.getClass().getSimpleName() + '@' + Integer.toHexString(hashCode()); } /** * Return a string describing field values * * @return string describing fields */ public String toSummaryString(){ final String ln = System.getProperty("line.separator"); return " => Drag dockable: " + getItem() + ln + " => Station target: " + getTarget() + ln + " => Dockable beneath mouse:" + getDockableBeneathMouse() + ln + " => Closest side:" + getSideDockableBeneathMouse() + ln + " => Drag dockable VS dockable beneath mouse:" + getItemPositionVSBeneathDockable(); } }