Open xpenatan opened 10 years ago
I'll have a look at the issue next weekend.
I could not reproduce your issue. The little application below did save and load the layout even after I restarted it several times.
Maybe you could provide me with a little sample application that shows how to create the error.
package test;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.io.File;
import java.io.IOException;
import javax.swing.JFrame;
import bibliothek.gui.dock.common.CControl;
import bibliothek.gui.dock.common.DefaultSingleCDockable;
import bibliothek.gui.dock.common.behavior.ExternalizingCGridAreaConfiguration;
public class ExternalSaveLoadTest {
public static void main( String[] args ) {
JFrame frame = new JFrame();
frame.setDefaultCloseOperation( JFrame.DO_NOTHING_ON_CLOSE );
final CControl control = new CControl( frame );
ExternalizingCGridAreaConfiguration.installOn( control );
frame.add( control.getContentArea() );
frame.setBounds( 50, 50, 800, 800 );
DefaultSingleCDockable dock1 = new DefaultSingleCDockable( "a", "Aaaa" );
DefaultSingleCDockable dock2 = new DefaultSingleCDockable( "b", "Bbbb" );
DefaultSingleCDockable dock3 = new DefaultSingleCDockable( "c", "Cccc" );
control.addDockable( dock1 );
control.addDockable( dock2 );
control.addDockable( dock3 );
dock1.setVisible( true );
dock2.setVisible( true );
dock3.setVisible( true );
try{
control.readXML( new File( "external.xml" ) );
}
catch(IOException e){
e.printStackTrace();
}
frame.addWindowListener( new WindowAdapter() {
public void windowClosing( WindowEvent e ) {
try{
control.writeXML( new File("external.xml") );
}
catch(IOException ex){
ex.printStackTrace();
}
System.exit( 0 );
}
} );
frame.setVisible( true );
}
}
Hi, here is the edited code. if you comment "ExternalizingCGridAreaConfiguration.installOn( control );" it will work after loading/saving multiple times but if you uncomment it stop working after some loading/saving ( fileContent get lost).
package tutorial.common.basics;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.File;
import java.io.IOException;
import javax.swing.JFrame;
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.behavior.ExternalizingCGridAreaConfiguration;
import bibliothek.gui.dock.common.theme.ThemeMap;
import bibliothek.util.xml.XElement;
public class ExternalSaveLoadTest {
public static void main( String[] args ) {
JFrame frame = new JFrame();
frame.setDefaultCloseOperation( JFrame.DO_NOTHING_ON_CLOSE );
final CControl control = new CControl( frame );
control.setTheme(ThemeMap.KEY_ECLIPSE_THEME);
ExternalizingCGridAreaConfiguration.installOn( control );
EditorFactory factory = new EditorFactory();
control.addMultipleDockableFactory( "file-editor", factory );
frame.add( control.getContentArea() );
frame.setBounds( 50, 50, 800, 800 );
File file = new File( "external.xml" ) ;
if(file.exists())
{
try{
control.readXML(file);
}
catch(IOException e){
e.printStackTrace();
}
}
else
{
DefaultDockable dock1 = new DefaultDockable( new LayoutFileData("AAA"), factory);
DefaultDockable dock2 = new DefaultDockable( new LayoutFileData("BBB"), factory);
DefaultDockable dock3 = new DefaultDockable( new LayoutFileData("CCC"), factory);
control.addDockable( dock1 );
control.addDockable( dock2 );
control.addDockable( dock3 );
dock1.setVisible( true );
dock2.setVisible( true );
dock3.setVisible( true );
}
frame.addWindowListener( new WindowAdapter() {
public void windowClosing( WindowEvent e ) {
try{
control.writeXML( new File("external.xml") );
}
catch(IOException ex){
ex.printStackTrace();
}
System.exit( 0 );
}
} );
frame.setVisible( true );
}
public static class LayoutFileData implements MultipleCDockableLayout{
private String fileContent;
public LayoutFileData(){
}
public LayoutFileData(String name){
this.fileContent = name;
}
public String getFileContent(){
return fileContent;
}
@Override
public boolean equals( Object obj ){
if( this == obj ){
return true;
}
if( obj == null ){
return false;
}
if( getClass() != obj.getClass() ){
return false;
}
LayoutFileData other = (LayoutFileData) obj;
return equals( fileContent, other.fileContent );
}
private boolean equals( Object a, Object b ){
if( a == null ){
return b == null;
}
else{
return a.equals( b );
}
}
public void readStream( DataInputStream in ) throws IOException{
fileContent = in.readUTF();
}
public void readXML( XElement element )
{
fileContent = element.getElement( "content" ).getString();
}
public void writeStream( DataOutputStream out ) throws IOException
{
out.writeUTF( fileContent );
}
public void writeXML( XElement element ){
element.addElement( "content" ).setString( fileContent );
}
}
/* This factory builds a link between EditorDockable and EditorLayout */
public static class EditorFactory implements MultipleCDockableFactory<DefaultDockable, LayoutFileData>{
/* An empty layout is required to read a layout from an XML file or from a byte stream */
public LayoutFileData create(){
return new LayoutFileData();
}
/* An optional method allowing to reuse 'dockable' when loading a new layout */
public boolean match( DefaultDockable dockable, LayoutFileData layout ){
return dockable.getDataLayout().equals( layout );
}
/* Called when applying a stored layout */
public DefaultDockable read( LayoutFileData layout )
{
return new DefaultDockable(layout, this);
}
/* Called when storing the current layout */
public LayoutFileData write( DefaultDockable dockable ){
return dockable.getDataLayout();
}
}
public static class DefaultDockable extends DefaultMultipleCDockable
{
LayoutFileData layout;
public DefaultDockable(LayoutFileData dataLayout, EditorFactory factory)
{
super(factory);
this.layout = dataLayout;
setTitleText(layout.fileContent);
}
public LayoutFileData getDataLayout()
{
return layout;
}
}
}
Thanks, I could reproduce the error now. It only happens when using MultipleCDockables.
To understand the bug: there is a feature where the framework tries to store the layout of missing dockables. When reading a layout MultipleCDockables are missing (because they are not yet created), so their layout is stored until the dockables are created.
In this example MultipleCDockables are nested (your "DefaultDockable" is inside an ExternalCGridArea). When the ExternalCGridArea is created the framework notices that the layout of this dockable is already stored - and applies the stored layout to the grid-area. Unfortunately the newly created grid-area already has loaded its children at that time, and it will load its children a second time. And this double loading leads to some confusion in the internal data structure of the framework.
I'll upload a fix to stop the unwanted double loading of the layout.
(Edit: the fix is pushed in version 1.1.2p12)
ok thanks ! =)
There is another issue with 10e Glass Extension that has memory leak when resizing dockables but it seems the creator disappeared right ?
Yeah, I don't even have access to all of the source code of the glass extension. :-/
Hi, I tried the "ExternalizingCGridAreaConfiguration.installOn( control );" and it works great except for saving/loading.
When I close the app and open it again it works for first time but after the second save it doesn't save correctly. After loading I see two blank dockables together without its content and title.
If its a bug or you have a saving/loading example using Externalizing class please tell.
Thanks