Part 1: some examples how the position of a Dockable can be set (using Core only).
1: just drop it at the correct location
2: drop it over an existing location
3. predefine location for each Dockable using perspectives (that would be the advanced solution)
I admit, I’ve written these examples in a hurry… If you have only a limited set of Dockables, or know at least some Dockables in advance, then I would strongly suggest to use the 3. option for setting up some of the initial locations.
The answer to your second question will be available soon.
import java.awt.BorderLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JButton;
import javax.swing.JFrame;
import bibliothek.gui.DockFrontend;
import bibliothek.gui.dock.DefaultDockable;
import bibliothek.gui.dock.SplitDockStation;
import bibliothek.gui.dock.station.split.SplitDockProperty;
/*
* Method 1: easy, but results are not very good
*/
public class Dock77 {
private static int index = 0;
public static void main( String[] args ){
JFrame frame = new JFrame();
DockFrontend frontend = new DockFrontend( frame );
frame.setDefaultCloseOperation( JFrame.EXIT_ON_CLOSE );
SplitDockStation station = new SplitDockStation();
frontend.addRoot( "split", station );
frame.add( station );
frame.add( create( frontend, station, SplitDockProperty.NORTH ), BorderLayout.NORTH );
frame.add( create( frontend, station, SplitDockProperty.SOUTH ), BorderLayout.SOUTH );
frame.add( create( frontend, station, SplitDockProperty.EAST ), BorderLayout.EAST );
frame.add( create( frontend, station, SplitDockProperty.WEST ), BorderLayout.WEST );
frame.setBounds( 20, 20, 400, 400 );
frame.setVisible( true );
}
private static JButton create( final DockFrontend frontend, final SplitDockStation station, final SplitDockProperty location ){
JButton button = new JButton("add");
button.addActionListener( new ActionListener(){
@Override
public void actionPerformed( ActionEvent e ){
DefaultDockable dockable = new DefaultDockable( "Title " + index );
frontend.addDockable( "id " + index, dockable );
station.drop( dockable, location );
index++;
}
});
return button;
}
}```
```package test;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JButton;
import javax.swing.JFrame;
import bibliothek.gui.DockFrontend;
import bibliothek.gui.DockStation;
import bibliothek.gui.dock.DefaultDockable;
import bibliothek.gui.dock.SplitDockStation;
import bibliothek.gui.dock.layout.DockableProperty;
import bibliothek.gui.dock.util.DockUtilities;
/*
* Method 2: take a Dockable whose location you already know and duplicate that location
*/
public class Dock78 {
private static int index = 0;
public static void main( String[] args ){
JFrame frame = new JFrame();
DockFrontend frontend = new DockFrontend( frame );
frame.setDefaultCloseOperation( JFrame.EXIT_ON_CLOSE );
SplitDockStation station = new SplitDockStation();
frontend.addRoot( "split", station );
frame.add( station );
station.drop( new CustomDockable( frontend ) );
frame.setBounds( 20, 20, 400, 400 );
frame.setVisible( true );
}
private static class CustomDockable extends DefaultDockable{
public CustomDockable( final DockFrontend frontend ){
super( "Title " + index );
frontend.addDockable( "id " + index, this );
index++;
JButton button = new JButton( "clone" );
button.addActionListener( new ActionListener(){
@Override
public void actionPerformed( ActionEvent e ){
DockStation root = DockUtilities.getRoot( CustomDockable.this );
DockableProperty location = DockUtilities.getPropertyChain( root, CustomDockable.this );
CustomDockable copy = new CustomDockable( frontend );
root.drop( copy, location );
}
});
add( button );
}
}
}```
```package test;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.util.Map;
import javax.swing.JFrame;
import javax.swing.JMenu;
import javax.swing.JMenuBar;
import javax.swing.JMenuItem;
import bibliothek.gui.DockFrontend;
import bibliothek.gui.DockStation;
import bibliothek.gui.Dockable;
import bibliothek.gui.dock.DefaultDockable;
import bibliothek.gui.dock.DockFactory;
import bibliothek.gui.dock.SplitDockStation;
import bibliothek.gui.dock.frontend.FrontendDockablePerspective;
import bibliothek.gui.dock.frontend.Setting;
import bibliothek.gui.dock.layout.LocationEstimationMap;
import bibliothek.gui.dock.perspective.PerspectiveDockable;
import bibliothek.gui.dock.perspective.PredefinedPerspective;
import bibliothek.gui.dock.station.split.PerspectiveSplitDockGrid;
import bibliothek.gui.dock.station.split.SplitDockPerspective;
import bibliothek.gui.dock.station.split.SplitDockPlaceholderProperty;
import bibliothek.gui.dock.station.support.PlaceholderStrategy;
import bibliothek.gui.dock.station.support.PlaceholderStrategyListener;
import bibliothek.util.Path;
import bibliothek.util.xml.XElement;
/*
* Method 3: if you know some of the Dockables in advance, you can make use of perspectives to set their initial position
*/
public class Dock79 {
public static void main( String[] args ){
JFrame frame = new JFrame();
final DockFrontend frontend = new DockFrontend( frame );
frame.setDefaultCloseOperation( JFrame.EXIT_ON_CLOSE );
SplitDockStation station = new SplitDockStation();
frontend.addRoot( "split", station );
frame.add( station );
frontend.registerFactory( new CustomDockableFactory(), true );
JMenu menu = new JMenu( "Dockables" );
menu.add( createItem( frontend, "a" ) );
menu.add( createItem( frontend, "b" ) );
menu.add( createItem( frontend, "c" ) );
menu.add( createItem( frontend, "d" ) );
menu.add( createItem( frontend, "e" ) );
menu.add( createItem( frontend, "f" ) );
menu.add( createItem( frontend, "g" ) );
menu.add( createItem( frontend, "h" ) );
JMenuBar bar = new JMenuBar();
bar.add( menu );
frame.setJMenuBar( bar );
// enable placeholders
allowPlaceholders( frontend );
// setup the layout
setupInitialLayout( frontend );
frame.setBounds( 20, 20, 400, 400 );
frame.setVisible( true );
}
private static JMenuItem createItem( final DockFrontend frontend, final String id ){
JMenuItem item = new JMenuItem( id );
item.addActionListener( new ActionListener(){
@Override
public void actionPerformed( ActionEvent e ){
// switches the visibility of the dockable with id "id". Create new dockables if required
Dockable dockable = frontend.getDockable( id );
if( dockable == null ){
dockable = new CustomDockable( id );
// new dockables need to be registered...
frontend.addDockable( id, dockable );
// ... and their initial location must be associated with the correct placeholder
frontend.getFrontendEntry( id ).setLocation( "split", new SplitDockPlaceholderProperty( new Path( "custom", id ) ) );
frontend.setHideable( dockable, true );
}
if( frontend.isShown( dockable )){
frontend.hide( dockable );
}
else{
frontend.show( dockable );
}
}
});
return item;
}
private static void allowPlaceholders( final DockFrontend frontend ){
// add a simple placeholder-strategy that enables all placeholders
frontend.getController().getProperties().set( PlaceholderStrategy.PLACEHOLDER_STRATEGY, new PlaceholderStrategy(){
@Override
public void uninstall( DockStation station ){
// ignore
}
@Override
public void removeListener( PlaceholderStrategyListener listener ){
// ignore
}
@Override
public boolean isValidPlaceholder( Path placeholder ){
return true;
}
@Override
public void install( DockStation station ){
// ignore
}
@Override
public Path getPlaceholderFor( Dockable dockable ){
String name = frontend.getNameOf( dockable );
if( name == null ){
return null;
}
return new Path( "custom", name );
}
@Override
public void addListener( PlaceholderStrategyListener listener ){
// ignore
}
});
}
private static void setupInitialLayout( DockFrontend frontend ){
// Admitted, the next two lines are a hack...
PredefinedPerspective perspective = (PredefinedPerspective)frontend.getPerspective( false );
SplitDockPerspective split = (SplitDockPerspective)perspective.get( "rootsplit" );
// build up the initial layout
PerspectiveSplitDockGrid grid = new PerspectiveSplitDockGrid();
grid.addDockable( 0, 0, 1, 1, new CustomDockablePerspective( "a" ) );
grid.addDockable( 0, 0, 1, 1, new CustomDockablePerspective( "b" ) );
grid.addPlaceholders( 0, 0, 1, 1, new Path( "custom", "c" ) );
grid.addPlaceholders( 0, 0, 1, 1, new Path( "custom", "d" ) );
grid.addDockable( 1, 0, 1, 1, new CustomDockablePerspective( "e" ) );
grid.addDockable( 1, 0, 1, 1, new CustomDockablePerspective( "f" ) );
grid.addPlaceholders( 1, 0, 1, 1, new Path( "custom", "g" ) );
grid.addPlaceholders( 1, 0, 1, 1, new Path( "custom", "h" ) );
// deploy layout on station
split.read( grid.toTree(), null );
// convert the perspective into the intermediate format and apply the layout
Setting setting = new Setting();
setting.putRoot( "split", perspective.convert( split ) );
frontend.setSetting( setting, false );
for( Dockable dockable : frontend.listDockables() ){
frontend.setHideable( dockable, true );
}
}
// a simple representation of our CustomDockable
private static class CustomDockablePerspective extends FrontendDockablePerspective{
public CustomDockablePerspective( String id ){
super( id );
}
@Override
public String getFactoryID(){
return "custom";
}
}
// Our custom implementation of a dockable, notice that it has a custom "factory id"
private static class CustomDockable extends DefaultDockable{
private String id;
public CustomDockable( String id ){
setTitleText( "Title " + id );
setFactoryID( "custom" );
this.id = id;
}
public String getId(){
return id;
}
}
// this factory will read/write instances of our CustomDockable
private static class CustomDockableFactory implements DockFactory<CustomDockable, CustomDockablePerspective, String>{
@Override
public void estimateLocations( String layout, LocationEstimationMap children ){
// ignore
}
@Override
public CustomDockable layout( String layout, Map<Integer, Dockable> children, PlaceholderStrategy placeholders ){
return new CustomDockable( layout );
}
@Override
public CustomDockable layout( String layout, PlaceholderStrategy placeholders ){
return new CustomDockable( layout );
}
@Override
public CustomDockablePerspective layoutPerspective( String layout, Map<Integer, PerspectiveDockable> children ){
return new CustomDockablePerspective( layout );
}
@Override
public void layoutPerspective( CustomDockablePerspective perspective, String layout, Map<Integer, PerspectiveDockable> children ){
// nothing to do
}
@Override
public String getID(){
return "custom";
}
@Override
public String getLayout( CustomDockable element, Map<Dockable, Integer> children ){
return element.getId();
}
@Override
public String getPerspectiveLayout( CustomDockablePerspective element, Map<PerspectiveDockable, Integer> children ){
return element.getId();
}
@Override
public String read( DataInputStream in, PlaceholderStrategy placeholders ) throws IOException{
return in.readUTF();
}
@Override
public String read( XElement element, PlaceholderStrategy placeholders ){
return element.getString();
}
@Override
public void setLayout( CustomDockable element, String layout, Map<Integer, Dockable> children, PlaceholderStrategy placeholders ){
// nothing to do
}
@Override
public void setLayout( CustomDockable element, String layout, PlaceholderStrategy placeholders ){
// nothing to do
}
@Override
public void write( String layout, DataOutputStream out ) throws IOException{
out.writeUTF( layout );
}
@Override
public void write( String layout, XElement element ){
element.setString( layout );
}
}
}```