package tutorial.common.guide; import java.awt.BorderLayout; import java.awt.Color; import java.io.DataInputStream; import java.io.DataOutputStream; import java.io.IOException; import java.util.HashMap; import java.util.Map; import javax.swing.JPanel; import tutorial.support.ColorSingleCDockable; import tutorial.support.JTutorialFrame; import tutorial.support.Tutorial; import bibliothek.gui.dock.common.CControl; import bibliothek.gui.dock.common.DefaultMultipleCDockable; import bibliothek.gui.dock.common.MultipleCDockableFactory; import bibliothek.gui.dock.common.MultipleCDockableLayout; import bibliothek.gui.dock.common.SingleCDockable; import bibliothek.gui.dock.common.SingleCDockableFactory; import bibliothek.gui.dock.common.mode.ExtendedMode; import bibliothek.gui.dock.common.perspective.CControlPerspective; import bibliothek.gui.dock.common.perspective.CDockablePerspective; import bibliothek.gui.dock.common.perspective.CGridPerspective; import bibliothek.gui.dock.common.perspective.CMinimizePerspective; import bibliothek.gui.dock.common.perspective.CPerspective; import bibliothek.gui.dock.common.perspective.CWorkingPerspective; import bibliothek.gui.dock.common.perspective.MultipleCDockablePerspective; import bibliothek.gui.dock.common.perspective.SingleCDockablePerspective; import bibliothek.gui.dock.facile.mode.Location; import bibliothek.gui.dock.layout.DockableProperty; import bibliothek.gui.dock.station.flap.FlapDockProperty; import bibliothek.util.Filter; import bibliothek.util.xml.XElement; @Tutorial( title="Perspectives (History)", id="PerspectivesHistory" ) public class PerspectivesHistory { /* CDockables not only have a current location, they also have a history of locations. * For example if a CDockable was minimized on the east side of the application, then this * location "minimized east" is stored in the history and used if the user minimizes the * dockable the next time. * * The perspective API allows create and modify the history of each dockable, this example * sets up several dockables at different locations with a history. * **** * IMPORTANT: In this example we set the history of MultipleCDockables. We need to * manually set the identifiers of the MultipleCDockablePerspectives to get this working. **** */ /* We are going to work with MultipleCDockables so we need a factory and an identifier * for this factory. */ public static final String CUSTOM_MULTI_FACTORY_ID = "custom"; public static void main( String[] args ){ JTutorialFrame frame = new JTutorialFrame( PerspectivesHistory.class ); CControl control = new CControl( frame ); frame.destroyOnClose( control ); /* When working with perspectives it is always a good idea first to set up the * CControl, then create the perspectives. */ ColorFactory colorFactory = new ColorFactory(); control.addSingleDockableFactory( colorFactory, colorFactory ); control.addMultipleDockableFactory( CUSTOM_MULTI_FACTORY_ID, new CustomMultiFactory() ); /* By creating the root-stations now we automatically create counterparts in the * perspective. Otherwise we would need to do some setting up with the perspectives as * well. */ frame.add( control.getContentArea(), BorderLayout.CENTER ); control.createWorkingArea( "work" ); /* Access to the perspective API */ CControlPerspective perspectives = control.getPerspectives(); /* Creating a new, empty perspective */ CPerspective perspective = perspectives.createEmptyPerspective(); /* For building up a history we need to move around CDockablePerspectives. It is * not possible to use several dockables with the same identifier. To make things * easier we just store the dockables in a map. In a real application you probably * want to implement a more advanced mechanism to store and access your dockables. * * IMPORTANT: the unique identifier of MultipleCDockablePerspectives is set by this method. */ Map<String, CDockablePerspective> dockables = collect(); /* We start by assigned the minimized location of all dockables. */ setUpMinimized( perspective, dockables ); /* Now we assign the normalized location of all dockables. */ setUpNormalized( perspective, dockables ); /* It is also possible to access and modify the location history directly. */ modifyHistoryDirectly( perspective, dockables ); /* At the end we set up the layout that the user will see when the application starts. */ setUpFinalLayout( perspective, dockables ); /* By calling "shrink" we instruct the perspective to remove unnecessary * PerspectiveStations from the layout. This is what the SingleParentRemover will do * with real DockStations. */ perspective.shrink(); /* Finally we apply the perspective we just created */ perspectives.setPerspective( perspective, true ); frame.setVisible( true ); } /* This method creates several dockable-perspectives and stores them in a map. */ private static Map<String, CDockablePerspective> collect(){ Map<String, CDockablePerspective> result = new HashMap<String, CDockablePerspective>(); result.put( "Red", new SingleCDockablePerspective( "Red" ) ); result.put( "Green", new SingleCDockablePerspective( "Green" ) ); result.put( "Blue", new SingleCDockablePerspective( "Blue" ) ); result.put( "Yellow", new SingleCDockablePerspective( "Yellow" ) ); result.put( "White", new SingleCDockablePerspective( "White" ) ); result.put( "Black", new SingleCDockablePerspective( "Black" ) ); for( int i = 0; i < 5; i++ ){ CustomMultiLayout layout = new CustomMultiLayout( new Color( 0, i*20, 50 )); String id = "m" + i; /* When creating the new MultipleCDockablePerspective we directly assign a unique identifier. * If we do not assign the identifier the framework will assign a random identifier in the moment * when the layout is converted to the intermediate format. As this happens at the very end, the * dockable will run around without identifier for a long time. But without identifier history * information cannot be created properly. The reason is that the framework uses placeholders to indicate * where a dockable was shown, and these placeholders depend on the unique identifiers of the dockables. */ result.put( id, new MultipleCDockablePerspective( CUSTOM_MULTI_FACTORY_ID, id, layout )); } return result; } /* This method assigns the minimized location to the dockables */ private static void setUpMinimized( CPerspective perspective, Map<String, CDockablePerspective> dockables ){ /* In the beginning we access different minimize-perspectives and just drop our dockables * onto them. */ CMinimizePerspective west = perspective.getContentArea().getWest(); west.add( dockables.get( "Red" ) ); west.add( dockables.get( "Green" ) ); west.add( dockables.get( "Blue" ) ); CMinimizePerspective east = perspective.getContentArea().getEast(); east.add( dockables.get( "Yellow" ) ); east.add( dockables.get( "White" ) ); east.add( dockables.get( "Black" ) ); CMinimizePerspective south = perspective.getContentArea().getSouth(); for( int i = 0; i < 5; i++ ){ south.add( dockables.get( "m" + i ) ); } /* And then we instruct the framework that the current location of the dockables should * be stored as history information. * The dockables remain at their current location, but we can just re-arrange them later. */ perspective.storeLocations(); } /* This method assigns the normalized location to the dockables. It works very much the same * as the method "setUpMinimized" just above. */ private static void setUpNormalized( CPerspective perspective, Map<String, CDockablePerspective> dockables ){ CGridPerspective center = perspective.getContentArea().getCenter(); CWorkingPerspective work = (CWorkingPerspective)perspective.getStation( "work" ); center.gridAdd( 0, 0, 50, 25, dockables.get( "Red" )); center.gridAdd( 50, 0, 50, 25, dockables.get( "Green" )); center.gridAdd( 0, 25, 50, 25, dockables.get( "Blue" )); center.gridAdd( 50, 25, 50, 25, dockables.get( "Yellow" )); center.gridAdd( 0, 50, 100, 50, work ); work.gridAdd( 0, 0, 50, 100, dockables.get( "White" ), dockables.get( "Black" )); for( int i = 0; i < 5; i++ ){ work.gridAdd( 50, 0, 50, 100, dockables.get( "m" + i ) ); } perspective.storeLocations(); } /* It is possible to access and modify history information directly. In this case * modify the history of the "White" dockable such that it thinks it was minimized * on the "north" minimize-area. */ private static void modifyHistoryDirectly( CPerspective perspective, Map<String, CDockablePerspective> dockables ){ CMinimizePerspective north = perspective.getContentArea().getNorth(); CDockablePerspective white = dockables.get( "White" ); /* We first inform the north minimize-area that "white" was a child by * inserting a placeholder for "white" */ north.addPlaceholder( white ); /* Now we build up location information first by specifying the exact location of "white" */ DockableProperty property = new FlapDockProperty( 0, false, 100, white.intern().asDockable().getPlaceholder() ); /* We pack additional information like the mode and the root-station that was the parent of * "white" together. */ Location location = new Location( ExtendedMode.MINIMIZED.getModeIdentifier(), north.getUniqueId(), property ); /* And finally we add the new location information to the history. */ white.getLocationHistory().add( ExtendedMode.MINIMIZED, location ); } /* After building up the history we set up the layout that we show the user when the * applications starts. */ private static void setUpFinalLayout( CPerspective perspective, Map<String, CDockablePerspective> dockables ){ /* We minimize the "red" and the "black" dockable */ CMinimizePerspective west = perspective.getContentArea().getWest(); west.add( dockables.get( "Red" ) ); CMinimizePerspective east = perspective.getContentArea().getEast(); east.add( dockables.get( "Black" ) ); } /* This factory and filter creates new SingleCDockables with some panel that has some * special color set as background. */ private static class ColorFactory implements SingleCDockableFactory, Filter<String>{ private Map<String, Color> colors = new HashMap<String, Color>(); public ColorFactory(){ colors.put( "Red", Color.RED ); colors.put( "Green", Color.GREEN ); colors.put( "Blue", Color.BLUE ); colors.put( "Yellow", Color.YELLOW ); colors.put( "White", Color.WHITE ); colors.put( "Black", Color.BLACK ); } public boolean includes( String item ){ return colors.containsKey( item ); } public SingleCDockable createBackup( String id ){ return new ColorSingleCDockable( id, colors.get( id ) ); } } /* This is the kind of MultipleCDockable we will use on our application. */ private static class CustomMultiDockable extends DefaultMultipleCDockable{ private Color color; public CustomMultiDockable( CustomMultiFactory factory, String title, Color color ){ super( factory, title ); this.color = color; JPanel panel = new JPanel(); panel.setBackground( color ); panel.setOpaque( true ); add( panel, BorderLayout.CENTER ); } public Color getColor(){ return color; } } /* This kind of MultipleCDockableLayout describes the content of a CustomMultiDockable. */ private static class CustomMultiLayout implements MultipleCDockableLayout{ private Color color; public CustomMultiLayout( Color color ){ this.color = color; } public Color getColor(){ return color; } public void readStream( DataInputStream in ) throws IOException{ color = new Color( in.readInt() ); } public void readXML( XElement element ){ color = new Color( element.getInt() ); } public void writeStream( DataOutputStream out ) throws IOException{ out.writeInt( color.getRGB() ); } public void writeXML( XElement element ){ element.setInt( color.getRGB() ); } } /* And this factory creates new CustomMultiDockables and new CustomMultiLayouts when * the framework needs them. */ private static class CustomMultiFactory implements MultipleCDockableFactory<CustomMultiDockable, CustomMultiLayout>{ public CustomMultiLayout create(){ return new CustomMultiLayout( null ); } public boolean match( CustomMultiDockable dockable, CustomMultiLayout layout ){ return dockable.getColor().equals( layout.getColor() ); } public CustomMultiDockable read( CustomMultiLayout layout ){ Color color = layout.getColor(); String title = "R=" + color.getRed() + ", G=" + color.getGreen() + ", B=" + color.getBlue(); return new CustomMultiDockable( this, title, color ); } public CustomMultiLayout write( CustomMultiDockable dockable ){ return new CustomMultiLayout( dockable.getColor() ); } } }