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

bibliothek.gui.dock.layout.PredefinedDockSituation Maven / Gradle / Ivy

/*
 * 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
 * [email protected]
 * CH - Switzerland
 */

package bibliothek.gui.dock.layout;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;

import bibliothek.gui.DockController;
import bibliothek.gui.DockStation;
import bibliothek.gui.Dockable;
import bibliothek.gui.dock.DockElement;
import bibliothek.gui.dock.DockFactory;
import bibliothek.gui.dock.perspective.PerspectiveDockable;
import bibliothek.gui.dock.perspective.PerspectiveElement;
import bibliothek.gui.dock.perspective.PredefinedPerspective;
import bibliothek.gui.dock.station.support.PlaceholderStrategy;
import bibliothek.gui.dock.util.DockUtilities;
import bibliothek.gui.dock.util.extension.ExtensionManager;
import bibliothek.util.Version;
import bibliothek.util.xml.XElement;
import bibliothek.util.xml.XException;

/**
 * A {@link DockSituation} that does not load or store all {@link DockElement DockElements}.
 * All elements which are registered by {@link #put(DockElement)} are stored in an
 * internal list. On writing, just a unique id is written to the stream. 
 * A {@link DockFactory} is still necessary for these elements, but the factory may
 * just do nothing.
 * @author Benjamin Sigg
 */
public class PredefinedDockSituation extends DockSituation {
    /** A mapping from ids to a list of elements which must not be created by a factory */
    private Map stringToElement = new HashMap();
    /** A mapping from a list of elements to their ids */
    private Map elementToString = new HashMap();

    private static final String KNOWN = "predefined";
    private static final String UNKNOWN = "delegate_";

    /** backup factories for elements that should be in the cache, but are missing */
    private Map>> backups =
        new HashMap>>();

    private final PreloadFactory factory = new PreloadFactory();
    
    /**
     * Creates a new {@link DockSituation}, uses controller to access the
     * {@link ExtensionManager} and install additional {@link DockFactory}s.
     * @param controller the controller in whose realm this situation will be used
     */
    public PredefinedDockSituation( DockController controller ){
    	super( controller );
    }
    
    /**
     * Creates a new {@link PredefinedPerspective}. This perspective will write the layout in
     * such a way that a {@link PredefinedDockSituation} can read it again.
* Please note that clients need to register {@link DockElement}s using {@link PredefinedPerspective#put(String, PerspectiveElement)} * before the perspective can be used. The {@link DockElement}s registered to this by using {@link #put(String, DockElement)} * are ignored by the perspective. */ @Override public PredefinedPerspective createPerspective(){ return new PredefinedPerspective( this ){ private PreloadFactory preload; { preload = new PreloadFactory(this); } protected String getID( PerspectiveElement element ){ return PredefinedDockSituation.this.getID( element, this ); } protected DockFactory getFactory( String id ){ DockFactory factory = PredefinedDockSituation.this.getFactory( id ); if( factory == PredefinedDockSituation.this.factory ){ return preload; } return factory; } }; } /** * Adds a backup factory to this situation. A backup factory is used when * an element should be in the cache, but is missing. The backup factory * receives a {@link BackupFactoryData} object, the identifier of that * object does not have to be stored by factory. The * factory has only to look at the {@link BackupFactoryData#getData() data}-property. * This {@link PredefinedDockSituation} will set the identifier whenever * a method of factory is called, that has a {@link BackupFactoryData} * as parameter. * @param factory a backup factory */ public void addBackup( DockFactory> factory ){ backups.put( UNKNOWN + factory.getID(), factory ); } /** * Removes the backup factory with the name id. * @param id the id of the factory which should be removed */ public void removeBackup( String id ){ backups.remove( UNKNOWN + id ); } /** * Registers an element at this situation. When a stream is read, this * element will be returned instead of a newly created element (assuming * that the element was written into the stream). The key for * the element is generated automatically.
* Note: the order in which elements are added is important as the * unique key depends on the order. * @param element the element * @deprecated use {@link #put(String, DockElement)} instead */ @Deprecated public void put( DockElement element ){ put( String.valueOf( stringToElement.size() ), element ); } /** * Registers an element at this situation. When a stream is read, this * element will be returned instead a newly created element (assuming * that the element was written into the stream). * @param key the key of the element * @param element the element * @throws IllegalArgumentException if the key is already used */ public void put( String key, DockElement element ){ if( stringToElement.containsKey( key )) throw new IllegalArgumentException( "Key does already exist: " + key ); stringToElement.put( key, element ); elementToString.put( element, key ); } /** * Tells whether the layout of element itself should be stored * or loaded, that will not prevent the element from showing * up but from changing its content. The default implementation returns * always true. This method is intended to be overridden by * subclasses. * @param element the element whose contents might or might not be stored * or loaded * @return true if the contents should be handled, false * if they should be discarded */ protected boolean shouldLayout( DockElement element ){ return true; } /** * Tells whether the layout of element itself should be stored * or loaded, that will not prevent the element from showing * up but from changing its content. The default implementation uses the maps * of perspective and this {@link DockSituation} to convert element * into a preset {@link DockElement} and calls {@link #shouldLayout(DockElement)}. If the * element is not found, true is returned. * @param element the element whose contents might or might not be stored * or loaded * @param perspective the perspective for which the question has to be answered * @return true if the contents should be handled, false * if they should be discarded */ protected boolean shouldLayout( PerspectiveElement element, PredefinedPerspective perspective ){ String key = perspective.get( element ); if( key != null ){ DockElement dock = stringToElement.get( key ); if( dock != null ){ return shouldLayout( dock ); } } return true; } @Override protected DockLayoutInfo fillMissing( DockLayoutInfo info ) { DockLayout layout = info.getDataLayout(); if( KNOWN.equals( layout.getFactoryID() )){ PredefinedLayout preloaded = (PredefinedLayout)layout.getData(); DockLayoutInfo delegate = preloaded.getDelegate(); DockLayoutInfo newDelegate = null; if( delegate.getKind() == DockLayoutInfo.Data.BYTE ){ newDelegate = fillMissingStream( preloaded ); } else if( delegate.getKind() == DockLayoutInfo.Data.XML ){ newDelegate = fillMissingXML( preloaded ); } if( newDelegate != null ){ info = new DockLayoutInfo( new DockLayout( KNOWN, new PredefinedLayout( preloaded.getPredefined(), newDelegate ))); } } return info; } /** * Given a set of Dockables this method * estimates which of them will be visible once composition * is applied. * @param the kind of elements to check * @param base a collection of Dockables in no specific * order and with no restrictions * @param composition location information for various elements * @return A subset of base with those elements which will * be visible once this situation converts composition */ public Set listVisible( Collection base, DockLayoutComposition composition ){ Set result = new HashSet(); listVisible( base, composition, result ); return result; } @SuppressWarnings("unchecked") private void listVisible( final Collection base, DockLayoutComposition composition, final Set result ){ DockLayoutInfo info = composition.getLayout(); if( info.getKind() == DockLayoutInfo.Data.DOCK_LAYOUT ){ DockLayout layout = info.getDataLayout(); // preloaded element with key if( KNOWN.equals( layout.getFactoryID() )){ PredefinedLayout preload = (PredefinedLayout)layout.getData(); String key = preload.getPredefined(); DockElement element = stringToElement.get( key ); if( element != null ){ if( base.contains( element )){ result.add( (D)element ); } if( composition.isIgnoreChildren() ){ DockUtilities.visit( element, new DockUtilities.DockVisitor(){ @Override public void handleDockable( Dockable dockable ) { if( base.contains( dockable )){ result.add( (D)dockable ); } } @Override public void handleDockStation( DockStation station ) { if( base.contains( station )){ result.add( (D)station ); } } }); } } } } // check all children for( DockLayoutComposition child : composition.getChildren() ){ listVisible( base, child, result ); } } /** * Lists for all keys that can be found in composition its * estimated location.
* Note: This method will call {@link #estimateLocations(DockLayoutComposition)} * to get the most recent locations * @param composition some composition to search for keys and locations * @param missingOnly if set, then only locations of keys for which * no {@link DockLayout} is set are reported. This are the keys which most * likely will be ignored when calling {@link #convert(DockLayoutComposition)} * @return the map of keys and positions, might be empty */ public Map listEstimatedLocations( DockLayoutComposition composition, boolean missingOnly ){ return listEstimatedLocations( composition, composition.getLayout().getLocation(), missingOnly ); } /** * Lists for all keys that can be found in composition its * estimated location.
* Note: This method will call {@link #estimateLocations(DockLayoutComposition)} * to get the most recent locations * @param composition some composition to search for keys and locations * @param location the location of composition itself * @param missingOnly if set, then only locations of keys for which * no {@link DockLayout} is set are reported. This are the keys which most * likely will be ignored when calling {@link #convert(DockLayoutComposition)} * @return the map of keys and positions, might be empty */ public Map listEstimatedLocations( DockLayoutComposition composition, DockableProperty location, boolean missingOnly ){ estimateLocations( composition, location ); Map map = new HashMap(); listEstimatedLocations( composition, missingOnly, map ); if( location != null ){ String key = getKey( composition, missingOnly ); if( key != null ){ map.put( key, location ); } } return map; } private void listEstimatedLocations( DockLayoutComposition composition, boolean missingOnly, Map map ){ DockableProperty location = composition.getLayout().getLocation(); if( location != null ){ String key = getKey( composition, missingOnly ); if( key != null){ map.put( key, location ); } } List children = composition.getChildren(); if( children != null ){ for( DockLayoutComposition child : children ){ listEstimatedLocations( child, missingOnly, map ); } } } /** * Gets a map containing some or all of the named layouts. * @param composition some composition to analyze * @param missingOnly if set, then only locations of keys for which * no {@link DockLayout} is set are reported. This are the keys which most * likely will be ignored when calling {@link #convert(DockLayoutComposition)} * @return the map of keys and layouts, might be empty */ public Map listLayouts( DockLayoutComposition composition, boolean missingOnly ){ Map map = new HashMap(); listLayouts( composition, missingOnly, map ); return map; } private void listLayouts( DockLayoutComposition composition, boolean missingOnly, Map map ){ String key = getKey( composition, missingOnly ); if( key != null){ map.put( key, composition ); } List children = composition.getChildren(); if( children != null ){ for( DockLayoutComposition child : children ){ listLayouts( child, missingOnly, map ); } } } /** * Gets the name of element which is represented by composition. * @param composition the composition whose element key is searched * @param missingOnly if set, then the key will only be returned if composition * is not fully loaded * @return the key or null */ private String getKey( DockLayoutComposition composition, boolean missingOnly ){ DockLayoutInfo layout = composition.getLayout(); if( layout.getKind() != DockLayoutInfo.Data.DOCK_LAYOUT ) return null; if( !KNOWN.equals( layout.getDataLayout().getFactoryID() )) return null; PredefinedLayout preloaded = (PredefinedLayout)layout.getDataLayout().getData(); if( missingOnly && preloaded.getDelegate().getKind() == DockLayoutInfo.Data.DOCK_LAYOUT ){ // if there is such a Dockable registered then it is not missing... if( stringToElement.containsKey( preloaded.getPredefined() )){ return null; } } String key = preloaded.getPredefined(); return key; } /** * Tries to read the byte data in layout. * @param layout the layout to read * @return either a new info or null if the data could * not be read */ @SuppressWarnings("unchecked") private DockLayoutInfo fillMissingStream( PredefinedLayout layout ){ byte[] bytes = layout.getDelegate().getDataByte(); try{ DataInputStream in = new DataInputStream( new ByteArrayInputStream( bytes )); String factoryId = in.readUTF(); DockFactory factory = (DockFactory)getFactory( factoryId ); DockLayoutInfo info = null; if( factory == null ){ DockFactory> backup = getBackup( factoryId ); if( backup != null ){ BackupFactoryData data = (BackupFactoryData)backup.read( in, getPlaceholderStrategy() ); if( data != null && data.getData() != null ){ info = new DockLayoutInfo( new DockLayout( factoryId, data.getData() )); } } } else{ Object delegate = factory.read( in, getPlaceholderStrategy() ); if( delegate != null ){ info = new DockLayoutInfo( new DockLayout( factoryId, delegate )); } } in.close(); return info; } catch( IOException ex ){ throw new IllegalArgumentException( "Cannot read stream", ex ); } } /** * Tries to read the xml data in layout. * @param layout the layout to read * @return either a new info or null if the data could * not be read */ @SuppressWarnings("unchecked") private DockLayoutInfo fillMissingXML( PredefinedLayout layout ){ XElement xdelegate = layout.getDelegate().getDataXML(); String factoryId = xdelegate.getString( "id" ); Object delegate = null; DockFactory factory = (DockFactory)getFactory( factoryId ); if( factory == null ){ DockFactory> backup = getBackup( factoryId ); if( backup != null ){ BackupFactoryData data = (BackupFactoryData)backup.read( xdelegate, getPlaceholderStrategy() ); if( data != null ) delegate = data.getData(); } } else{ delegate = factory.read( xdelegate, getPlaceholderStrategy() ); } if( delegate == null ){ return null; } return new DockLayoutInfo( new DockLayout( factoryId, delegate ) ); } /** * Gets the identifier that matches element which is part of perspective. * @param element some element whose identifier is searched * @param perspective the owner of element * @return the identifier */ protected String getID( PerspectiveElement element, PredefinedPerspective perspective ){ String key = perspective.get( element ); if( key == null ) return UNKNOWN + super.getID( element ); else return KNOWN; } @Override public String getID( DockElement dockable ){ String key = elementToString.get( dockable ); if( key == null ) return UNKNOWN + super.getID( dockable ); else return KNOWN; } @Override protected String getID( DockFactory factory ) { if( factory == this.factory ) return KNOWN; else return UNKNOWN + super.getID( factory ); } @Override protected String getFactoryID( String id ) { if( KNOWN.equals( id )) return factory.getID(); else return id.substring( UNKNOWN.length() ); } /** * Given the unique identifier of a factory tells what identifier will be used * internally. This method may be useful if creating a {@link DockLayout} manually. * @param id the id of some factory * @return the id that will be used internally */ public static String convertFactoryID( String id ){ return UNKNOWN + id; } @Override public DockFactory getFactory( String id ){ if( KNOWN.equals( id )) return factory; else return super.getFactory( id ); } /** * Searches a backup factory with the name id. * @param id the name of the factory * @return the factory or null */ @SuppressWarnings( "unchecked" ) protected DockFactory> getBackup( String id ){ return (DockFactory>)backups.get( id ); } @Override public String getIdentifier( DockLayoutComposition composition ){ DockLayout layout = composition.getLayout().getDataLayout(); if( layout != null && layout.getFactoryID().equals( KNOWN )){ PredefinedLayout predefined = (PredefinedLayout) layout.getData(); return predefined.getPredefined(); } return null; } /** * A factory which uses other factories as delegate. This factory does * not always use the delegates, sometimes it does just read an element * which was predefined in {@link PredefinedDockSituation}. * @author Benjamin Sigg */ private class PreloadFactory implements DockFactory{ private PredefinedPerspective perspective; /** * Creates a new factory */ public PreloadFactory(){ // nothing } /** * Creates a new factory * @param perspective the perspective whose contents should be used for handling {@link PerspectiveElement} */ public PreloadFactory( PredefinedPerspective perspective ){ this.perspective = perspective; } public String getID() { return KNOWN; } @SuppressWarnings("unchecked") public void estimateLocations( PredefinedLayout layout, LocationEstimationMap children ){ DockLayoutInfo delegate = layout.getDelegate(); if( delegate.getKind() == DockLayoutInfo.Data.DOCK_LAYOUT ){ String factoryId = delegate.getDataLayout().getFactoryID(); DockFactory factory = (DockFactory)getFactory( factoryId ); if( factory != null ){ factory.estimateLocations( delegate.getDataLayout().getData(), children ); } } } @SuppressWarnings("unchecked") public PredefinedLayout getLayout( DockElement element, Map children ) { if( shouldLayout( element )){ String factoryId = UNKNOWN + PredefinedDockSituation.super.getID( element ); DockFactory factory = (DockFactory)getFactory( factoryId ); if( factory == null ) throw new IllegalStateException( "Missing factory: " + factoryId ); Object data = factory.getLayout( element, children ); DockLayout layout = new DockLayout( factoryId, data ); return new PredefinedLayout( elementToString.get( element ), new DockLayoutInfo( layout )); } else{ return new PredefinedLayout( elementToString.get( element ), new DockLayoutInfo() ); } } @SuppressWarnings("unchecked") public void setLayout( DockElement element, PredefinedLayout layout, Map children, PlaceholderStrategy placeholders ) { DockLayoutInfo delegate = layout.getDelegate(); if( delegate.getKind() == DockLayoutInfo.Data.DOCK_LAYOUT && shouldLayout( element )){ String factoryId = delegate.getDataLayout().getFactoryID(); DockFactory factory = (DockFactory)getFactory( factoryId ); if( factory != null ){ DockController controller = element.getController(); try{ if( controller != null ) controller.freezeLayout(); factory.setLayout( element, delegate.getDataLayout().getData(), children, placeholders ); } finally{ if( controller != null ) controller.meltLayout(); } } } } @SuppressWarnings("unchecked") public void setLayout( DockElement element, PredefinedLayout layout, PlaceholderStrategy placeholders ) { DockLayoutInfo delegate = layout.getDelegate(); if( delegate.getKind() == DockLayoutInfo.Data.DOCK_LAYOUT && shouldLayout( element )){ String factoryId = delegate.getDataLayout().getFactoryID(); DockFactory factory = (DockFactory)getFactory( factoryId ); if( factory != null ){ DockController controller = element.getController(); try{ if( controller != null ) controller.freezeLayout(); factory.setLayout( element, delegate.getDataLayout().getData(), placeholders ); } finally{ if( controller != null ) controller.meltLayout(); } } } } public DockElement layout( PredefinedLayout layout, Map children, PlaceholderStrategy placeholders ) { DockLayoutInfo delegate = layout.getDelegate(); boolean isLayout = delegate.getKind() == DockLayoutInfo.Data.DOCK_LAYOUT; boolean isNull = delegate.getKind() == DockLayoutInfo.Data.NULL; if( !isLayout && !isNull ){ return null; } DockElement element = stringToElement.get( layout.getPredefined() ); if( element == null && isLayout ){ String factoryId = delegate.getDataLayout().getFactoryID(); DockFactory> factory = getBackup( factoryId ); if( factory != null ){ return factory.layout( new BackupFactoryData( layout.getPredefined(), delegate.getDataLayout().getData()), children, placeholders ); } return null; } setLayout( element, layout, children, placeholders ); return element; } public DockElement layout( PredefinedLayout layout, PlaceholderStrategy placeholders ) { DockLayoutInfo delegate = layout.getDelegate(); boolean isLayout = delegate.getKind() == DockLayoutInfo.Data.DOCK_LAYOUT; boolean isNull = delegate.getKind() == DockLayoutInfo.Data.NULL; if( !isLayout && !isNull ){ return null; } DockElement element = stringToElement.get( layout.getPredefined() ); if( element == null && isLayout ){ if( layout.getDelegate() == null ) return null; String factoryId = delegate.getDataLayout().getFactoryID(); DockFactory> factory = getBackup( factoryId ); if( factory != null ){ return factory.layout( new BackupFactoryData( layout.getPredefined(), delegate.getDataLayout().getData()), placeholders); } return null; } setLayout( element, layout, placeholders ); return element; } @SuppressWarnings("unchecked") public PerspectiveElement layoutPerspective( PredefinedLayout layout, Map children ){ if( perspective == null ){ throw new IllegalStateException( "the perspective of this factory is not set, meaning this factory cannot be used handling perspective dependent tasks" ); } DockLayoutInfo delegate = layout.getDelegate(); boolean isLayout = delegate.getKind() == DockLayoutInfo.Data.DOCK_LAYOUT; boolean isNull = delegate.getKind() == DockLayoutInfo.Data.NULL; if( !isLayout && !isNull ){ return null; } PerspectiveElement element = perspective.get( layout.getPredefined() ); if( element == null && isLayout ){ String factoryId = delegate.getDataLayout().getFactoryID(); DockFactory factory = getBackup( factoryId ); if( factory != null ){ return factory.layoutPerspective(new BackupFactoryData( layout.getPredefined(), delegate.getDataLayout().getData()), children ); } return null; } layoutPerspective( element, layout, children ); return element; } @SuppressWarnings("unchecked") public void layoutPerspective( PerspectiveElement element, PredefinedLayout layout, Map children ){ DockLayoutInfo delegate = layout.getDelegate(); if( delegate.getKind() == DockLayoutInfo.Data.DOCK_LAYOUT && shouldLayout( element, perspective )){ String factoryId = delegate.getDataLayout().getFactoryID(); DockFactory factory = getFactory( factoryId ); if( factory != null ){ factory.layoutPerspective( element, delegate.getDataLayout().getData(), children ); } } } @SuppressWarnings("unchecked") public PredefinedLayout getPerspectiveLayout( PerspectiveElement element, Map children ){ if( perspective == null ){ throw new IllegalStateException( "the perspective of this factory is not set, meaning this factory cannot be used handling perspective dependent tasks" ); } DockLayoutInfo info; if( shouldLayout( element, perspective )){ String factoryId = UNKNOWN + PredefinedDockSituation.super.getID( element ); DockFactory factory = getFactory( factoryId ); if( factory == null ) throw new IllegalStateException( "Missing factory: " + factoryId ); Object data = factory.getPerspectiveLayout( element, children ); DockLayout layout = new DockLayout( factoryId, data ); info = new DockLayoutInfo( layout ); } else{ info = new DockLayoutInfo(); } String key = perspective.get( element ); if( key == null ){ throw new IllegalStateException( "Expected a key for an element, the element should be known to the perspective, otherwise this method would not have been called: '" + element +"'" ); } return new PredefinedLayout( key, info ); } @SuppressWarnings("unchecked") public void write( PredefinedLayout layout, DataOutputStream out ) throws IOException { Version.write( out, Version.VERSION_1_0_7 ); DockLayoutInfo info = layout.getDelegate(); out.writeUTF( layout.getPredefined() ); if( info.getKind() == DockLayoutInfo.Data.BYTE ){ out.writeBoolean( true ); out.write( info.getDataByte() ); } else if( info.getKind() == DockLayoutInfo.Data.DOCK_LAYOUT ){ out.writeBoolean( true ); DockLayout delegate = info.getDataLayout(); String factoryId = delegate.getFactoryID(); DockFactory factory = (DockFactory)getFactory( factoryId ); if( factory == null ) throw new IOException( "Missing factory: " + factoryId ); out.writeUTF( factoryId ); factory.write( delegate.getData(), out ); } else if( info.getKind() == DockLayoutInfo.Data.NULL ){ out.writeBoolean( false ); } else{ throw new IllegalArgumentException( "Cannot store information as byte[], it is not present as raw byte[] or in an understandable format" ); } } @SuppressWarnings("unchecked") public PredefinedLayout read( DataInputStream in, PlaceholderStrategy placeholders ) throws IOException { Version version = Version.read( in ); version.checkCurrent(); boolean version7 = Version.VERSION_1_0_7.compareTo( version ) <= 0; String preloaded = in.readUTF(); boolean nullValue = false; if( version7 ){ nullValue = !in.readBoolean(); } DockLayoutInfo info = null; if( nullValue ){ info = new DockLayoutInfo(); } else{ String factoryId = in.readUTF(); DockFactory factory = (DockFactory)getFactory( factoryId ); if( factory == null ){ DockFactory backup = getBackup( factoryId ); if( backup != null ){ BackupFactoryData data = (BackupFactoryData)backup.read( in, placeholders ); if( data != null && data.getData() != null ){ info = new DockLayoutInfo( new DockLayout( factoryId, data.getData() )); } } else{ // store as byte[] ByteArrayOutputStream out = new ByteArrayOutputStream(); DataOutputStream dout = new DataOutputStream( out ); dout.writeUTF( factoryId ); int read; while( (read = in.read()) != -1 ){ dout.write( read ); } dout.close(); info = new DockLayoutInfo( out.toByteArray() ); } } else{ Object delegate = factory.read( in, placeholders ); if( delegate != null ){ info = new DockLayoutInfo( new DockLayout( factoryId, delegate )); } } } if( info == null ) return null; return new PredefinedLayout( preloaded, info ); } @SuppressWarnings("unchecked") public void write( PredefinedLayout layout, XElement element ) { element.addElement( "replacement" ).addString( "id", layout.getPredefined() ); DockLayoutInfo info = layout.getDelegate(); if( info.getKind() == DockLayoutInfo.Data.XML ){ element.addElement( info.getDataXML() ); } else if( info.getKind() == DockLayoutInfo.Data.DOCK_LAYOUT ){ DockLayout delegate = layout.getDelegate().getDataLayout(); String factoryId = delegate.getFactoryID(); DockFactory factory = (DockFactory)getFactory( factoryId ); if( factory == null ) throw new XException( "Missing factory: " + factoryId ); XElement xdelegate = element.addElement( "delegate" ); xdelegate.addString( "id", factoryId ); factory.write( delegate.getData(), xdelegate ); } else if( info.getKind() == DockLayoutInfo.Data.NULL ){ // nothing to store } else{ throw new IllegalArgumentException( "Cannot store information as xml, it is neither present as raw xml nor in an understandable format" ); } } @SuppressWarnings("unchecked") public PredefinedLayout read( XElement element, PlaceholderStrategy placeholders ) { String preload = element.getElement( "replacement" ).getString( "id" ); XElement xdelegate = element.getElement( "delegate" ); if( xdelegate == null ){ return new PredefinedLayout( preload, new DockLayoutInfo() ); } String factoryId = xdelegate.getString( "id" ); Object delegate = null; DockFactory factory = (DockFactory)getFactory( factoryId ); if( factory == null ){ DockFactory backup = getBackup( factoryId ); if( backup != null ){ BackupFactoryData data = (BackupFactoryData)backup.read( xdelegate, placeholders ); if( data != null ) delegate = data.getData(); } } else{ delegate = factory.read( xdelegate, placeholders ); } if( delegate == null ){ return new PredefinedLayout( preload, new DockLayoutInfo( xdelegate )); } else{ DockLayout layout = new DockLayout( factoryId, delegate ); return new PredefinedLayout( preload, new DockLayoutInfo( layout ) ); } } } }