CControl IllegalStateException in Method load(String name)

Hi,

I’m getting a IllegalStateException in method load(String name) from CControl when I try to load a layout which has been saved before. The layouts only contain DefaultSingleCDockables and each DefaultSingleCDockable only available one layout.

I’m using 1.1.0. Should I provide a demo for the error or could someone give me a hint what is wrong.
With 1.0.8 my Application did not throws any errors in this situation.

Thanks,
Martin

java.lang.IllegalStateException: The parent of ‘bibliothek.gui.dock.common.intern.DefaultCommonDockable@68f1e723’ is not null but ‘bibliothek.gui.dock.StackDockStation@2d2e3a2c’
at bibliothek.gui.dock.DockHierarchyLock.ensureUnlinked(DockHierarchyLock.java:299)
at bibliothek.gui.dock.DockHierarchyLock.access$400(DockHierarchyLock.java:45)
at bibliothek.gui.dock.DockHierarchyLock$Token.release(DockHierarchyLock.java:354)
at bibliothek.gui.dock.StackDockStation.remove(StackDockStation.java:1393)
at bibliothek.gui.dock.StackDockStation.drag(StackDockStation.java:1153)
at bibliothek.gui.DockUI.updateTheme(DockUI.java:417)
at bibliothek.gui.dock.StackDockStation.callDockUiUpdateTheme(StackDockStation.java:513)
at bibliothek.gui.dock.station.AbstractDockableStation.updateTheme(AbstractDockableStation.java:110)
at bibliothek.gui.dock.control.DockRegister.register(DockRegister.java:383)
at bibliothek.gui.dock.control.DockRegister$1.handleDockStation(DockRegister.java:187)
at bibliothek.gui.dock.util.DockUtilities.visitStation(DockUtilities.java:151)
at bibliothek.gui.dock.util.DockUtilities.visitDockable(DockUtilities.java:142)
at bibliothek.gui.dock.util.DockUtilities.visit(DockUtilities.java:111)
at bibliothek.gui.dock.control.DockRegister.add(DockRegister.java:180)
at bibliothek.gui.dock.control.DockRegister.access$400(DockRegister.java:46)
at bibliothek.gui.dock.control.DockRegister$StationListener.addDockable(DockRegister.java:606)
at bibliothek.gui.dock.control.DockRegister$StationListener.fire(DockRegister.java:542)
at bibliothek.gui.dock.control.DockRegister.setStalled(DockRegister.java:504)
at bibliothek.gui.dock.support.mode.ModeManager.runTransaction(ModeManager.java:489)
at bibliothek.gui.dock.facile.mode.LocationModeManager.runLayoutTransaction(LocationModeManager.java:473)
at bibliothek.gui.dock.common.intern.CDockFrontend.setSetting(CDockFrontend.java:161)
at bibliothek.gui.DockFrontend.load(DockFrontend.java:1413)
at bibliothek.gui.dock.common.CControl.load(CControl.java:2673)

It would be interesting to to know layout you are currently in, and the one you are trying to load. And also if you did any modifications to the behavior of the framework.

The exception tells that the framework tried to remove a DefaultCommonDockable from a StackDockStation but did not succeed. This is quite a strange bug, because it happens only if the dock-parent of the Dockable was not set to null, but that command is executed in any case.

Hi Beni,

thank you for our answer. While creating a demo for the problem I found the bug in my Application. The reason was a circle in the event handling of the Dockables. I added a FocusListener to the Dockables and at the end of the event handling I tried to modify the Dockables. In the case of loading a new layout this make no sense. After refactoring the event handling there is no exception anymore.

Thanks,
Martin

Good to hear your found the bug. Actually this “DockHierarchyLock” should prevent exactly such cases, but it should have thrown the exception when your code is executed, not afterwards. If you still have the old code that caused the exception, then I would be interested to see it. Perhaps in the future the exception could happen earlier.

[Edit: it does not have to be a full demo, just some snippets are ok too]

I tried to isolate the problem but I was not successful. I attached the example but in the example the exception could not reproduced. I think the exception is forced thru bad design in my application.

In the Demo you can add Figures and and Desktops, set a tiled layout 2x2 for a desktop, and switch between the desktops.

In the real Application the exception occurs depending if isAdjusting used or not in the FocusListener, but in the real appliaction perhaps there a some additional aspects regarding the event handling which I could not ingrate easily into the demo.

In the real Application I also get the following information before the exception which I did not recognizes before, the information leads me to the problem.

Warning: layout should not be modified by subclasses of bibliothek.gui.dock.event.DockStationListener
This is only an information, not an exception. If your code is actually safe you can:

  • disabled the warning by calling DockUtilities.disableCheckLayoutLocked() )
    mark your code as safe by setting the annotation ‘LayoutLocked’
import java.awt.BorderLayout;
import java.awt.Container;
import java.awt.Dimension;
import java.awt.Rectangle;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.lang.reflect.InvocationTargetException;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.Vector;

import javax.swing.DefaultComboBoxModel;
import javax.swing.JButton;
import javax.swing.JComboBox;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JToolBar;
import javax.swing.SwingUtilities;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;

import bibliothek.extension.gui.dock.theme.flat.FlatDockableDisplayer;
import bibliothek.gui.dock.SplitDockStation;
import bibliothek.gui.dock.common.CContentArea;
import bibliothek.gui.dock.common.CControl;
import bibliothek.gui.dock.common.CGrid;
import bibliothek.gui.dock.common.CLocation;
import bibliothek.gui.dock.common.DefaultSingleCDockable;
import bibliothek.gui.dock.common.SingleCDockable;
import bibliothek.gui.dock.common.event.CDockableLocationEvent;
import bibliothek.gui.dock.common.event.CDockableLocationListener;
import bibliothek.gui.dock.common.intern.CDockable;
import bibliothek.gui.dock.common.mode.ExtendedMode;
import bibliothek.gui.dock.common.theme.ThemeMap;
import bibliothek.gui.dock.layout.DockableProperty;
import bibliothek.gui.dock.station.split.DefaultSplitLayoutManager;
import bibliothek.gui.dock.station.split.Leaf;
import bibliothek.gui.dock.station.split.PutInfo;
import bibliothek.gui.dock.station.split.SplitDockPathProperty;
import bibliothek.gui.dock.station.split.SplitDockProperty;
import bibliothek.gui.dock.station.split.SplitLayoutManager;
import bibliothek.gui.dock.util.PropertyKey;

public class Example {
	
	
	private  final static String EMPTY_DESKTOP = "EMPTY"; 	
		
	private CControl control;
	private int counterFigure = 0; 
	private int counterDesktop = -1;
	private Integer currentDesktop = -1;
	private Vector<Integer> desktopList = new Vector<Integer>();
	private JComboBox comboBox; 
	private boolean isAdjusting = false;
	
	private ArrayList<SingleCDockable> dockableList = new ArrayList<SingleCDockable>();


	public Example(JFrame frame){
		
		initToolbar(frame);
		initDocking(frame);		
					
		initDesktop();

	}
	
	private void initDocking(JFrame frame){
		  control = new CControl(frame);	
			PropertyKey<SplitLayoutManager> key = SplitDockStation.LAYOUT_MANAGER;
			DefaultSplitLayoutManager defaultSplitLayoutManager = new DefaultSplitLayoutManager() {
				@Override
				public void calculateDivider(SplitDockStation station,
						PutInfo putInfo, Leaf origin) {

					super.calculateDivider(station, putInfo, origin);
					putInfo.setDivider(0.5);
				}
			};

			control.putProperty(key, defaultSplitLayoutManager);

			ThemeMap themes = control.getThemes();
			themes.select(ThemeMap.KEY_FLAT_THEME);				  
		  
		  frame.add(control.getContentArea(), BorderLayout.CENTER);
		  
		  control.save(EMPTY_DESKTOP);
	}
	
	private void initToolbar(JFrame frame){
		
		JToolBar toolbar = new JToolBar();		
		JButton addFigureButton = new JButton("Add Figure");
		addFigureButton.addActionListener(new ActionListener(){
			@Override
			public void actionPerformed(ActionEvent arg0) {
				addFigure();				
			}			
		});
				
		toolbar.add(addFigureButton);
				
		JButton addDesktopButton = new JButton("Add Desktop");			
		addDesktopButton.addActionListener(new ActionListener(){
			@Override
			public void actionPerformed(ActionEvent arg0) {
				addDesktop();				
			}			
		});				
		toolbar.add(addDesktopButton);
		
		
		JButton tiledLayoutButton = new JButton("#");			
		tiledLayoutButton.addActionListener(new ActionListener(){
			@Override
			public void actionPerformed(ActionEvent arg0) {
				setTiledLayout();				
			}			
		});				
		toolbar.add(tiledLayoutButton);
		
		
		
		comboBox = new JComboBox(desktopList);
		comboBox.addActionListener(new ActionListener(){
			@Override
			public void actionPerformed(ActionEvent arg0) {				
				int index = comboBox.getSelectedIndex();
				if (index > -1){
					switchToDesktop(index);
				}				
			}			
		});				
		
		toolbar.add(comboBox);
		
		
				
		frame.getContentPane().add(toolbar,BorderLayout.NORTH);
	}
	
	public void addFigure() {				
		SingleCDockable dockable = create("Figure "+counterFigure++);       
        control.addDockable(dockable);   
        dockable.setVisible(true);            
                           
	}	
	
	private void switchToDesktop(Integer desktopID){
		 saveCurrentDesktop();				 
		 load(desktopID.toString());		 
		 currentDesktop = desktopID;
	}
	
	private void load(String desktopID){
		isAdjusting = true;
		 control.load(desktopID);
		 isAdjusting = false;
	}

	
	private void addDesktop(){		
		saveCurrentDesktop();
		initDesktop();				
	}	
	
	
	private void initDesktop(){		
		load(EMPTY_DESKTOP);		
		counterDesktop++;
		currentDesktop = counterDesktop;		
		desktopList.add(counterDesktop);		
		comboBox.setModel(new DefaultComboBoxModel(desktopList));
	}
	
	private void saveCurrentDesktop(){
		control.save(currentDesktop.toString());
	}

    
    public static void main(String[] args) {
    	
		try {
			SwingUtilities.invokeAndWait(new Runnable() {
				@Override
				public void run() {

					 try {
						UIManager.setLookAndFeel(UIManager
						 .getSystemLookAndFeelClassName());
					} catch (ClassNotFoundException e) {
						e.printStackTrace();
					} catch (InstantiationException e) {
						e.printStackTrace();
					} catch (IllegalAccessException e) {
						e.printStackTrace();
					} catch (UnsupportedLookAndFeelException e) {
						e.printStackTrace();
					}
					 
				      JFrame frame = new JFrame();
				        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
				        frame.setLayout(new BorderLayout());  
				                
				        frame.add(new JLabel("WEST"), BorderLayout.WEST);	  
				        frame.add(new JLabel("EAST"), BorderLayout.EAST);
				        frame.add(new JLabel("SOUTH"), BorderLayout.SOUTH);
				       				      
				        Example example = new Example(frame);
				        frame.setBounds(20, 20, 400, 400);
				        frame.setVisible(true);        
				        				        			        			
				}
			});
		} catch (InterruptedException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (InvocationTargetException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}		
  
    }
   		  
	private void setTiledLayout() {

		Rectangle[] h = new Rectangle[2];
		h[0] = new Rectangle(0, 0, 100, 50);
		h[1] = new Rectangle(0, 50, 100, 50);

		Rectangle[] q = new Rectangle[4];
		q[0] = new Rectangle(0, 0, 50, 50);
		q[1] = new Rectangle(50, 0, 50, 50);
		q[2] = new Rectangle(0, 50, 50, 50);
		q[3] = new Rectangle(50, 50, 50, 50);

		ArrayList<SingleCDockable> currrentDockableList = new ArrayList<SingleCDockable>();
		for (Iterator<SingleCDockable> iterator = dockableList.iterator(); iterator
				.hasNext();) {
			SingleCDockable dockable = iterator.next();

			if (dockable.getBaseLocation() == null) {
				continue;
			}
			dockable.setExtendedMode(ExtendedMode.NORMALIZED);
			currrentDockableList.add(dockable);
		}

		CGrid grid = new CGrid(control);

		if (currrentDockableList.size() == 2) {
			for (int i = 0; i < currrentDockableList.size(); i++) {
				grid.add(h**.x, h**.y, h**.width, h**.height,
						currrentDockableList.get(i));
			}
		} else {
			for (int i = 0; i < currrentDockableList.size(); i++) {
				int qIdx = i % 4;
				grid.add(q[qIdx].x, q[qIdx].y, q[qIdx].width, q[qIdx].height,
						currrentDockableList.get(i));
			}
		}
		control.getContentArea().deploy(grid);
	}


    private SingleCDockable create(final String title) {
    	 
    	JLabel label = new JLabel();
    	label.setOpaque(true);    	
 
        final DefaultSingleCDockable cDockable = new DefaultSingleCDockable(
                title, title, label);
        
        dockableList.add(cDockable);
        
        cDockable.addFocusListener(new CFocusAdapter() {
			@Override
			public void focusGained(CDockable cDockable) {				
//				if (isAdjusting){
//					return;
//				}				
				if (cDockable.isVisible()) {
				((DefaultSingleCDockable)cDockable).toFront();
				}
			}
		});            
        
        cDockable.addCDockableLocationListener(new CDockableLocationListener() {	 
			@Override
			public void changed(CDockableLocationEvent event) {
				updateFigureLocation((DefaultSingleCDockable) event.getDockable());	        		
			}
		});		
        
        
        return cDockable;
    }
    
	private void updateFigureLocation( DefaultSingleCDockable dockable){

		if (!dockable.isVisible()){
			return;
		}				

		//Figure figure = getFigure(dockable);
		
		Rectangle printPostion = getLocation(dockable);
		
		//figure.setPrintLocation(printPostion);

		CLocation location = dockable.getBaseLocation();		

		if (dockable.getExtendedMode() == ExtendedMode.NORMALIZED) {
			// fall back to Core and assume that green is a child of a
			// SplitDockStation (not necessarily true,
			// it could also be a StackDockStation. If that happens
			// "property.getSuccessor" is not null, and the
			// code below may not work properly anymore).
			DockableProperty property = location.findProperty();

			if (property instanceof SplitDockProperty) {
				SplitDockProperty rectangle = (SplitDockProperty) property;

//				figure.setLocation(new Rectangle((int) (100 * rectangle
//						.getX()), (int) (100 * rectangle.getY()),
//						(int) (100 * rectangle.getWidth()),
//						(int) (100 * rectangle.getHeight())));
//				figure.setInternal(true);

			} else if (property instanceof SplitDockPathProperty) {

				SplitDockProperty splitDockProperty = ((SplitDockPathProperty) property)
						.toLocation();

//				figure.setLocation(new Rectangle(
//						(int) (100 * splitDockProperty.getX()),
//						(int) (100 * splitDockProperty.getY()),
//						(int) (100 * splitDockProperty.getWidth()),
//						(int) (100 * splitDockProperty.getHeight())));
//				figure.setInternal(true);

			} else {
//				System.out.println("Could not save location for "
//						+ figure.getName() + " Property: " + property);


			}
		} else {
			// System.out.println("Could not save location for "
			// + figure.getName() + " NOT NORMALIZED");
		}			
	}
	
	private Rectangle getLocation(DefaultSingleCDockable dockable ){

		Container contentPane = dockable.getContentPane();
		CContentArea target = control.getContentArea();
		Dimension targetSize = target.getSize();

		Container source = contentPane;
		while (true) {
			if (source.getParent() instanceof FlatDockableDisplayer) {
				break;
			}
			if (source.getParent() instanceof CContentArea) {
				break;
			}
			source = source.getParent();
		}

		Dimension size = source.getSize();
		Rectangle position = new Rectangle(0, 0, size.width, size.height);

		Rectangle pos = SwingUtilities.convertRectangle(source, position,
				target);

		Rectangle printPostion = new Rectangle(
				(int) ((100.0 * pos.x) / targetSize.width),
				(int) ((100.0 * pos.y) / targetSize.height),
				(int) ((100.0 * pos.width) / targetSize.width),
				(int) ((100.0 * pos.height) / targetSize.height));

		return printPostion;

	}	
    
        
    
  
}```