CControl writeXML and readXML don't persist closed/hidden state

Heya,

I’ve got a simple demo going with my factory calling out to singleCDockable.setCloseable(true) so that I can merrily close tabs. I’ve got menu items that allow me to reopen them, and everything is happy in that respect.

The trouble comes with trying to persist the closed state. It appears that writeXML doesn’t store any information about the tool being closed. Is there something I’ve missed? I’ve been digging around on the forums and haven’t found anything similar.

Calls to mainControl.readXML(file) and mainControl.writeXML(file) are working just fine for all of the other aspects of the dockable states.

thanks,

-nate

Make sure the “closeable” property is set before loading the layout. Because the framework will open any Dockable that is “not closeable and not visible”.

Thank you for the prompt response! :smiley:

I believe I’m doing things in the right order. Here is a reduced sample of my code:

	{
...
		@Override
		public SingleCDockable createBackup(String title)
		{
			EditorTool tool = new EditorTool(title);
			DefaultSingleCDockable dockable = new DefaultSingleCDockable(tool.getName(), tool.getName(), tool.getComponent());
			dockable.setCloseable(true);
			return dockable;
		}
	}
...
public JFrame createEditor()
	{
		JFrame editorFrame = new JFrame();
		CControl mainControl = new CControl(editorFrame);
		editorFrame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

		ToolComponentFactory factory = new ToolComponentFactory();
		mainControl.addSingleDockableFactory(factory, factory);
		editorFrame.setLayout(new GridLayout(1, 1));
		editorFrame.add(mainControl.getContentArea());

		CControlPerspective controlPerspectives = mainControl.getPerspectives();
		CPerspective perspective = controlPerspectives.createEmptyPerspective();

		CGridPerspective center = perspective.getContentArea().getCenter();
		center.gridAdd(0, 0, 79, 400, new SingleCDockablePerspective("MyTool"));
		center.gridAdd(80, 300, 319, 99, new SingleCDockablePerspective("MyOtherTool"));

		CStackPerspective stack = new CStackPerspective();
		stack.add(new SingleCDockablePerspective("MyStackedTool"));
		stack.add(new SingleCDockablePerspective("MyOtherStackedTool"));
		stack.setSelection(stack.getDockable(0));
		center.grid().addDockable(80, 0, 319, 300, stack);

		controlPerspectives.setPerspective("main", perspective);
		mainControl.load("main");
		mainControl.setTheme(ThemeMap.KEY_ECLIPSE_THEME);

		editorFrame.setBounds(10, 10, 400, 400);
		loadLayout();
		editorFrame.setVisible(true);
		return editorFrame;
	}
...
	public void loadLayout()
	{
		final File file = getLayoutXML();
		if (file.exists())
		{
			EventQueue.invokeLater(new Runnable()
			{

				@Override
				public void run()
				{
					try
					{
						mainControl.readXML(file);
					} catch (IOException e)
					{
						System.out.println("Barf");
					}
				}
			});

		}
	}

	public void saveUILayout()
	{
		final File file = getLayoutXML();

		try
		{
			mainControl.writeXML(file);
		} catch (IOException e)
		{
			System.out.println("Barf");
		}
	}

I’m doing multiple calls to save/load the layout outside of these methods, so all of the dockables should already be created and set as closeable, right? What tag should I be seeing in the output xml that designates a dockable as hidden?

Cheers,

-nate

About the xml file: there are some elements called “root”, if the identifier of a Dockable shows up as child of such a “root”, then it is visible (the identifier may also show up as placeholder, such identifiers can be ignored to answer the question of the visibility).

I just copied your file and let it run. After closing some Dockables, then closing the app and restarting the app, the closed Dockables did not appear.

So what am I missing? Is my test wrong, or does your application something I’m missing? For example does this EditorTool something special?

The application I did try out was:


import java.awt.EventQueue;
import java.awt.GridLayout;
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.SingleCDockable;
import bibliothek.gui.dock.common.SingleCDockableFactory;
import bibliothek.gui.dock.common.perspective.CControlPerspective;
import bibliothek.gui.dock.common.perspective.CGridPerspective;
import bibliothek.gui.dock.common.perspective.CPerspective;
import bibliothek.gui.dock.common.perspective.CStackPerspective;
import bibliothek.gui.dock.common.perspective.SingleCDockablePerspective;
import bibliothek.gui.dock.common.theme.ThemeMap;
import bibliothek.util.Filter;

public class VisibilityIssue {
	private CControl mainControl;

	private class ToolComponentFactory implements SingleCDockableFactory, Filter<String>
	{
		@Override
		public boolean includes(String item) {
			return true;
		}
	
	    @Override
	    public SingleCDockable createBackup(String id)
	    {
	        DefaultSingleCDockable dockable = new DefaultSingleCDockable(id, id);
	        dockable.setCloseable(true);
	        return dockable;
	    }
	}
	
	public static void main(String[] args) {
		new VisibilityIssue().createEditor();
	}
	
	public JFrame createEditor()
	{
		JFrame editorFrame = new JFrame();
		mainControl = new CControl(editorFrame);
		editorFrame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
		
		ToolComponentFactory factory = new ToolComponentFactory();
		mainControl.addSingleDockableFactory(factory, factory);
		editorFrame.setLayout(new GridLayout(1, 1));
		editorFrame.add(mainControl.getContentArea());
		
		CControlPerspective controlPerspectives = mainControl.getPerspectives();
		CPerspective perspective = controlPerspectives.createEmptyPerspective();
		
		CGridPerspective center = perspective.getContentArea().getCenter();
		center.gridAdd(0, 0, 79, 400, new SingleCDockablePerspective("MyTool"));
		center.gridAdd(80, 300, 319, 99, new SingleCDockablePerspective("MyOtherTool"));
		
		CStackPerspective stack = new CStackPerspective();
		stack.add(new SingleCDockablePerspective("MyStackedTool"));
		stack.add(new SingleCDockablePerspective("MyOtherStackedTool"));
		stack.setSelection(stack.getDockable(0));
		center.grid().addDockable(80, 0, 319, 300, stack);
		
		controlPerspectives.setPerspective("main", perspective);
		mainControl.load("main");
		mainControl.setTheme(ThemeMap.KEY_ECLIPSE_THEME);
		
		editorFrame.setBounds(10, 10, 400, 400);
		loadLayout();
		editorFrame.setVisible(true);
		
		editorFrame.setDefaultCloseOperation(JFrame.DO_NOTHING_ON_CLOSE);
		editorFrame.addWindowListener(new WindowAdapter() {
			@Override
			public void windowClosing(WindowEvent e) {
				saveUILayout();
				System.exit(0);
			}
		});
		return editorFrame;
	}
	
	public File getLayoutXML(){
		return new File( "layoutTest.xml");
	}
	
	public void loadLayout()
	{
		final File file = getLayoutXML();
		if (file.exists())
		{
			EventQueue.invokeLater(new Runnable()
			{
				
				@Override
				public void run()
				{
					try
					{
						mainControl.readXML(file);
					} catch (IOException e)
					{
						System.out.println("Barf");
					}
				}
			});
			
		}
	}
	
	public void saveUILayout()
	{
		final File file = getLayoutXML();
		
		try
		{
			mainControl.writeXML(file);
		} catch (IOException e)
		{
			System.out.println("Barf");
		}
	}
}```

Hmm. Now I’m really confused. Using your completed example works fine for me as well.

However, in my non-simplified version I’m still having issues. I’ve swapped out my EditorTool for a DefaultSingleCDockable(id, id) and the issue persists, so the gremlin is lurking somewhere else.

I’ll stop bugging you for now until I can figure out what the difference is. I’ll update when I’ve got a better idea what the real issue is.

Thanks Again,

-nate

I figured it out. Turns out I had some name mismatches when using tool IDs vs. tool titles in my code. My naming scheme was subtle enough to have it not be completely obvious where the disconnect was.

The solution ended up residing in my factory class. The following code made things start working:

		@Override
		public SingleCDockable createBackup(String toolID)
		{
			IEditorTool tool = tools.get(toolID);
			JComponent component = tool.getComponent();

			DefaultSingleCDockable dockable = new DefaultSingleCDockable(toolID, tool.getTitle(), component);
			dockable.setCloseable(true);
			return dockable;
		}```
I needed to be explicit about IDs vs. Titles, as I'd evidently transposed them when referring to them interchangeably as "name".

Previously I'd been using the tool's title as both arguments for the dockable, which didn't surface any issues except for the actual layout persistence: [EVIL] ```DefaultSingleCDockable dockable = new DefaultSingleCDockable(tool.getTitle(), tool.getTitle(), component);``` [/EVIL]
Once I straightened things out and got consistent usage of IDs, the layout persistence started respecting closed views. Things are happy now. Sorry for wasting your time! Total user error.

thanks,

-nate

Hehe, it’s always good when errors are fixed without my help :wink: