/* * 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) 2008 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 * * Benjamin Sigg * benjamin_sigg@gmx.ch * CH - Switzerland */ package bibliothek.gui.dock.station.split; import java.awt.Dimension; import java.awt.Point; import javax.swing.SwingUtilities; import bibliothek.gui.Dockable; import bibliothek.gui.dock.SplitDockStation; import bibliothek.gui.dock.SplitDockStation.Orientation; import bibliothek.gui.dock.station.StationDropItem; /** * The default implementation of {@link SplitLayoutManager}. * @author Benjamin Sigg */ public class DefaultSplitLayoutManager implements SplitLayoutManager{ public void install( SplitDockStation station ) { // ignore } public void uninstall( SplitDockStation station ) { // ignore } public Dockable willMakeFullscreen( SplitDockStation station, Dockable dockable ) { return dockable; } public PutInfo prepareDrop( SplitDockStation station, StationDropItem item ){ if( station.isFullScreen() ) return null; if( station.getDockableCount() == 0 ){ PutInfo putInfo = new PutInfo( null, PutInfo.Put.CENTER, item.getDockable(), true ); putInfo = validatePutInfo( station, putInfo ); return putInfo; } else{ Point point = new Point( item.getMouseX(), item.getMouseY() ); SwingUtilities.convertPointFromScreen( point, station ); PutInfo putInfo = station.getRoot().getPut( point.x, point.y, item.getDockable() ); if( putInfo == null && station.isAllowSideSnap() ){ putInfo = calculateSideSnap( station, point.x, point.y, null, item.getDockable() ); putInfo = validatePutInfo( station, putInfo ); } if( putInfo != null ){ putInfo.setDockable( item.getDockable() ); calculateDivider( station, putInfo, null, item ); } return putInfo; } } public PutInfo prepareMove( SplitDockStation station, StationDropItem item ){ if( station.isFullScreen() ) return null; Point point = new Point( item.getMouseX(), item.getMouseY() ); SwingUtilities.convertPointFromScreen( point, station ); Root root = station.getRoot(); PutInfo putInfo = root.getPut( point.x, point.y, item.getDockable() ); Leaf leaf = root.getLeaf( item.getDockable() ); if( putInfo == null && station.isAllowSideSnap() ){ putInfo = calculateSideSnap( station, point.x, point.y, leaf, item.getDockable() ); putInfo = validatePutInfo( station, putInfo ); if( putInfo != null ){ leaf = null; } } if( (putInfo != null) && (putInfo.getNode() instanceof Leaf) && (((Leaf)putInfo.getNode())).getDockable() == item.getDockable() ){ putInfo.setNode( null ); } if( putInfo != null ){ putInfo.setDockable( item.getDockable() ); calculateDivider( station, putInfo, leaf, item ); } return putInfo; } /** * Calculates where to add a {@link Dockable} if the mouse is outside * this station. * @param station the station onto which <code>drop</code> might be dropped * @param x The x-coordinate of the mouse * @param y The y-coordinate of the mouse * @param leaf The leaf which was the old parent of the moved {@link Dockable} * or <code>null</code> * @param drop the element that will be dropped * @return The preferred location or <code>null</code> */ protected PutInfo calculateSideSnap( SplitDockStation station, int x, int y, Leaf leaf, Dockable drop ){ if( station.getDockableCount() == 0 ) return null; if( station.getDockableCount() == 1 && station.getDockable( 0 ) == drop ) return null; PutInfo info; if( SplitNode.above( 0, 0, station.getWidth(), station.getHeight(), x, y )){ if( SplitNode.above( 0, station.getHeight(), station.getWidth(), 0, x, y )){ // top info = new PutInfo( station.getRoot().getChild(), PutInfo.Put.TOP, drop, false ); } else{ // bottom info = new PutInfo( station.getRoot().getChild(), PutInfo.Put.RIGHT, drop, false ); } } else{ if( SplitNode.above( 0, station.getHeight(), station.getWidth(), 0, x, y )){ // left info = new PutInfo( station.getRoot().getChild(), PutInfo.Put.LEFT, drop, false ); } else{ // right info = new PutInfo( station.getRoot().getChild(), PutInfo.Put.BOTTOM, drop, false ); } } if( leaf != null && station.getRoot().getChild() instanceof Node){ Node node = (Node)station.getRoot().getChild(); if( node.getLeft().isVisible() && node.getRight().isVisible() ){ if( info.getPut() == PutInfo.Put.TOP && node.getOrientation() == Orientation.VERTICAL && node.getLeft() == leaf ) return null; if( info.getPut() == PutInfo.Put.BOTTOM && node.getOrientation() == Orientation.VERTICAL && node.getRight() == leaf ) return null; if( info.getPut() == PutInfo.Put.LEFT && node.getOrientation() == Orientation.HORIZONTAL && node.getLeft() == leaf ) return null; if( info.getPut() == PutInfo.Put.RIGHT && node.getOrientation() == Orientation.HORIZONTAL && node.getRight() == leaf ) return null; } } return info; } public void calculateDivider( SplitDockStation station, PutInfo putInfo, Leaf origin, StationDropItem item ){ final double MINIMUM_ORIGINAL_SIZE = 0.25; SplitNode other = putInfo.getNode(); if( other == null ){ return; } Dimension oldSize = origin == null ? item.getOriginalSize() : origin.getSize(); if( other.getParent() instanceof Root ){ other = other.getParent(); } Dimension nodeSize = other.getSize(); int size = Math.min( oldSize.width, oldSize.height ); if( origin != null ){ if( origin.getParent() instanceof Node ){ Node originParent = (Node)origin.getParent(); if( (putInfo.getPut() == PutInfo.Put.LEFT || putInfo.getPut() == PutInfo.Put.RIGHT) && originParent.getOrientation() == Orientation.HORIZONTAL ){ size = oldSize.width; } else if( (putInfo.getPut() == PutInfo.Put.TOP || putInfo.getPut() == PutInfo.Put.BOTTOM) && originParent.getOrientation() == Orientation.VERTICAL){ size = oldSize.height; } } } else{ if( putInfo.getOldSize() != 0 ){ size = putInfo.getOldSize(); } } double divider = 0.5; int dividerSize = station.getDividerSize(); if( putInfo.getPut() == PutInfo.Put.TOP ){ if( size != 0 ) divider = (size + dividerSize/2.0) / nodeSize.height; divider = validateDivider( station, divider, item.getMinimumSize(), other.getMinimumSize(), Orientation.VERTICAL, other.getWidth(), other.getHeight() ); if( divider > 1 - MINIMUM_ORIGINAL_SIZE ) divider = 1 - MINIMUM_ORIGINAL_SIZE; } else if( putInfo.getPut() == PutInfo.Put.BOTTOM ){ if( size != 0 ) divider = 1.0 - (size + dividerSize/2.0) / nodeSize.height; divider = validateDivider( station, divider, other.getMinimumSize(), item.getMinimumSize(), Orientation.VERTICAL, other.getWidth(), other.getHeight() ); if( divider < MINIMUM_ORIGINAL_SIZE ) divider = MINIMUM_ORIGINAL_SIZE; } else if( putInfo.getPut() == PutInfo.Put.LEFT ){ if( size != 0 ) divider = (size + dividerSize/2.0) / nodeSize.width; divider = validateDivider( station, divider, item.getMinimumSize(), other.getMinimumSize(), Orientation.HORIZONTAL, other.getWidth(), other.getHeight() ); if( divider > 1 - MINIMUM_ORIGINAL_SIZE ) divider = 1 - MINIMUM_ORIGINAL_SIZE; } else if( putInfo.getPut() == PutInfo.Put.RIGHT ){ if( size != 0 ) divider = 1.0 - (size + dividerSize/2.0) / nodeSize.width; divider = validateDivider( station, divider, other.getMinimumSize(), item.getMinimumSize(), Orientation.HORIZONTAL, other.getWidth(), other.getHeight() ); if( divider < MINIMUM_ORIGINAL_SIZE ) divider = MINIMUM_ORIGINAL_SIZE; } putInfo.setDivider( divider ); putInfo.setOldSize( size ); } public double validateDivider( SplitDockStation station, double divider, Node node ){ divider = Math.min( 1, Math.max( 0, divider )); SplitNode left = node.getLeft(); SplitNode right = node.getRight(); Dimension leftMin = null; Dimension rightMin = null; if( left != null ){ leftMin = left.getMinimumSize(); } if( right != null ){ rightMin = right.getMinimumSize(); } if( leftMin == null ){ leftMin = new Dimension(); } if( rightMin == null ){ rightMin = new Dimension(); } return validateDivider( station, divider, leftMin, rightMin, node.getOrientation(), node.getWidth(), node.getHeight() ); } /** * Tests whether the specified <code>divider</code>-value is legal or not. * @param station the station for which the divider is intended * @param divider the value of a divider on a {@link Node} * @param minimumLeft the minimal number of pixels on the left or top side of the divider * @param minimumRight the minimal number of pixels on the right or bottom side of the divider * @param orientation the orientation of the divider * @param width the relative width of the base (in respect to the size of this station) * @param height the relative height of the base (in respect to the size of this station) * @return a legal value as near as possible to <code>divider</code> */ protected double validateDivider( SplitDockStation station, double divider, Dimension minimumLeft, Dimension minimumRight, Orientation orientation, double width, double height ){ double factor; double size; int left, right; if( orientation == Orientation.HORIZONTAL ){ factor = station.getRoot().getWidthFactor(); size = width; left = minimumLeft.width; right = minimumRight.width; } else{ factor = station.getRoot().getHeightFactor(); size = height; left = minimumLeft.height; right = minimumRight.height; } if( factor <= 0 || Double.isNaN( factor )) return divider; double leftNeed = left / factor; double rightNeed = right / factor; double dividerNeed = station.getDividerSize() / factor; if( leftNeed + rightNeed + dividerNeed >= size ) divider = (leftNeed + dividerNeed / 2) / ( leftNeed + rightNeed + dividerNeed ); else if( divider * size < leftNeed + dividerNeed / 2 ) divider = (leftNeed + dividerNeed / 2) / size; else if( divider * size > size - rightNeed - dividerNeed / 2 ) divider = (size - rightNeed - dividerNeed / 2) / size; return divider; } public PutInfo validatePutInfo( SplitDockStation station, PutInfo putInfo ){ if( putInfo != null ){ if( !station.accept( putInfo.getDockable() )) return null; if( putInfo.getNode() != null && (putInfo.getPut() == PutInfo.Put.CENTER || putInfo.getPut() == PutInfo.Put.TITLE )){ if( !putInfo.getDockable().accept( station, ((Leaf)putInfo.getNode()).getDockable() ) || !((Leaf)putInfo.getNode()).getDockable().accept( station, putInfo.getDockable() ) || !station.getController().getAcceptance().accept( station, ((Leaf)putInfo.getNode()).getDockable(), putInfo.getDockable() )){ return null; } } else{ if( !putInfo.getDockable().accept( station ) || !station.getController().getAcceptance().accept( station, putInfo.getDockable() )){ return null; } } } return putInfo; } public void updateBounds( Root root, double x, double y, double factorW, double factorH ) { root.updateBounds( x, y, 1, 1, factorW, factorH, true ); } }