Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Externalizing configuration fail #28

Open
xpenatan opened this issue Jul 7, 2014 · 6 comments
Open

Externalizing configuration fail #28

xpenatan opened this issue Jul 7, 2014 · 6 comments
Assignees

Comments

@xpenatan
Copy link

xpenatan commented Jul 7, 2014

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

@Benoker Benoker self-assigned this Jul 8, 2014
@Benoker
Copy link
Owner

Benoker commented Jul 8, 2014

I'll have a look at the issue next weekend.

@Benoker
Copy link
Owner

Benoker commented Jul 12, 2014

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 );
    }
}

@xpenatan
Copy link
Author

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;
        }
    }
}

@Benoker
Copy link
Owner

Benoker commented Jul 13, 2014

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)

@xpenatan
Copy link
Author

ok thanks ! =)

There is another issue with 10e Glass Extension that has memory leak when resizing dockables but it seems the creator disappeared right ?

@Benoker
Copy link
Owner

Benoker commented Jul 15, 2014

Yeah, I don't even have access to all of the source code of the glass extension. :-/

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants