I think that when a PredefinedDockFactory wraps my factory, it is able to show a dockable only if the dockable exists in the Frontend’s cache. If the dockable does not exist in the cache, then it does not call the layout() method of my factory to get the dockable.
Is my understanding correct? If so, is there a way to get around this?
That’s correct. You use the frontend in a way that I did not anticipate.
Well, you could write your own caching mechanism and completely forget DockFrontend…
Or you could use the snapshot of the next version - which miraculously has a new feature that allows to add a „backup factory“ to DockFrontend.
The new library can be found here.
This „backup factory“ is used whenever an element is read that is missing in the cache. The frontend even inserts the missing element into its cache - with the name the element had when it was stored (there can be no conflicts in the cache, if the element would have the same name as an already existing element, then it would be overridden by the existing element).
The only thing you have to do, is to replace every occurrence of…
frontend.registerFactory( someFactory );
… by …
frontend.registerBackupFactory( someFactory );```
.. or the short version ...
```frontend.registerFactory( someFactory, true );```
----
I've rewritten the small example we had earlier in order to support the new backup factory. The important change is around lines 50-60 (don't worry about the two factories, I just use two of them to simulate a more complex application).
On the first startup, we do not have a xml-file:
shown:
added: A name=a
added: B name=b
shown: A
shown: B
It is written on shutdown:
getLayout: A > Text from A
getLayout: B > Text from B
write: A > Text from A
write: B > Text from B
Using the old version: If we start the application now, without putting "A" and "B" in the cache, then we would get a blank frame:
shown:
read: A > Text from A
read: B > Text from B
In the new version however, the backup factory jumps in, creates and registers two new Dockables:
shown:
read: A > Text from A
read: B > Text from B
layout: A > Text from A
added: A name=a
layout: B > Text from B
added: B name=b
shown: A
shown: B
And that is the code:
```import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.io.*;
import java.util.Map;
import javax.swing.JFrame;
import javax.swing.JScrollPane;
import javax.swing.JTextArea;
import bibliothek.gui.DockFrontend;
import bibliothek.gui.Dockable;
import bibliothek.gui.dock.DefaultDockable;
import bibliothek.gui.dock.DockFactory;
import bibliothek.gui.dock.SplitDockStation;
import bibliothek.gui.dock.event.DockFrontendAdapter;
import bibliothek.gui.dock.station.split.SplitDockGrid;
import bibliothek.util.xml.XElement;
import bibliothek.util.xml.XIO;
public class Dock2 {
public static void main( String[] args ){
final JFrame frame = new JFrame( "Demo" );
final DockFrontend frontend = new DockFrontend( frame );
frontend.addFrontendListener( new DockFrontendAdapter(){
@Override
public void added( DockFrontend frontend, Dockable dockable ) {
System.out.println( "added: " + dockable.getTitleText() + " name=" + frontend.getNameOf( dockable ) );
}
@Override
public void removed( DockFrontend frontend, Dockable dockable ) {
System.out.println( "removed: " + dockable.getTitleText() );
}
@Override
public void shown( DockFrontend frontend, Dockable dockable ) {
System.out.println( "shown: " + dockable.getTitleText() );
}
@Override
public void hidden( DockFrontend fronend, Dockable dockable ) {
System.out.println( "hidden: " + dockable.getTitleText() );
}
});
SplitDockStation station = new SplitDockStation();
frame.setDefaultCloseOperation( JFrame.DO_NOTHING_ON_CLOSE );
frame.setBounds( 20, 20, 400, 400 );
frame.add( station.getComponent() );
frontend.addRoot( station, "root" );
TextFactory factoryA = new TextFactory( "A" );
TextFactory factoryB = new TextFactory( "B" );
frontend.registerFactory( factoryA );
frontend.registerFactory( factoryB );
/* use new feature */
//*
frontend.registerBackupFactory( factoryA );
frontend.registerBackupFactory( factoryB );
// */
/* end use new feature */
if( !putXML( frontend ) )
putDefault( frontend, station );
frame.addWindowListener( new WindowAdapter(){
@Override
public void windowClosing( WindowEvent e ) {
frame.setVisible( false );
XElement element = new XElement( "root" );
frontend.writeXML( element );
try {
XIO.writeUTF( element, new FileOutputStream( "test.xml" ) );
}
catch( FileNotFoundException e1 ) {
e1.printStackTrace();
}
catch( IOException e1 ) {
e1.printStackTrace();
}
System.exit( 0 );
}
});
frame.setVisible( true );
}
private static boolean putXML( DockFrontend frontend ){
try{
XElement element = XIO.readUTF( new FileInputStream( "test.xml" ));
frontend.readXML( element );
return true;
}
catch( IOException ex ){
// Ooops
ex.printStackTrace();
return false;
}
}
private static void putDefault( DockFrontend frontend, SplitDockStation station ){
SplitDockGrid grid = new SplitDockGrid();
TextDockable a = new TextDockable( "A" );
TextDockable b = new TextDockable( "B" );
frontend.add( a, "a" );
frontend.add( b, "b" );
grid.addDockable( 0, 0, 1, 1, a );
grid.addDockable( 0, 1, 1, 1, b );
station.dropTree( grid.toTree() );
}
private static class TextDockable extends DefaultDockable{
private JTextArea area = new JTextArea();
public TextDockable( String title ){
super( title );
getContentPane().add( new JScrollPane( area ));
setFactoryID( "text_" + title );
}
public String getText(){
return area.getText();
}
public void setText( String text ){
area.setText( text );
}
}
private static class TextFactory implements DockFactory<TextDockable, String>{
private String title;
public TextFactory( String title ){
this.title = title;
}
public String getID() {
return "text_" + title;
}
public String getLayout( TextDockable element, Map<Dockable, Integer> children ) {
System.out.println( "getLayout: " + title + " > " + element.getText() );
return element.getText();
}
public TextDockable layout( String layout, Map<Integer, Dockable> children ) {
System.out.println( "layout: " + title + " > " + layout );
TextDockable dock = new TextDockable( title );
dock.setText( layout );
return dock;
}
public TextDockable layout( String layout ) {
System.out.println( "layout: " + title + " > " + layout );
TextDockable dock = new TextDockable( title );
dock.setText( layout );
return dock;
}
public String read( DataInputStream in ) throws IOException {
// never happens
System.out.println( "I should not be here" );
return in.readUTF();
}
public String read( XElement element ) {
System.out.println( "read: " + title + " > " + element.getString() );
return element.getString();
}
public void setLayout( TextDockable element, String layout, Map<Integer, Dockable> children ) {
System.out.println( "setLayout: " + element.getTitleText() + " > " + layout );
element.setText( layout );
}
public void setLayout( TextDockable element, String layout ) {
System.out.println( "setLayout: " + element.getTitleText() + " > " + layout );
element.setText( layout );
}
public void write( String layout, DataOutputStream out ) throws IOException {
// never happens
System.out.println( "I should not be here" );
out.writeUTF( layout );
}
public void write( String layout, XElement element ) {
System.out.println( "write: " + title + " > " + layout );
element.setString( layout );
}
}
}```