Problem with using perspectives in context of toolbars - bibliothek.gui.dock.ToolbarG

I am using toolbars with perspectives, but if I try to add new dockables using factories to the frame, the following execption occurs:

Exception in thread "main" java.lang.ClassCastException: bibliothek.gui.dock.ToolbarGroupDockStation cannot be cast to bibliothek.gui.dock.ToolbarDockStation
	at bibliothek.gui.dock.station.toolbar.ToolbarDockStationFactory.getLayout(Unknown Source)
	at bibliothek.gui.dock.layout.DockSituation.convert(DockSituation.java:335)
	at bibliothek.gui.dock.layout.DockSituation.convert(DockSituation.java:326)
	at bibliothek.gui.DockFrontend.getSetting(DockFrontend.java:1467)
	at bibliothek.gui.dock.common.intern.CDockFrontend.getSetting(CDockFrontend.java:136)
	at bibliothek.gui.dock.common.perspective.CControlPerspective.getPerspective(CControlPerspective.java:127)
	at com.XX.ui.main.MainFrame.addEditor(MainFrame.java:224)
	at com.XX.ui.main.MainFrame.<init>(MainFrame.java:145)
	at com.XX.ui.main.MainFrame.main(MainFrame.java:111)

The code at line 224 where the problem occurs:

this.perspective = this.control.getPerspectives().getPerspective(true);
		CWorkingPerspective working = (CWorkingPerspective)this.perspective.getStation("editors");
		EditorDockableLayout layout = new EditorDockableLayout(title, panel);
		working.gridAdd(0, 0, 100, 100, new MultipleCDockablePerspective(CUSTOM_MULTI_FACTORY_ID, layout));
		this.control.getPerspectives().setPerspective(this.perspective, true);
		this.perspective.storeLocations();

The line 224 is the first line .this.perspectives = this.control.getPerspectives().getPerspective(true).
If I remove this line, all is working but any layout change vanishs if I add a new dockable using perspectives.

Which version of the framework are you using? Because there was a bug like this in 1.1.1, but in the current preview 1.1.2p1e it should be fixed.

Ok, I have upgraded from 1.1.1 to 1.1.2f, now a new exception occurs at the same position:

Exception in thread "main" java.lang.IllegalArgumentException: unknown format: dock.ToolbarContainerStation
	at bibliothek.gui.dock.station.support.PlaceholderList.read(PlaceholderList.java:265)
	at bibliothek.gui.dock.station.support.PlaceholderList.read(PlaceholderList.java:246)
	at bibliothek.gui.dock.station.toolbar.ToolbarContainerDockPerspective.read(Unknown Source)
	at bibliothek.gui.dock.station.toolbar.ToolbarContainerDockStationFactory.layoutPerspective(Unknown Source)
	at bibliothek.gui.dock.station.toolbar.ToolbarContainerDockStationFactory.layoutPerspective(Unknown Source)
	at bibliothek.gui.dock.common.intern.station.CommonDockStationFactory.layoutPerspective(CommonDockStationFactory.java:268)
	at bibliothek.gui.dock.common.intern.station.CommonDockStationFactory.layoutPerspective(CommonDockStationFactory.java:65)
	at bibliothek.gui.dock.layout.PredefinedDockSituation$PreloadFactory.layoutPerspective(PredefinedDockSituation.java:754)
	at bibliothek.gui.dock.layout.PredefinedDockSituation$PreloadFactory.layoutPerspective(PredefinedDockSituation.java:743)
	at bibliothek.gui.dock.layout.PredefinedDockSituation$PreloadFactory.layoutPerspective(PredefinedDockSituation.java:565)
	at bibliothek.gui.dock.perspective.Perspective.convert(Perspective.java:259)
	at bibliothek.gui.dock.common.perspective.CControlPerspective.convert(CControlPerspective.java:648)
	at bibliothek.gui.dock.common.perspective.CControlPerspective.getPerspective(CControlPerspective.java:128)
	at com.myDBDesigner.ui.main.MainFrame.addEditor(MainFrame.java:224)
	at com.myDBDesigner.ui.main.MainFrame.<init>(MainFrame.java:145)
	at com.myDBDesigner.ui.main.MainFrame.main(MainFrame.java:111)

My init code is:

		// initialize attributes
		this.toolbarStores = new HashMap<String, ToolbarStore>(1);

		// adding menu bar
		this.menuBar = new UIMenuBar();
		this.setJMenuBar(this.menuBar);
		// set docking
		this.control = new CControl(this);
		this.control.setTheme(ThemeMap.KEY_ECLIPSE_THEME);
		this.area = new CToolbarContentArea(this.control, "center");
		this.control.addStationContainer(this.area);
		this.getContentPane().add(this.area, BorderLayout.CENTER);
		this.control.createWorkingArea("editors");
		// register factories
		control.addSingleDockableFactory(new RegexFilter("toolbox.*"), new ToolboxFactory("toolbox"));
		control.addSingleDockableFactory(new RegexFilter("toolbar.*"), new ToolbarItemFactory("toolbar"));
		control.addMultipleDockableFactory(CUSTOM_MULTI_FACTORY_ID, new EditorDockableFactory("editor"));
		this.perspective = this.control.getPerspectives().createEmptyPerspective();
		this.toolbars = new CToolbarContentPerspective(this.perspective, "center");
		CGridPerspective grid = this.toolbars.getCenter();
		CWorkingPerspective working = (CWorkingPerspective)this.perspective.getStation("editors");
		grid.gridAdd(20, 0, 80, 100, working);
		// adding status bar
		this.statusBar = new UIToolBar();
		this.getContentPane().add(this.statusBar, BorderLayout.SOUTH);
		this.control.getPerspectives().setPerspective(this.perspective, true);

I could reproduce the exception, seems like there was some old code running that needed an update. I’ve uploaded v1.1.2p1g. At least this exception was gone.

Please let me know, if your application works with this update :wink:

Thanks for your quick response, I have tested my application with the version 1.1.2g.
But a new exception occurs now, it`s the same line of code (line 224) in my code:

Exception in thread "main" java.lang.IllegalArgumentException: layout must not be null
	at bibliothek.gui.dock.common.perspective.MultipleCDockablePerspective.<init>(MultipleCDockablePerspective.java:73)
	at bibliothek.gui.dock.common.intern.CommonMultipleDockableFactory.layoutPerspective(CommonMultipleDockableFactory.java:156)
	at bibliothek.gui.dock.common.intern.CommonMultipleDockableFactory.layoutPerspective(CommonMultipleDockableFactory.java:57)
	at bibliothek.gui.dock.perspective.Perspective.convert(Perspective.java:259)
	at bibliothek.gui.dock.perspective.Perspective.convert(Perspective.java:248)
	at bibliothek.gui.dock.perspective.Perspective.convert(Perspective.java:248)
	at bibliothek.gui.dock.common.perspective.CControlPerspective.convert(CControlPerspective.java:648)
	at bibliothek.gui.dock.common.perspective.CControlPerspective.getPerspective(CControlPerspective.java:128)
	at com.myDBDesigner.ui.main.MainFrame.addEditor(MainFrame.java:224)
	at com.myDBDesigner.ui.main.MainFrame.<init>(MainFrame.java:146)
	at com.myDBDesigner.ui.main.MainFrame.main(MainFrame.java:111)

Important to node is, that the first MultipleCDockable is set correctly on the frame, the second (and following) produces the problem:
Part of MainFrame.init (line 145-148):

this.addEditor("Test1", new JPanel());
		this.addEditor("Test2", new JPanel());
		this.addEditor("Test3", new JPanel());
		this.addEditor("Test4", new JPanel());

Hmpf… I have not tested this yet. But just to make sure: your EditorDockableFactory does not return null in any of its method?

Well, in the write method, it returns null. So I have added something, I think is working. The result is, that it is now working, but the editor panels are collected in a group (a tab without a title, if I click on it, the including tabs are visible).
EditorDockable constructor: public EditorDockable(EditorDockableFactory factory, String title, JPanel panel, ImageIcon icon)
My EditorDockableFactory.write code:

		return layout;```
And the read method:
]```
EditorDockable dockable = new EditorDockable(this, arg0.getTitle(), arg0.getPanel(), arg0.getIcon());
		dockable.addFocusListener(MainFrame.focusListener);
		dockable.setCloseable(true);
		dockable.setRemoveOnClose(true);
		return dockable;

The following exception occurs too:

Exception in thread "AWT-EventQueue-0" java.lang.ArrayIndexOutOfBoundsException: 1
	at bibliothek.extension.gui.dock.theme.eclipse.stack.tab.Arch.calculate(Arch.java:127)
	at bibliothek.extension.gui.dock.theme.eclipse.stack.tab.Arch.<init>(Arch.java:61)
	at bibliothek.extension.gui.dock.theme.eclipse.stack.tab.ArchGradientPainter.arch(ArchGradientPainter.java:277)
	at bibliothek.extension.gui.dock.theme.eclipse.stack.tab.ArchGradientPainter.rightSideTop(ArchGradientPainter.java:681)
	at bibliothek.extension.gui.dock.theme.eclipse.stack.tab.ArchGradientPainter.rightSide(ArchGradientPainter.java:675)
	at bibliothek.extension.gui.dock.theme.eclipse.stack.tab.ArchGradientPainter.contains(ArchGradientPainter.java:396)
	at java.awt.Container.findComponentAtImpl(Unknown Source)
	at java.awt.Container.findComponentAtImpl(Unknown Source)
	at java.awt.Container.findComponentAtImpl(Unknown Source)
	at java.awt.Container.findComponentAtImpl(Unknown Source)
	at java.awt.Container.findComponentAtImpl(Unknown Source)
	at java.awt.Container.findComponentAtImpl(Unknown Source)
	at java.awt.Container.findComponentAtImpl(Unknown Source)
	at java.awt.Container.findComponentAtImpl(Unknown Source)
	at java.awt.Container.findComponentAtImpl(Unknown Source)
	at java.awt.Container.findComponentAtImpl(Unknown Source)
	at java.awt.Container.findComponentAtImpl(Unknown Source)
	at java.awt.Container.findComponentAtImpl(Unknown Source)
	at java.awt.Container.findComponentAtImpl(Unknown Source)
	at java.awt.Container.findComponentAtImpl(Unknown Source)
	at java.awt.Container.findComponentAtImpl(Unknown Source)
	at java.awt.Container.findComponentAtImpl(Unknown Source)
	at java.awt.Container.findComponentAtImpl(Unknown Source)
	at java.awt.Container.findComponentAtImpl(Unknown Source)
	at java.awt.Container.findComponentAt(Unknown Source)
	at sun.awt.windows.WGlobalCursorManager.findComponentAt(Native Method)
	at sun.awt.GlobalCursorManager._updateCursor(Unknown Source)
	at sun.awt.GlobalCursorManager.updateCursorImmediately(Unknown Source)
	at sun.awt.windows.WComponentPeer.updateCursorImmediately(Unknown Source)
	at java.awt.Component.updateCursorImmediately(Unknown Source)
	at java.awt.Component.hide(Unknown Source)
	at java.awt.Component.show(Unknown Source)
	at java.awt.Component.setVisible(Unknown Source)
	at javax.swing.JComponent.setVisible(Unknown Source)
	at bibliothek.gui.dock.station.stack.CombinedStackDockComponent.setSelectedDockable(CombinedStackDockComponent.java:429)
	at bibliothek.gui.dock.station.stack.CombinedStackDockComponent.setSelectedIndex(CombinedStackDockComponent.java:420)
	at bibliothek.gui.dock.StackDockStation.setFrontDockable(StackDockStation.java:701)
	at bibliothek.gui.DockController$FocusControllerObserver.dockableFocused(DockController.java:1442)
	at bibliothek.gui.dock.control.focus.AbstractFocusController.fireDockableFocused(AbstractFocusController.java:199)
	at bibliothek.gui.dock.control.DefaultFocusController.execute(DefaultFocusController.java:223)
	at bibliothek.gui.dock.control.DefaultFocusController$Request.run(DefaultFocusController.java:323)
	at bibliothek.gui.dock.control.DefaultFocusController$Request.enqueue(DefaultFocusController.java:276)
	at bibliothek.gui.dock.control.DefaultFocusController.grant(DefaultFocusController.java:240)
	at bibliothek.gui.dock.control.DefaultFocusController.execute(DefaultFocusController.java:210)
	at bibliothek.gui.dock.control.DefaultFocusController$Request.run(DefaultFocusController.java:323)
	at bibliothek.gui.dock.control.DefaultFocusController$Request.enqueue(DefaultFocusController.java:276)
	at bibliothek.gui.dock.control.DefaultFocusController.focus(DefaultFocusController.java:126)
	at bibliothek.gui.DockController.setFocusedDockable(DockController.java:1004)
	at bibliothek.gui.dock.common.intern.CDockController.setFocusedDockable(CDockController.java:70)
	at bibliothek.gui.dock.control.focus.DefaultMouseFocusObserver.check(DefaultMouseFocusObserver.java:270)
	at bibliothek.gui.dock.control.focus.DefaultMouseFocusObserver.check(DefaultMouseFocusObserver.java:174)
	at bibliothek.gui.dock.control.focus.DefaultMouseFocusObserver.check(DefaultMouseFocusObserver.java:136)
	at bibliothek.gui.dock.control.focus.DefaultMouseFocusObserver$GlobalMouseListener.mousePressed(DefaultMouseFocusObserver.java:330)
	at bibliothek.gui.dock.control.DefaultGlobalMouseDispatcher.dispatch(DefaultGlobalMouseDispatcher.java:111)
	at bibliothek.gui.dock.control.DefaultGlobalMouseDispatcher$3.eventDispatched(DefaultGlobalMouseDispatcher.java:232)
	at java.awt.Toolkit$SelectiveAWTEventListener.eventDispatched(Unknown Source)
	at java.awt.Toolkit$ToolkitEventMulticaster.eventDispatched(Unknown Source)
	at java.awt.Toolkit$ToolkitEventMulticaster.eventDispatched(Unknown Source)
	at java.awt.Toolkit$ToolkitEventMulticaster.eventDispatched(Unknown Source)
	at java.awt.Toolkit$ToolkitEventMulticaster.eventDispatched(Unknown Source)
	at java.awt.Toolkit$ToolkitEventMulticaster.eventDispatched(Unknown Source)
	at java.awt.Toolkit.notifyAWTEventListeners(Unknown Source)
	at java.awt.Component.dispatchEventImpl(Unknown Source)
	at java.awt.Container.dispatchEventImpl(Unknown Source)
	at java.awt.Component.dispatchEvent(Unknown Source)
	at java.awt.LightweightDispatcher.retargetMouseEvent(Unknown Source)
	at java.awt.LightweightDispatcher.processMouseEvent(Unknown Source)
	at java.awt.LightweightDispatcher.dispatchEvent(Unknown Source)
	at java.awt.Container.dispatchEventImpl(Unknown Source)
	at java.awt.Window.dispatchEventImpl(Unknown Source)
	at java.awt.Component.dispatchEvent(Unknown Source)
	at java.awt.EventQueue.dispatchEventImpl(Unknown Source)
	at java.awt.EventQueue.access$000(Unknown Source)
	at java.awt.EventQueue$3.run(Unknown Source)
	at java.awt.EventQueue$3.run(Unknown Source)
	at java.security.AccessController.doPrivileged(Native Method)
	at java.security.ProtectionDomain$1.doIntersectionPrivilege(Unknown Source)
	at java.security.ProtectionDomain$1.doIntersectionPrivilege(Unknown Source)
	at java.awt.EventQueue$4.run(Unknown Source)
	at java.awt.EventQueue$4.run(Unknown Source)
	at java.security.AccessController.doPrivileged(Native Method)
	at java.security.ProtectionDomain$1.doIntersectionPrivilege(Unknown Source)
	at java.awt.EventQueue.dispatchEvent(Unknown Source)
	at java.awt.EventDispatchThread.pumpOneEventForFilters(Unknown Source)
	at java.awt.EventDispatchThread.pumpEventsForFilter(Unknown Source)
	at java.awt.EventDispatchThread.pumpEventsForHierarchy(Unknown Source)
	at java.awt.EventDispatchThread.pumpEvents(Unknown Source)
	at java.awt.EventDispatchThread.pumpEvents(Unknown Source)
	at java.awt.EventDispatchThread.run(Unknown Source)```

Ok, the exception with the Arch is something else - probably the framework tries to paint a Component with size 0/0 or something like that…

The result is, that it is now working, but the editor panels are collected in a group (a tab without a title, if I click on it, the including tabs are visible)

Before I start and try to reproduce this issue, can you please show me how you set up these editor panels? How do they get their initial location?

[Edit: Just to clarify: you see tabs within tabs? But there is only one „top tab“?]

Here is my code to add an editor dockables (alias MultipleCDockable):

public void addEditor(String title, JPanel panel) {
		this.perspective = this.control.getPerspectives().getPerspective(true);
		CWorkingPerspective working = (CWorkingPerspective)this.perspective.getStation("editors");
		EditorDockableLayout layout = new EditorDockableLayout(title, panel);
		working.gridAdd(0, 0, 100, 100, new MultipleCDockablePerspective(CUSTOM_MULTI_FACTORY_ID, layout));
		this.control.getPerspectives().setPerspective(this.perspective, true);
		this.perspective.storeLocations();
	}

The location is only for testing, in real it would be x:20, y:0, w:80, h:100.
The other SingleCDockables will be located at x:0, y:0 with w:20 and h:100.
Interesting is, that the grouping starts if 2 or more dockables are visible. Is there any properites
to change this, I would assume the grouping only starts if there is no more space for the tabs (which is not the case).

Note, I have tried my application again without any code changes. Now I havent received an exception like the previous one. I dont know why. For your answer about the tabs. I see tabs in tabs. An more bright blue tab which includes the other tabs. But to access the other tabs, I have to close displayed one tab before.

I’ve uploaded a new version fixing the “Arch”-Bug. Also this new version includes a method called “CWorkingPerspective.unpack”, which will fix the issue with tabs in tabs. The method is called automatically, you do not have to modify your code.

Why “unpack”? The first two Dockables are stacked, and the stack itself is yet another Dockable. When you call the “getPerspective” method the grid no longer contains two Dockables but one stack containing two Dockables. And if you add the third one the framework stacks it together with the existing stack…

Now… about using the perspective API to add a single Dockable. If I understood correctly what you want to do - open a new editor Dockable during runtime - there is an easier solution using the method “show”:

EditorDockable editor = new ...
work.show( editor );```
This will open "editor" in the same stack as the last focused editor-Dockable. 

(P.S. The "show" method has an issue if the last focused Dockable was maximized, but that will be addressed in the next release. It's still better than using the perspective API.)

Thanks for you efforts and quick response. Sadly I have to report that the downloaded file under 1.1.2 Preview 1h is the same as 1.1.2 Preview 1g (I downloaded both times the same zip archive.) See: http://dock.javaforge.com/download.html (10.12.12 22:00). So I failed to test the fixed arch bug (the exception occurs like previous). Please note again, the exception only occurs sometimes, I haven`t been able to reproduce it correctly. But the „grouping“ of tabs is a real issue, I guess your unpack will solve the problem. As I am using your perspective :slight_smile: API in three parts and have already written a number of classes related the the perspectives, I would prefer to continue using the perspectives. I like the perspectives , and for the toolbar they are working good. My quesiton is, can I use the perspective for the toolbar and the SingleCDockables while using the common without perspectives for my editor dockables (MultipleCDockable)?

Oh %%&%*. I just should create that homepage automatically… click here please.

You can mix the perspective API and the “normal” API. In general the perspective API is good at setting up the initial layout, but modifying a running application is usually easier by not using perspectives.

Thank you very much, docking frames works now with the perspectives as expected. Now all the dockablee tabs are shown correctly.

Good. Sorry for all the bugs… but I just like writing features more than testing features :stuck_out_tongue: If you have any other issues with the framework, let me know.