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

bibliothek.gui.dock.common.intern.layout.CLayoutChangeStrategy 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) 2010 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.common.intern.layout;

import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Set;

import bibliothek.gui.Dockable;
import bibliothek.gui.DockFrontend.DockInfo;
import bibliothek.gui.dock.common.CControl;
import bibliothek.gui.dock.common.MultipleCDockable;
import bibliothek.gui.dock.common.MultipleCDockableFactory;
import bibliothek.gui.dock.common.MultipleCDockableLayout;
import bibliothek.gui.dock.common.SingleCDockable;
import bibliothek.gui.dock.common.event.CVetoClosingEvent;
import bibliothek.gui.dock.common.intern.CDockable;
import bibliothek.gui.dock.common.intern.CommonDockable;
import bibliothek.gui.dock.common.intern.CommonMultipleDockableLayout;
import bibliothek.gui.dock.frontend.DefaultLayoutChangeStrategy;
import bibliothek.gui.dock.frontend.DockFrontendInternals;
import bibliothek.gui.dock.frontend.Setting;
import bibliothek.gui.dock.layout.DockLayout;
import bibliothek.gui.dock.layout.DockLayoutComposition;
import bibliothek.gui.dock.layout.DockLayoutInfo;
import bibliothek.gui.dock.layout.DockSituation;
import bibliothek.gui.dock.layout.PredefinedDockSituation;
import bibliothek.gui.dock.station.support.PlaceholderStrategy;
import bibliothek.util.FrameworkOnly;

/**
 * Strategy that pays attention to {@link MultipleCDockableFactory#match(bibliothek.gui.dock.common.MultipleCDockable, bibliothek.gui.dock.common.MultipleCDockableLayout)}
 * and that fires {@link CVetoClosingEvent}s for {@link MultipleCDockable}s as well.
 * @author Benjamin Sigg
 */
@FrameworkOnly
public class CLayoutChangeStrategy extends DefaultLayoutChangeStrategy {
	/** the control in whose realm this strategy is used */
	private CControl control;
	
	/** the internal name of the {@link ReplacementDockFactory} */
	private static final String REPLACEMENT_FACTORY_ID = PredefinedDockSituation.convertFactoryID( ReplacementDockFactory.REPLACEMENT_FACTORY_ID );
	
	/**
	 * Creates a new strategy.
	 * @param control the control in whose realm this strategy will be used
	 */
	public CLayoutChangeStrategy( CControl control ){
		this.control = control;
	}
	
	@Override
	protected PredefinedDockSituation createSituation( DockFrontendInternals frontend, boolean entry, boolean onSetLayout ){
		PredefinedDockSituation situation = super.createSituation( frontend, entry, onSetLayout );
		if( onSetLayout ){
			situation.add( new ReplacementDockFactory() );
		}
		situation.setPlaceholderStrategy( control.getProperty( PlaceholderStrategy.PLACEHOLDER_STRATEGY ) );
		return situation;
	}
	
	@Override
	protected boolean shouldPredefine( Dockable dockable ){
		if( dockable instanceof CommonDockable ){
			return ((CommonDockable)dockable).getDockable() instanceof SingleCDockable; 
		}
		else{
			return true;
		}
	}
	
	@Override
	protected Set estimateVisible( DockFrontendInternals frontend, DockSituation situation, DockLayoutComposition layout ){
        if( situation instanceof PredefinedDockSituation ){
            Set allDockables = new HashSet();
            for( DockInfo info : frontend.getDockables() ){
            	Dockable dockable = info.getDockable();
            	if( dockable != null ){
            		allDockables.add( dockable );
            	}
            }
            for( MultipleCDockable dockable : control.getRegister().getMultipleDockables() ){
            	allDockables.add( dockable.intern() );
            }
            
            PredefinedDockSituation predefined = (PredefinedDockSituation)situation;
            Set visible = predefined.listVisible( allDockables, layout );
            
            findVisible( visible, layout );
            
            return visible;
        }
        
        return null;
	}
	
	@Override
	protected Collection getClosingDockables( DockFrontendInternals frontend, Set visible ){
		Collection result = super.getClosingDockables( frontend, visible );
		
		for( MultipleCDockable dockable : control.getRegister().getMultipleDockables() ){
			CommonDockable intern = dockable.intern();
			if( !visible.contains( intern )){
				result.add( intern );
			}
		}
		
		return result;
	}
	
	private void findVisible( Set visible, DockLayoutComposition layout ){
		DockLayoutInfo info = layout.getLayout();
		if( info != null ){
			DockLayout data = info.getDataLayout();
			if( data != null ){
				if( REPLACEMENT_FACTORY_ID.equals( data.getFactoryID() )){
					CDockable dockable = (CDockable)data.getData();
					visible.add( dockable.intern() );
				}
			}
		}
		
		for( DockLayoutComposition child : layout.getChildren() ){
			findVisible( visible, child );
		}
	}
	
	/**
	 * Checks the {@link DockLayout} that is associated with composition and may replace 
	 * the layout by another layout if a {@link MultipleCDockableFactory} finds a match between an existing
	 * item and meta-data about an item. 
	 * @param frontend the caller of this method
	 * @param setting the layout that is about to be applied
	 * @param composition the composition to modify, may be null
	 * @return the replacement composition or null
	 */
	protected DockLayoutComposition replaceMultipleDockables( DockFrontendInternals frontend, CSettingAccess setting, DockLayoutComposition composition ){
		if( composition == null ){
			return null;
		}
		
		DockLayoutInfo info = composition.getLayout();
		if( info != null ){
			DockLayout layout = info.getDataLayout();
			if( layout != null ){
				MultipleCDockable match = setting.findMatch( layout );
				if( match != null ){
					DockLayout newLayout = new DockLayout( REPLACEMENT_FACTORY_ID, match );
					DockLayoutInfo newInfo = new DockLayoutInfo( newLayout );
					newInfo.setLocation( info.getLocation() );
					info = newInfo;
				}
			}
		}
	
		List oldChildren = composition.getChildren();
		List newChildren = new ArrayList( oldChildren.size() );
		
		for( DockLayoutComposition child : oldChildren ){
			newChildren.add( replaceMultipleDockables( frontend, setting, child ) );
		}
		
		return new DockLayoutComposition( info, composition.getAdjacent(), newChildren, composition.isIgnoreChildren() );
	}
	
	@Override
	protected SettingAccess createAccess( DockFrontendInternals frontend, Setting setting ){
		return new CSettingAccess( frontend, setting );
	}
	
	/**
	 * A {@link bibliothek.gui.dock.frontend.DefaultLayoutChangeStrategy.SettingAccess} that modifies the roots by calling
	 * {@link CLayoutChangeStrategy#replaceMultipleDockables(DockFrontendInternals, CSettingAccess, DockLayoutComposition)}.
	 * @author Benjamin Sigg
	 */
	protected class CSettingAccess extends SettingAccess{
		private DockFrontendInternals frontend;
		private Map modifiedRoots = new HashMap();
		
		/** all the factories that might be used to create a match */
		private Map> factories;
		
		/** the dockables which have not yet been paired off ordered by their factories */
		private Map> remainingDockables;
		
		public CSettingAccess( DockFrontendInternals frontend, Setting setting ){
			super( setting );
			this.frontend = frontend;
			
			Map> factories = control.getRegister().getFactories();
			this.factories = new HashMap>();
			for( Map.Entry> entry : factories.entrySet() ){
				this.factories.put( PredefinedDockSituation.convertFactoryID( entry.getKey() ), entry.getValue() );
			}
			
			remainingDockables = new HashMap>();
			
			for( MultipleCDockable dockable : control.getRegister().getMultipleDockables() ){
				for( Map.Entry> entry : factories.entrySet() ){
					if( entry.getValue() == dockable.getFactory() ){
						String key = PredefinedDockSituation.convertFactoryID( entry.getKey() );
						List list  = remainingDockables.get( key );
						if( list == null ){
							list = new LinkedList();
							remainingDockables.put( key, list );
						}
						list.add( dockable );
						break;
					}
				}
			}
		}
		
		/**
		 * Searches a match for the meta-data layout. The result of this method will
		 * never be result again for this {@link CSettingAccess}.
		 * @param layout the element whose match is searched
		 * @return the match or null if none was found
		 */
		@SuppressWarnings("unchecked")
		public MultipleCDockable findMatch( DockLayout layout ){
			String factoryId = layout.getFactoryID();
			Object data = layout.getData();
			
			if( data instanceof CommonMultipleDockableLayout ){
				MultipleCDockableLayout multipleLayout = ((CommonMultipleDockableLayout) data).getLayout();
				MultipleCDockableFactory factory = (MultipleCDockableFactory) factories.get( factoryId );
				if( factory != null ){
					List list = remainingDockables.get( factoryId );
					if( list != null ){
						Iterator iterator = list.iterator();
						while( iterator.hasNext() ){
							MultipleCDockable next = iterator.next();
							if( factory.match( next, multipleLayout )){
								iterator.remove();
								if( list.isEmpty() ){
									remainingDockables.remove( factoryId );
								}
								return next;
							}
						}
					}
				}
			}
			
			return null;
		}
		
		@Override
		public DockLayoutComposition getRoot( String root ){
			DockLayoutComposition result = modifiedRoots.get( root );
			if( result == null ){
				result = replaceMultipleDockables( frontend, this, super.getRoot( root ) );
				modifiedRoots.put( root, result );
			}
			return result;
		}
	}
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy