All Downloads are FREE. Search and download functionalities are using the official Maven repository.

bibliothek.gui.dock.facile.station.split.LockedResizeLayoutManager Maven / Gradle / Ivy

Go to download

DockingFrames is an open source Java Swing docking framework, licenced under LGPL 2.1. This is the same distribution as the original distribution (http://www.docking-frames.org/), only reinstalled in maven

There is a newer version: 1.1.2p20b.fix-1
Show newest version
/*
 * 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) 2007 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
 * [email protected]
 * CH - Switzerland
 */
package bibliothek.gui.dock.facile.station.split;

import java.awt.Rectangle;

import bibliothek.gui.Dockable;
import bibliothek.gui.dock.station.split.DefaultSplitLayoutManager;
import bibliothek.gui.dock.station.split.Leaf;
import bibliothek.gui.dock.station.split.Node;
import bibliothek.gui.dock.station.split.Root;
import bibliothek.gui.dock.station.split.SplitLayoutManager;
import bibliothek.gui.dock.station.split.SplitNode;

/**
 * A {@link SplitLayoutManager} that can lock the size of some {@link Dockable}s
 * during resize. This class is intended to be subclassed.
 * @param  the type of the temporary data this manager works with 
 * @author Benjamin Sigg
 */
public abstract class LockedResizeLayoutManager extends DelegatingSplitLayoutManager{
    /**
     * Tells how to merge the {@link ResizeRequest}s of this manager.
     */
    private ConflictResolver conflictResolver = new DefaultConflictResolver();
    
    /**
     * Creates a new manager using the {@link DefaultSplitLayoutManager}
     * as delegate.
     */
    public LockedResizeLayoutManager(){
        this( new DefaultSplitLayoutManager() );
    }
    
    /**
     * Creates a new manager.
     * @param delegate the base functionality 
     */
    public LockedResizeLayoutManager( SplitLayoutManager delegate ){
        super( delegate );
    }
    
    /**
     * Sets the {@link ConflictResolver} that will determine how to merge
     * {@link ResizeRequest}s and how to resolve conflicts.
     * @param conflictResolver the new policy, not null
     */
    public void setConflictResolver( ConflictResolver conflictResolver ) {
        if( conflictResolver == null )
            throw new IllegalArgumentException( "conflictResolver must not be null" );
        this.conflictResolver = conflictResolver;
    }
    
    /**
     * Gets the policy that tells how two {@link ResizeRequest}s are merged.
     * @return the policy
     */
    public ConflictResolver getConflictResolver() {
        return conflictResolver;
    }
    
    @Override
    public void updateBounds( Root root, double x, double y, double factorW, double factorH ) {
        Rectangle current = root.getCurrentBounds();
        Rectangle bounds = root.getBounds();
        
        boolean resize = isResize( root ); 

        if( resize ){
            resize = current.width > 10 && current.height > 10 && bounds.width > 10 && bounds.height > 10;
        }
        
        if( resize ){
        	updateBoundsLocked( root, x, y, factorW, factorH );
        }
        else if( hasTreeChanged( root )){
        	updateBoundsLocked( root, x, y, factorW, factorH );	
        }
        else{ 
        	super.updateBounds( root, x, y, factorW, factorH );
        }
    }

    /**
     * Tells whether the current operation is a resize operation. The locked sizes will only be respected if
     * the operation is a resize operation.
     * @param root the item that is going to be updated
     * @return whether a resize operation is in progress
     */
    protected boolean isResize( Root root ){
    	Rectangle current = root.getCurrentBounds();
        Rectangle bounds = root.getBounds();
        
        return !current.equals( bounds );
    }

    /**
     * Tells whether the current operation happens because the tree has changed (e.g. a leaf has been added or removed). 
     * This method is only called if {@link #isResize(Root)} already returned false. 
     * @param root the item that is going to be updated
     * @return whether the tree has changed
     */
    protected boolean hasTreeChanged( Root root ){
    	return root.hasTreeChanged();
    }
    
    /**
     * Updates the bounds of root and all its children and does
     * consider all {@link ResizeRequest}.
     * @param root the root element of a tree to update
     * @param x the left coordinate of root
     * @param y the top coordinate of root
     * @param factorW a factor all x-coordinates have to be multiplied with
     * in order to get the pixel coordinates
     * @param factorH a factor all y-coordinates have to be multiplied with
     * in order to get the pixel coordinates
     */
    public void updateBoundsLocked( Root root, double x, double y, double factorW, double factorH ){
        ResizeElement element = toElement( null, root );
        element.prepareResize();
        root.updateBounds( x, y, 1, 1, factorW, factorH, false );
        element.prepareRequests();
        element.adapt( 0, 0 );
        root.updateBounds( x, y, 1, 1, factorW, factorH, true );
    }

    
    /**
     * Gets the size request that changes the size of leaf such
     * that it has a valid size again.
     * @param t the data that was created in {@link #prepareResize(Leaf)} or null
     * @param leaf the leaf which size is not yet valid.
     * @return the preferred size or null
     */
    public abstract ResizeRequest getRequest( T t, Leaf leaf );
    
    /**
     * Called before the resize takes place, subclasses might store some
     * properties.
     * @param leaf some leaf
     * @return some temporary data that gets forwarded to {@link #getRequest(Object, Leaf)},
     * can be null
     */
    public abstract T prepareResize( Leaf leaf );
    
    /**
     * Transforms a {@link SplitNode} into the matching kind of {@link ResizeElement}.
     * The subtree of node is transformed as well.
     * @param parent the parent of the new element
     * @param node some root, node, leaf or null
     * @return some root, node, leaf or null
     */
    public ResizeElement toElement( ResizeElement parent, SplitNode node ){
    	for( int i = 0; i < 5; i++ ){
    		ResizeElement result = asyncToElement( parent, node );
    		if( result == null || result.isValid() ){
    			return result;
    		}
    		
    		try {
				Thread.sleep( 20 );
			}
			catch( InterruptedException e ) {
				// ignore
			}
    	}
    	
    	System.err.println( "LockedResizeLayoutManager.toElement: Potential race condition detected, converting SplitNode to ResizeElement failed 5 times in a row. The node is ignored." );
    	return null;
    }
    
    /**
     * Called by {@link #toElement(ResizeElement, SplitNode)}, tries to create a {@link ResizeElement} out of
     * node in an environment where race conditions are possible. This is a best effort method, callers
     * should check the result using the method {@link ResizeElement#isValid()}.
     * @param parent the parent of the new element
     * @param node some root, node, leaf or null
     * @return some root, node, leaf or null
     */
    protected ResizeElement asyncToElement( ResizeElement parent, SplitNode node ){
    	if( node instanceof Root ){
            return new ResizeRoot( this, (Root)node );
    	}
        if( node instanceof Node ){
        	Node real = (Node)node;
        	SplitNode left = real.getLeft();
        	SplitNode right = real.getRight();
        	
        	boolean leftVisible = left == null ? false : left.isVisible();
        	boolean rightVisible = right == null ? false : right.isVisible();
        	if( leftVisible && rightVisible ){
        		return new ResizeNode( this, parent, (Node)node );
        	}
        	if( leftVisible ){
        		return toElement( parent, left.getVisible() );
        	}
        	if( rightVisible ){
        		return toElement( parent, right.getVisible() );
        	}
        	return null;
        }
        if( node instanceof Leaf ){
            return new ResizeLeaf( this, parent, (Leaf)node );
        }
        
        return null;
    }
}






© 2015 - 2024 Weber Informatics LLC | Privacy Policy