Perspective center store/load

Hello,
If I store and load the perspectives, are the DefaultMultipleCDockable that are added to perspective.getContentArea().getCenter() not stored in the perspective?

Because if I move the dockable that is added to the center, store the layout and load it again, the dockables are back to the initial minimized position.

My code follows the example in Guide->Common->Perspective (History).
Except that I add MultipleCDockable to the center instead SingleCDockable.

CGridPerspective center = perspective.getContentArea().getCenter();
// ...
center.gridAdd(x, y, w, h, perspective);

If you copied the example directly, you might have more than one “MultipleCDockablePerspective” with the same identifier - and in such a case the final location is more or less randomly chosen.

Could you please post the code you execute in order to move the dockables around?

No I only have one CWorkingPerspective.

If you mean the perspective, I use that code:

	/**
	 * Sets the default perspective.
	 * 
	 * @param perspectives
	 *            the {@link CControlPerspective}.
	 * 
	 * @param perspective
	 *            the {@link CPerspective}.
	 * 
	 * @param singleDockablePerspectives
	 *            the {@link Map} of the {@link DockablePerspective} for the
	 *            windows outside of the work area.
	 * 
	 * @param workDockablePerspectives
	 *            the {@link Map} of the {@link DockablePerspective} for the
	 *            windows in the work area.
	 * 
	 * @param workAreaId
	 *            the identifier of the work area.
	 */
	@Override
	public void setupPerspective(CControlPerspective perspectives,
			CPerspective perspective,
			Map<String, DockablePerspective> singleDockablePerspectives,
			Map<String, DockablePerspective> workDockablePerspectives,
			String workAreaId) {
		setupMinimizePerspective(singleDockablePerspectives, perspective);
		setupMinimizePerspective(workDockablePerspectives, perspective);
		perspective.storeLocations();
		CGridPerspective center = perspective.getContentArea().getCenter();
		CWorkingPerspective work = (CWorkingPerspective) perspective
				.getStation(workAreaId);
		setupGridPerspective(center, singleDockablePerspectives);
		setupGridPerspective(work, workDockablePerspectives);
		perspective.storeLocations();
		setupMinimizePerspective(singleDockablePerspectives, perspective);
		perspective.shrink();
		perspectives.setPerspective(perspective, true);
	}

	private void setupGridPerspective(CGridPerspective grid,
			Map<String, DockablePerspective> perspectives) {
		for (DockablePerspective perspective : perspectives.values()) {
			DockWindow window = perspective.window;
			PerspectivePosition position = window.getPosition();
			int x = getPerspectiveX(position);
			int y = getPerspectiveY(position);
			int w = getPerspectiveW(position);
			int h = getPerspectiveH(position);
			grid.gridAdd(x, y, w, h, perspective.perspective);
		}
	}

	private void setupMinimizePerspective(
			Map<String, DockablePerspective> dockablePerspectives,
			CPerspective perspective) {
		for (DockablePerspective dockablePerspective : dockablePerspectives
				.values()) {
			DockWindow window = dockablePerspective.window;
			PerspectivePosition position = window.getPosition();
			CMinimizePerspective min = getMinimizePerspective(position,
					perspective);
			min.add(dockablePerspective.perspective);
		}
	}

	private CMinimizePerspective getMinimizePerspective(
			PerspectivePosition position, CPerspective perspective) {
		switch (position) {
		case CENTER:
			return perspective.getContentArea().getSouth();
		case EAST:
			return perspective.getContentArea().getEast();
		case NORTH:
			return perspective.getContentArea().getNorth();
		case SOUTH:
			return perspective.getContentArea().getSouth();
		case WEST:
			return perspective.getContentArea().getWest();
		}
		throw new IllegalArgumentException();
	}

	private int getPerspectiveX(PerspectivePosition position) {
		switch (position) {
		case CENTER:
			return 0;
		case EAST:
			return 150;
		case NORTH:
			return 0;
		case SOUTH:
			return 0;
		case WEST:
			return 0;
		}
		throw new IllegalArgumentException();
	}


Thanks, I can reproduce the issue now. Will write back once a solution is ready.

I think I know what is going on. You are calling “setupMinimizePerspective” 3 times, two times with “singleDockablePerspectives” as argument.

While the MultipleCDockables are not in that map, the CWorkingArea itself is a SingleCDockable - and if you just collect the SingleCDockables without checking their type, it will land in that list.

Modifying the map before calling “setupMinimizePerspective” did improve my own test application a lot. Obviously you will have to use another identifier than “single work”… you could also check if the a SingleCDockablePerspective is an instance of “CWorkingPerspective”, in which case you just ignore it.


	public void setupPerspective(CControlPerspective perspectives,
			CPerspective perspective,
			Map<String, DockablePerspective> singleDockablePerspectives,
			Map<String, DockablePerspective> workDockablePerspectives,
			String workAreaId) {
		setupMinimizePerspective(singleDockablePerspectives, perspective);
		setupMinimizePerspective(workDockablePerspectives, perspective);
		perspective.storeLocations();
	
		CGridPerspective center = perspective.getContentArea().getCenter();
		CWorkingPerspective work = (CWorkingPerspective) perspective
				.getStation(workAreaId);
		setupGridPerspective(center, singleDockablePerspectives);
		setupGridPerspective(work, workDockablePerspectives);
		perspective.storeLocations();
		
		System.out.println( singleDockablePerspectives.remove( "single work" ).perspective );
		setupMinimizePerspective(singleDockablePerspectives, perspective);
		perspective.shrink();
		perspectives.setPerspective(perspective, true);
	}

P.S. in my application I needed to call “grid.gridClear()” in “setupGridPerspective”, you may need to add that line if you have a strange exception.

I think there is a little misunderstanding.
I’m using only MultipleCDockable.
Below is the output of the two maps right before I apply the perspective.
I have mis-used your naming. „single“ means for me a MultipleCDockable outside the work area. „work“ means for me a MultipleCDockable inside the work area. Because I don’t know how many docks my application will have.

Also I don’t collect, the user is adding the dockables. See the three methods.
So I do not have CWorkingArea in the maps.

singleDockablePerspectives

{single_b=DockablePerspective[com.anrisoftware.fdsanalysis.windows.docks.dockingframes.singledockable.DefaultSingleDockWindow@5f7e228c,bibliothek.gui.dock.common.perspective.MultipleCDockablePerspective@520e464e], single_a=DockablePerspective[com.anrisoftware.fdsanalysis.windows.docks.dockingframes.singledockable.DefaultSingleDockWindow@2b5cf9de,bibliothek.gui.dock.common.perspective.MultipleCDockablePerspective@6518740f]}

workDockablePerspectives

{work_1=DockablePerspective[com.anrisoftware.fdsanalysis.windows.docks.dockingframes.core.DefaultWorkDockWindow@3826ea10,bibliothek.gui.dock.common.perspective.MultipleCDockablePerspective@2d0dd3d], work_0=DockablePerspective[com.anrisoftware.fdsanalysis.windows.docks.dockingframes.core.DefaultWorkDockWindow@3a1cea92,bibliothek.gui.dock.common.perspective.MultipleCDockablePerspective@406c350c]}

	@Override
	public void addSingleDock(SingleDockWindow window) {
		singleDockablePerspectives.put(window.getId(), new DockablePerspective(
				window, new MultipleCDockablePerspective(
						SingleDockableFactory.ID, window.getId(),
						singleDockableLayoutFactory.createFor(window))));
	}

	@Override
	public void addWorkDock(WorkDockWindow window) {
		workDockablePerspectives.put(window.getId(), new DockablePerspective(
				window, new MultipleCDockablePerspective(
						WorkDockableFactory.ID, window.getId(),
						workDockableLayoutFactory.createFor(window))));
	}

	@Override
	public void addToolDock(ToolDockWindow window) {
		singleDockablePerspectives.put(window.getId(), new DockablePerspective(
				window, new SingleCDockablePerspective(window.getId())));
	}

Oh, and there I was hoping I found an easy solution…

Well, the example and the test application I wrote show me, that the framework in general appears to work correctly. Hence this is probably more an issue of your setup.

So I have to ask you to post a way to reliably reproduce the issue (in this case: a compiling, working test-application).

Ok will do.
I want to create an abstraction for the DoggyFrames for my applications anyway. Because the Eclipse kind of docking windows are quite common.

Hello,
I’ve created a project on Github. You can clone it and test the issue. It’s a little bit project, but you need only to look at one module: prefdialog-misc-swing
In the package com.anrisoftware.prefdialog.miscswing.docks

The class that setups the perspective is com.anrisoftware.prefdialog.miscswing.docks.perspectives.dockingframes.DefaultPerspectiveTask.

Repository: git://github.com/devent/prefdialog.git
Branch: docking-frames-workspace

git clone git://github.com/devent/prefdialog.git
git checkout -b docking-frames-workspace
git pull origin docking-frames-workspace

You can try and run DocksTest#“manually store and load perspective”()
But it’s written in Groovy.

What I have discovered is that if I remove the minimize perspective at the last step and not use the center CGridPerspective then the perspective is correctly saved and loaded (// setupMinimizePerspective(view …):

		setupMinimizePerspective(viewDockablePerspectives, perspective);
		setupMinimizePerspective(editorDockablePerspectives, perspective);
		perspective.storeLocations();
		// CGridPerspective center = perspective.getContentArea().getCenter();
		CWorkingPerspective work = (CWorkingPerspective) perspective
				.getStation(workAreaId);
		setupGridPerspective(work, viewDockablePerspectives);
		setupGridPerspective(work, editorDockablePerspectives);
		perspective.storeLocations();
		// setupMinimizePerspective(viewDockablePerspectives, perspective);
		perspective.shrink();
		perspectives.setPerspective(perspective, true);

But i just followed the tutorial code, except I have only MultipleCDockable, with two
MultipleCDockableLayout with different IDs. One I put in the work CWorkingPerspective and the other I put in the centre CGridPerspective.

        /* We start by assigned the minimized location of all dockables. */
        setUpMinimized( perspective, dockables );
        /* Now we assign the normalized location of all dockables. */
        setUpNormalized( perspective, dockables );
        /* It is also possible to access and modify the location history directly. */
        modifyHistoryDirectly( perspective, dockables );
        /* At the end we set up the layout that the user will see when the application starts. */
        setUpFinalLayout( perspective, dockables );

How is your tutorial PerspectivesHistory even working without:

        CWorkingPerspective work = (CWorkingPerspective)perspective.getStation( "work" );
        center.gridAdd( 0, 50, 100, 100, work );

Hi devent, I’ll have a look at your application during the weekend.

To your last question: because the working-area cannot be closed, and it’s default location is somewhere on the grid :wink:

Yes thank you.

Right now I’m thinking if I really need perspectives.
I can achieve the same if I just store and load layouts?
After reading the tutorials again, I think the perspective is to layout the docks before I add any docks?

In the end, loading a layout from a file, and loading a layout from a perspective are almost the same thing. Inside the framework the same algorithms are used to convert the layout-data in an actual layout (which is visible on the screen with Dockables).

With starting the application, moving the Dockables around manually, and then saving the layout(s) in a file you could indeed achieve the same results as with using perspectives.

Personally I prefer perspectives because it is easier for me to add new Dockables, and to make sure I did not forget one - but my way of working may not be the best choice for everyone :wink: