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

bibliothek.gui.dock.control.SingleParentRemover Maven / Gradle / Ivy

The 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.control;

import bibliothek.gui.DockController;
import bibliothek.gui.DockStation;
import bibliothek.gui.Dockable;
import bibliothek.gui.dock.accept.DockAcceptance;
import bibliothek.gui.dock.control.relocator.DockRelocatorEvent;
import bibliothek.gui.dock.control.relocator.VetoableDockRelocatorAdapter;
import bibliothek.gui.dock.event.DockRegisterAdapter;

/**
 * An observer of a {@link DockController}. The remover
 * ensures that there is no dockable {@link DockStation} with only one
 * or none child.
 * @author Benjamin Sigg
 */
public class SingleParentRemover{
	/** the controller using the remover */
	private DockController controller;
	
    /** observers a {@link DockRelocator} and searches for changes */
    private DockRelocatorObserver dockRelocatorObserver = new DockRelocatorObserver();
    /** observers a {@link DockRegister} and searches for changes */
    private DockRegisterObserver dockRegisterObserver = new DockRegisterObserver();
   
    /** state, ensures that no station is tested more than once in a run */
    private boolean onTest = false;
    
    /**
     * Commands this remover to observe controller.
     * @param controller a controller to observe
     */
    public void install( DockController controller ){
    	if( this.controller != null ){
    		throw new IllegalStateException( "a controller is already installed" );
    	}
    	this.controller = controller;
    	
        controller.getRelocator().addVetoableDockRelocatorListener( dockRelocatorObserver );
        controller.getRegister().addDockRegisterListener( dockRegisterObserver );
        testAll( controller );
    }
    
    /**
     * Commands this remover that it should no longer observe
     * controller.
     * @param controller a controller
     */
    public void uninstall( DockController controller ){
    	if( this.controller != controller ){
    		throw new IllegalArgumentException( "controller is not installed" );
    	}
        controller.getRelocator().removeVetoableDockRelocatorListener( dockRelocatorObserver );
        controller.getRegister().removeDockRegisterListener( dockRegisterObserver );
        this.controller = null;
    }
    
    /**
     * Tests all stations of controller and removes
     * as many of them as possible
     * @param controller the controller to test
     */
    public void testAll( DockController controller ){
        if( onTest )
            return;
        
        try{
            onTest = true;
            controller.getRegister().setStalled( true );
            
            int index = 0;
            while( index < controller.getRegister().getStationCount() ){
                if( test( controller.getRegister().getStation( index ))){
                    index = 0;
                }
                else
                    index++;
            }
        }
        finally{
            controller.getRegister().setStalled( false );
            onTest = false;
        }
    }
    
    /**
     * Tells whether station should be automatically
     * removed or just be ignored.
     * @param station a station to test
     * @return true if the station may be removed
     * by this remover, false otherwise.
     */
    protected boolean shouldTest( DockStation station ){
        return true;
    }
    
    /**
     * Tries to replace station with its only child or 
     * remove station if it has no children at all. If the
     * parent of station refuses to accept the replacement
     * or station refuses to let its child go, nothing will
     * happen.
     * @param station the station to test
     * @return whether the station was replaced or removed
     */
    protected boolean test( DockStation station ){
        DockController controller = station.getController();
        if( controller != null ){
            controller.getRegister().setStalled( true );
            controller.getHierarchyLock().setConcurrent( true );
        }
        
        try{
        	
            if( !shouldTest( station ))
                return false;
            
            if( station.getDockableCount() > 1 )
                return false;
            
            Dockable transform = station.asDockable();
            if( transform == null )
                return false;
            
            DockStation parent = transform.getDockParent();
            
            if( parent == null )
                return false;
            
            if( parent.getController() == null )
                return false;
            
            if( station.getDockableCount() == 0 ){
                if( !parent.canDrag( transform ))
                    return false;
                
                parent.drag( transform );
                return true;
            }
            else{
                Dockable dockable = station.getDockable( 0 );
                if( !station.canDrag( dockable ))
                    return false;
                
                if( !parent.accept( dockable ) || !dockable.accept( parent ) )
                    return false;
                
                if( !parent.canReplace( transform, dockable ))
                    return false;
                
                DockAcceptance acceptance = station.getController().getAcceptance();
                
                if( acceptance != null ){
                	if( !acceptance.accept( parent, dockable ))
                		return false;
                }
                
                station.drag( dockable );
                parent.replace( transform.asDockStation(), dockable );
                return true;
            }
        }
        finally{
            if( controller != null ){
            	controller.getHierarchyLock().setConcurrent( false );
                controller.getRegister().setStalled( false );
            }
        }
    }
    
    /**
     * Calls {@link SingleParentRemover#testAll(DockController)}
     * if the structure of the dock-tree changes.
     * @author Benjamin Sigg
     */
    private class DockRegisterObserver extends DockRegisterAdapter{
        @Override
        public void dockableCycledRegister( DockController controller, Dockable dockable ) {
            testAll( controller );
        }
        
        @Override
        public void dockableRegistered( DockController controller, Dockable dockable ){
        	if( !controller.getRelocator().isOnPut() ){
                testAll( controller );
            }
        }
        
        @Override
        public void dockableUnregistered( DockController controller, Dockable dockable ) {
            if( !controller.getRelocator().isOnPut() ){
                testAll( controller );
            }
        }
        
        @Override
        public void dockStationRegistered( final DockController controller, DockStation station ){
        	controller.getHierarchyLock().onRelease( new Runnable(){
				public void run(){
					testAll( controller );	
				}
			});
        }
    }
    
    /**
     * Calls {@link SingleParentRemover#testAll(DockController)}
     * if the structure of the dock-tree changes.
     * @author Benjamin Sigg
     */
    private class DockRelocatorObserver extends VetoableDockRelocatorAdapter{
    	@Override
    	public void dropped( DockRelocatorEvent event ){
    	    testAll( controller );
        }
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy