CWorkingArea

Hi,

Thank you Beni for the tooltip. It is working fine

I noticed a “bug”, [please confirm if it is] when doing the following scenario:

  1. double click on the “Log” Dockable it will maximize
  2. Right click on the “Log” dockable and select the “Minimize” menu item
    Current Result --> The log will be minimized but its space is still reserved
    Expected Result --> The “log” is minimized but it’s old space is take by the above dockables
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;

import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;

import bibliothek.gui.DockController;
import bibliothek.gui.DockStation;
import bibliothek.gui.Dockable;
import bibliothek.gui.dock.StackDockStation;
import bibliothek.gui.dock.action.DockActionSource;
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.CStation;
import bibliothek.gui.dock.common.DefaultSingleCDockable;
import bibliothek.gui.dock.common.SingleCDockable;
import bibliothek.gui.dock.common.group.CGroupBehavior;
import bibliothek.gui.dock.common.intern.AbstractDockableCStation;
import bibliothek.gui.dock.common.intern.CControlAccess;
import bibliothek.gui.dock.common.intern.CDockable;
import bibliothek.gui.dock.common.intern.CommonDockable;
import bibliothek.gui.dock.common.intern.station.CommonDockStation;
import bibliothek.gui.dock.common.intern.ui.CSingleParentRemover;
import bibliothek.gui.dock.common.mode.CNormalModeArea;
import bibliothek.gui.dock.common.mode.ExtendedMode;
import bibliothek.gui.dock.common.perspective.CStationPerspective;
import bibliothek.gui.dock.common.theme.ThemeMap;
import bibliothek.gui.dock.event.DockStationAdapter;
import bibliothek.gui.dock.facile.mode.Location;
import bibliothek.gui.dock.facile.mode.LocationMode;
import bibliothek.gui.dock.facile.mode.ModeAreaListener;
import bibliothek.gui.dock.layout.DockableProperty;
import bibliothek.gui.dock.support.mode.AffectedSet;
import bibliothek.gui.dock.util.DirectWindowProvider;
import bibliothek.gui.dock.util.DockUtilities;

import bibliothek.util.Path;


public class Dock65 {
    private static Integer counter = 1;


    public Dock65() {
    }


    public static void main(String[] args) {
        JFrame frame = new JFrame();
        final CControl control = new CControl();
        control.setGroupBehavior(CGroupBehavior.TOPMOST);
        CContentArea contentArea = control.getContentArea();
        final CGrid grid = new CGrid(control);
        control.getController().setSingleParentRemover(new CustomSingleParentRemover(control));
        control.setTheme(ThemeMap.KEY_ECLIPSE_THEME);
        control.setRootWindow(new DirectWindowProvider(frame));
        CStack consolestack = new CStack("Navigation");
        control.addStation(consolestack, true);

        DefaultSingleCDockable dockable = new DefaultSingleCDockable("Log");
        dockable.setCloseable(true);
        // Set the title of a dockable
        dockable.setTitleText("Log");
        control.addDockable(dockable);
        consolestack.getStation().add(dockable.intern(), 0);
//        dockable.setWorkingArea(consolestack);
        dockable.setVisible(true);
        grid.add(0, 50, 50, 15, consolestack);
        control.getContentArea().deploy(grid);

        NaviagtionCDockable navigationDockable = new NaviagtionCDockable("Tree");
        navigationDockable.setTitleToolTip("Navigation");
        grid.add(0, 11, 2, 40, navigationDockable);
        navigationDockable.setTitleText("Navigation");
        control.getContentArea().deploy(grid);

        final CStack screensstack = new CStack("screens");
        control.addStation(screensstack, true);
        grid.add(40, 11, 48, 40, screensstack);
        control.getContentArea().deploy(grid);
        navigationDockable.getOpenScreen().addActionListener(new ActionListener() {
                @Override
                public void actionPerformed(ActionEvent e) {
                    String id = "Title " + counter++;
                    DefaultSingleCDockable dockable = new DefaultSingleCDockable(id, id);
                    control.addDockable(dockable);
                    screensstack.getStation().add(dockable.intern(), 0);
                    dockable.setCloseable(true);
                    dockable.setWorkingArea(screensstack);
                    dockable.setVisible(true);
                }
            });

        frame.add(contentArea);
        frame.setSize(500, 500);
        frame.setVisible(true);
    }


    private static class CStack extends AbstractDockableCStation<StackDockStation> implements CNormalModeArea, SingleCDockable {

        public CStack(String id) {
            CStackDockStation delegate = new CStackDockStation(this);
            CLocation stationLocation = new CLocation() {
                @Override
                public CLocation getParent() {
                    return null;
                }

                @Override
                public String findRoot() {
                    return getUniqueId();
                }

                @Override
                public DockableProperty findProperty(DockableProperty successor) {
                    return successor;
                }

                @Override
                public ExtendedMode findMode() {
                    return ExtendedMode.NORMALIZED;
                }

                @Override
                public CLocation aside() {
                    return this;
                }
            };
            init(delegate, id, stationLocation, delegate);
        }

        @Override
        public CStationPerspective createPerspective() { /* For this example we do not support perspectives. */
            throw new IllegalStateException("not implemented");
        }

        @Override
        public boolean isNormalModeChild(Dockable dockable) {
            return isChild(dockable);
        }

        @Override
        public DockableProperty getLocation(Dockable child) {
            return DockUtilities.getPropertyChain(getStation(), child);
        }

        @Override
        public void setLocation(Dockable dockable, DockableProperty location, AffectedSet set) {
            set.add(dockable);
            if (isChild(dockable)) {
                getStation().move(dockable, location);
            } else {
                if (!getStation().drop(dockable, location)) {
                    getStation().drop(dockable);
                }
            }
        }

        @Override
        public void addModeAreaListener(ModeAreaListener listener) {
            // not required
        }

        @Override
        public Path getTypeId() {
            // not required
            return null;
        }

        @Override
        public boolean autoDefaultArea() {
            return true;
        }

        @Override
        public boolean isChild(Dockable dockable) {
            return dockable.getDockParent() == getStation();
        }

        @Override
        public void removeModeAreaListener(ModeAreaListener listener) {
            // not required
        }

        @Override
        public void setController(DockController controller) {
            // ignore
        }

        @Override
        public void setMode(LocationMode mode) {
            // ignore
        }

        @Override
        public CLocation getCLocation(Dockable dockable) {
            DockableProperty property = DockUtilities.getPropertyChain(getStation(), dockable);
            return getStationLocation().expandProperty(property);
        }

        @Override
        public CLocation getCLocation(Dockable dockable, Location location) {
            DockableProperty property = location.getLocation();
            if (property == null) {
                return getStationLocation();
            }
            return getStationLocation().expandProperty(property);
        }

        @Override
        public boolean respectWorkingAreas() {
            return false;
        }

        @Override
        public boolean isCloseable() {
            return false;
        }

        @Override
        public boolean isExternalizable() {
            return false;
        }

        @Override
        public boolean isMaximizable() {
            return false;
        }

        @Override
        public boolean isMinimizable() {
            return false;
        }

        @Override
        public boolean isStackable() {
            return false;
        }

        @Override
        public boolean isWorkingArea() {
            return false;
        }

        public DockActionSource[] getSources() {
            return new DockActionSource[] { getClose() };
        }

        /* This method is called by the CControl and allows access to some inner API that is
         * * * hidden from normal clients. */
        @Override
        protected void install(CControlAccess access) {
            access.getLocationManager().getNormalMode().add(this);
        }

        @Override
        protected void uninstall(CControlAccess access) {
            access.getLocationManager().getNormalMode().remove(getUniqueId());
        }
    }

    private static class CStackDockStation extends StackDockStation implements CommonDockStation<StackDockStation, CStackDockStation>, CommonDockable {

        private CStack delegate;


        public CStackDockStation(CStack stack) {
            this.delegate = stack;
            final Runnable makeVisible = new Runnable() {
                @Override
                public void run() {
                    delegate.setVisible(true);
                }
            };
            DockUtilities.disableCheckLayoutLocked();
            addDockStationListener(new DockStationAdapter() {
                    @Override
                    public void dockableAdded(DockStation station, Dockable dockable) {
                        DockController controller = delegate.getControl().getOwner().getController();
                        controller.getHierarchyLock().onRelease(makeVisible);
                    }
                });
        }


        @Override
        public CDockable getDockable() {
            return delegate;
        }

        @Override
        public DockActionSource[] getSources() {
            return delegate.getSources();
        }

        @Override
        public CStation<StackDockStation> getStation() {
            return delegate;
        }

        @Override
        public StackDockStation getDockStation() {
            return this;
        }

        @Override
        public CStackDockStation asDockStation() {
            return this;
        }

        @Override
        public CommonDockable asDockable() {
            return this;
        }
    }

    private static class NaviagtionCDockable extends DefaultSingleCDockable {
        JButton openScreenBtn = new JButton();
        private JPanel panel = new JPanel();


        public NaviagtionCDockable(String title) {
            super(title);
            setTitleText(title);
            panel = new JPanel();
            panel.setOpaque(true);
            add(panel);
            openScreenBtn = new JButton("Open screen");
            panel.add(openScreenBtn);
        }


        public JButton getOpenScreen() {
            return openScreenBtn;
        }
    }

    private static class CustomSingleParentRemover extends CSingleParentRemover {
        public CustomSingleParentRemover(CControl control) {
            super(control);
        }


        @Override
        protected boolean shouldTest(DockStation station) {
            if (isCStack(station)) {
                return true;
            }
            return super.shouldTest(station);
        }

        @Override
        protected boolean test(DockStation station) {
            if (isCStack(station)) {
                if ((station.getDockableCount() > 0) || (station.asDockable().getDockParent() == null)) {
                    return false;
                } else {
                    CStack stack = (CStack) ((CommonDockStation<?, ?>) station).getStation();
                    // stack.setVisible(false);  this line caused problems, let's do this manually
                    Dockable dockable = station.asDockable();
                    stack.getControl().getLocationManager().store(dockable);
                    stack.getControl().getOwner().intern().hide(dockable);
                    return false;
                        // because CStack is a root station
                }
            }
            return super.test(station);
        }

        private boolean isCStack(DockStation station) {
            if (station instanceof CommonDockStation<?, ?>) {
                if (((CommonDockStation<?, ?>) station).getStation() instanceof CStack) {
                    return true;
                }
            }
            return false;
        }
    }
}

could you please advice?

Thanks

Hi,

I noticed also one issue after taking the latest revision.
For example if in the “Dock 65” example:

  1. Double click on the “Navigation” dockable ==> [It will maximize]
  2. stay in the same position where you’ve clicked in order to maximize and double click in order to “Normalize” ==> [It won’t work]
  3. If you change [move a little bit] the clicked mouse position and double click again it will be “Normalized” successfully

Could you please advice?

Thanks

  1. That is probably the CStack that remains open (it does not have any decorations hence appears as “empty space”).
  2. Perhaps because new Components were added or moved around, the mouse was not updated. I’m not sure whether that is an issue of my framework or of Swing.

I’ll have a closer look to these bugs in the evening.

Concerning the first question, what happens: The Single-parent-remover receives an event whenever a new Dockable is registered. In this case the CStackDockStation gets first registered as dockable, then as station. And the chain of events is “add as dockable” “call SingleParentRemover” “register as DockStation”, but only those DockStations which are registered are actually checked by the SingleParentRemover… the order of the events is wrong. This is a minor bug in the framework which does not affect “normal” clients, as with normal clients a StackDockStation always has at least 2 children. So I’ll give you a workaround (see code below) and fix the bug later.

As for the second question: I did not yet find the bug, I’ll try again later, but it does not have a high priority.


import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;

import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;

import bibliothek.gui.DockController;
import bibliothek.gui.DockStation;
import bibliothek.gui.Dockable;
import bibliothek.gui.dock.StackDockStation;
import bibliothek.gui.dock.action.DockActionSource;
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.CStation;
import bibliothek.gui.dock.common.DefaultSingleCDockable;
import bibliothek.gui.dock.common.SingleCDockable;
import bibliothek.gui.dock.common.group.CGroupBehavior;
import bibliothek.gui.dock.common.intern.AbstractDockableCStation;
import bibliothek.gui.dock.common.intern.CControlAccess;
import bibliothek.gui.dock.common.intern.CDockable;
import bibliothek.gui.dock.common.intern.CommonDockable;
import bibliothek.gui.dock.common.intern.station.CommonDockStation;
import bibliothek.gui.dock.common.intern.ui.CSingleParentRemover;
import bibliothek.gui.dock.common.mode.CNormalModeArea;
import bibliothek.gui.dock.common.mode.ExtendedMode;
import bibliothek.gui.dock.common.perspective.CStationPerspective;
import bibliothek.gui.dock.common.theme.ThemeMap;
import bibliothek.gui.dock.event.DockStationAdapter;
import bibliothek.gui.dock.facile.mode.Location;
import bibliothek.gui.dock.facile.mode.LocationMode;
import bibliothek.gui.dock.facile.mode.ModeAreaListener;
import bibliothek.gui.dock.layout.DockableProperty;
import bibliothek.gui.dock.support.mode.AffectedSet;
import bibliothek.gui.dock.util.DirectWindowProvider;
import bibliothek.gui.dock.util.DockUtilities;

import bibliothek.util.Path;


public class Dock65 {
    private static Integer counter = 1;


    public Dock65() {
    }


    public static void main(String[] args) {
        JFrame frame = new JFrame();
        final CControl control = new CControl();
        control.setGroupBehavior(CGroupBehavior.TOPMOST);
        CContentArea contentArea = control.getContentArea();
        final CGrid grid = new CGrid(control);
        control.getController().setSingleParentRemover(new CustomSingleParentRemover(control));
        control.setTheme(ThemeMap.KEY_ECLIPSE_THEME);
        control.setRootWindow(new DirectWindowProvider(frame));
        CStack consolestack = new CStack("Navigation");
        control.addStation(consolestack, true);

        DefaultSingleCDockable dockable = new DefaultSingleCDockable("Log");
        dockable.setCloseable(true);
        // Set the title of a dockable
        dockable.setTitleText("Log");
        control.addDockable(dockable);
        consolestack.getStation().add(dockable.intern(), 0);
//        dockable.setWorkingArea(consolestack);
        dockable.setVisible(true);
        grid.add(0, 50, 50, 15, consolestack);
        control.getContentArea().deploy(grid);

        NaviagtionCDockable navigationDockable = new NaviagtionCDockable("Tree");
        navigationDockable.setTitleToolTip("Navigation");
        grid.add(0, 11, 2, 40, navigationDockable);
        navigationDockable.setTitleText("Navigation");
        control.getContentArea().deploy(grid);

        final CStack screensstack = new CStack("screens");
        control.addStation(screensstack, true);
        grid.add(40, 11, 48, 40, screensstack);
        control.getContentArea().deploy(grid);
        navigationDockable.getOpenScreen().addActionListener(new ActionListener() {
                @Override
                public void actionPerformed(ActionEvent e) {
                    String id = "Title " + counter++;
                    DefaultSingleCDockable dockable = new DefaultSingleCDockable(id, id);
                    control.addDockable(dockable);
                    screensstack.getStation().add(dockable.intern(), 0);
                    dockable.setCloseable(true);
                    dockable.setWorkingArea(screensstack);
                    dockable.setVisible(true);
                }
            });

        frame.add(contentArea);
        frame.setSize(500, 500);
        frame.setVisible(true);
    }


    private static class CStack extends AbstractDockableCStation<StackDockStation> implements CNormalModeArea, SingleCDockable {

        public CStack(String id) {
            CStackDockStation delegate = new CStackDockStation(this);
            CLocation stationLocation = new CLocation() {
                @Override
                public CLocation getParent() {
                    return null;
                }

                @Override
                public String findRoot() {
                    return getUniqueId();
                }

                @Override
                public DockableProperty findProperty(DockableProperty successor) {
                    return successor;
                }

                @Override
                public ExtendedMode findMode() {
                    return ExtendedMode.NORMALIZED;
                }

                @Override
                public CLocation aside() {
                    return this;
                }
            };
            init(delegate, id, stationLocation, delegate);
        }

        @Override
        public CStationPerspective createPerspective() { /* For this example we do not support perspectives. */
            throw new IllegalStateException("not implemented");
        }

        @Override
        public boolean isNormalModeChild(Dockable dockable) {
            return isChild(dockable);
        }

        @Override
        public DockableProperty getLocation(Dockable child) {
            return DockUtilities.getPropertyChain(getStation(), child);
        }

        @Override
        public void setLocation(Dockable dockable, DockableProperty location, AffectedSet set) {
            set.add(dockable);
            if (isChild(dockable)) {
                getStation().move(dockable, location);
            } else {
                if (!getStation().drop(dockable, location)) {
                    getStation().drop(dockable);
                }
            }
        }

        @Override
        public void addModeAreaListener(ModeAreaListener listener) {
            // not required
        }

        @Override
        public Path getTypeId() {
            // not required
            return null;
        }

        @Override
        public boolean autoDefaultArea() {
            return true;
        }

        @Override
        public boolean isChild(Dockable dockable) {
            return dockable.getDockParent() == getStation();
        }

        @Override
        public void removeModeAreaListener(ModeAreaListener listener) {
            // not required
        }

        @Override
        public void setController(DockController controller) {
            // ignore
        }

        @Override
        public void setMode(LocationMode mode) {
            // ignore
        }

        @Override
        public CLocation getCLocation(Dockable dockable) {
            DockableProperty property = DockUtilities.getPropertyChain(getStation(), dockable);
            return getStationLocation().expandProperty(property);
        }

        @Override
        public CLocation getCLocation(Dockable dockable, Location location) {
            DockableProperty property = location.getLocation();
            if (property == null) {
                return getStationLocation();
            }
            return getStationLocation().expandProperty(property);
        }

        @Override
        public boolean respectWorkingAreas() {
            return false;
        }

        @Override
        public boolean isCloseable() {
            return false;
        }

        @Override
        public boolean isExternalizable() {
            return false;
        }

        @Override
        public boolean isMaximizable() {
            return false;
        }

        @Override
        public boolean isMinimizable() {
            return false;
        }

        @Override
        public boolean isStackable() {
            return false;
        }

        @Override
        public boolean isWorkingArea() {
            return false;
        }

        public DockActionSource[] getSources() {
            return new DockActionSource[] { getClose() };
        }

        /* This method is called by the CControl and allows access to some inner API that is
         * * * hidden from normal clients. */
        @Override
        protected void install(CControlAccess access) {
            access.getLocationManager().getNormalMode().add(this);
        }

        @Override
        protected void uninstall(CControlAccess access) {
            access.getLocationManager().getNormalMode().remove(getUniqueId());
        }
    }

    private static class CStackDockStation extends StackDockStation implements CommonDockStation<StackDockStation, CStackDockStation>, CommonDockable {

        private CStack delegate;


        public CStackDockStation(CStack stack) {
            this.delegate = stack;
            final Runnable makeVisible = new Runnable() {
                @Override
                public void run() {
                    delegate.setVisible(true);
                }
            };
            final Runnable makeInvisible = new Runnable() {
            	public void run(){
            		if( getDockableCount() == 0 ){
                        delegate.getControl().getLocationManager().store(CStackDockStation.this);
                        delegate.getControl().getOwner().intern().hide(CStackDockStation.this);
            		}
            	}
            };
            DockUtilities.disableCheckLayoutLocked();
            addDockStationListener(new DockStationAdapter() {
                    @Override
                    public void dockableAdded(DockStation station, Dockable dockable) {
                        DockController controller = delegate.getControl().getOwner().getController();
                        controller.getHierarchyLock().onRelease(makeVisible);
                    }
                    
                    @Override
                    public void dockableRemoved( DockStation station, Dockable dockable ){
                    	DockController controller = delegate.getControl().getOwner().getController();
                        controller.getHierarchyLock().onRelease(makeInvisible);
                    }
                });
        }


        @Override
        public CDockable getDockable() {
            return delegate;
        }

        @Override
        public DockActionSource[] getSources() {
            return delegate.getSources();
        }

        @Override
        public CStation<StackDockStation> getStation() {
            return delegate;
        }

        @Override
        public StackDockStation getDockStation() {
            return this;
        }

        @Override
        public CStackDockStation asDockStation() {
            return this;
        }

        @Override
        public CommonDockable asDockable() {
            return this;
        }
    }

    private static class NaviagtionCDockable extends DefaultSingleCDockable {
        JButton openScreenBtn = new JButton();
        private JPanel panel = new JPanel();


        public NaviagtionCDockable(String title) {
            super(title);
            setTitleText(title);
            panel = new JPanel();
            panel.setOpaque(true);
            add(panel);
            openScreenBtn = new JButton("Open screen");
            panel.add(openScreenBtn);
        }


        public JButton getOpenScreen() {
            return openScreenBtn;
        }
    }

    private static class CustomSingleParentRemover extends CSingleParentRemover {
        public CustomSingleParentRemover(CControl control) {
            super(control);
        }


        @Override
        protected boolean shouldTest(DockStation station) {
            if (isCStack(station)) {
                return true;
            }
            return super.shouldTest(station);
        }

        @Override
        protected boolean test(DockStation station) {
            if (isCStack(station)) {
                if ((station.getDockableCount() > 0) || (station.asDockable().getDockParent() == null)) {
                    return false;
                } else {
                    CStack stack = (CStack) ((CommonDockStation<?, ?>) station).getStation();
                    // stack.setVisible(false);  this line caused problems, let's do this manually
                    Dockable dockable = station.asDockable();
                    stack.getControl().getLocationManager().store(dockable);
                    stack.getControl().getOwner().intern().hide(dockable);
                    return false;
                        // because CStack is a root station
                }
            }
            return super.test(station);
        }

        private boolean isCStack(DockStation station) {
            if (station instanceof CommonDockStation<?, ?>) {
                if (((CommonDockStation<?, ?>) station).getStation() instanceof CStack) {
                    return true;
                }
            }
            return false;
        }
    }
}```

Hi,

I’m upgrading to docking frames version 1.1.1 preview 5c and I noticed that their is some incompatibility with the above sample:
For example CControl.getOwner() isn’t available
What should I implement in getConverterID() method?

Thx

“getOwner” is no longer necessary because the return type of “CDockable.getControl” has changed. Just delete “getOwner”, and the project will compile again.

The implementation of “getConverterID” should be:

public String getConverterID() {
	return super.getFactoryID();
}```

[Edit: You should also override "getFactoryID":
```@Override
public String getFactoryID(){
	return CommonDockStationFactory.FACTORY_ID;
}

]

I’ll have a closer look if you still have issues, but that will have to wait until the weekend.