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