Proper way to make "fixed pane" dock station?

Beni, hello;

can you please let me know:
what is the proper way to make “fixed pane” dock station?

that is, the one which stays “glued”, say, to the left border of the screen;

as in this example (lunch the “dock” jnlp):

http://code.google.com/p/widgetfx/

thank you;

Andrei

You need to implement the interface “DockAcceptance”. With the two methods you can forbid a Dockable to be dragged at a location where you don’t want it to be.

Then you have to call “DockController.addAcceptance” to tell the framework that it should use your new class.

got it, thanks;

  1. but it seems you explainend how to make a Dockable glued to the DockStation - which I also need;

  2. however what I asked is how to make ScreenDockStation glued to the actual display/screen position with fixed size?
    is there a feature for this in the docking-frames?

  3. please try to run this to see what I ask:
    http://widgetfx.org/dock/launch.jnlp

may be I am asking a wrong question wrongly :slight_smile:

let me try: in the language of docking frames,
I want to create one CControl, with two CScreenStations,
each of which contains one CGridArea, so I can move CDocables
between these screen stations / split areas;

how can I do this?

I don’t think that you need two ScreenDockStations, one should be sufficient: With the property ScreenDockStation.BOUNDARY_RESTRICTION you can introduce a BoundaryRestriction. The BoundaryRestriction decides for each window what location/size it can have. You need to make sure that your two CGridStations are children of the ScreenDockStation and that the boundary restriction forces them at the sides of the screen.

With the DockAcceptance you make sure that even if someone tries to drag around the SplitDockStation he cannot drop it anywhere (except perhaps another side of the screen?).

got it; thanks!

it feels like guides/common need a section: “how to extend docking-frames/common - by example”

I will post my examples here when done: http://code.google.com/p/docking-frames/

Beni:

I tried to follow your advice;
this is what I have so far:

http://code.google.com/p/docking-frames/source/browse/demo/trunk/docking-frames-examples/src/main/java/org/dockingframes/example/fixed_screen_dock/Main.java

2 problems with it:

  1. if I add red/green/blue dockables from central content area to the grid area that is inside screen station
    by dragging them, and then “normalize” them using the button on the dockable, the dockables just disappear;

  2. how do I provide drag/drop on the screen/grid area so that
    the user can flip the screen/grid area from left border of the screen to the right one?

Andrei

I can’t reproduce the first issue, whatever button I press the Dockables remain visible somewhere. You are sure the Dockables are not hidden behind each other? There is also something else: children of the screen/grid area are already considered “normalized” so there is no “normalize” button*

*(maybe they should not count as “normalized”, I’d have to think how that can be changed).

To the second question:
You need the right BoundaryRestriction.

    private Rectangle left;
    private Rectangle right;
    
    public AP_BoundaryRestriction(){
        Dimension screen = Toolkit.getDefaultToolkit().getScreenSize();
        left = new Rectangle(0, 0, screen.width/6, screen.height);
        right = new Rectangle(screen.width-screen.width/6, 0, screen.width/6, screen.height );
    }
    
    @Override
    public Rectangle check(ScreenDockWindow window) {
        Rectangle bounds = window.getWindowBounds();
        if( share( left, bounds ) > share( right, bounds )){
            return left;
        }
        else{
            return right;
        }
    }

    @Override
    public Rectangle check(ScreenDockWindow window, Rectangle target) {
        if( share( left, target ) > share( right, target )){
            return left;
        }
        else{
            return right;
        }
    }

    private int share(Rectangle a, Rectangle b){
        if( a.intersects(b)){
            Rectangle dest = new Rectangle();
            Rectangle.intersect(a, b, dest);
            return dest.width * dest.height;
        }
        return 0;
    }
}```


Probably you would also like to be able to drag the station independent on where you put the mouse, so you could modify the screen-windows to add a listener to the station. I did not test this code a lot, it might have some unexpected side effects.

This would be the new screen-window:
```    public class CustomScreenDockDialog extends ScreenDockDialog{
        private SplitDockStation station;
        
        private MouseInputListener listener = new MouseInputAdapter(){
            private Rectangle bounds;
            private Point start;
            
            public void mousePressed( MouseEvent e ){
                bounds = getWindowBounds();
                start = e.getPoint();
            }
            
            public void mouseDragged( MouseEvent e ){
                Point point = e.getPoint();
                SwingUtilities.convertPointToScreen( point, e.getComponent() );

                Rectangle bounds = new Rectangle( this.bounds );

                int dx = point.x - start.x;
                int dy = point.y - start.y;
                
                bounds.x += dx;
                bounds.y += dy;
                
                setWindowBounds( bounds );
                invalidate();
                validate();
            }
        };
        
        public CustomScreenDockDialog( ScreenDockStation station, JFrame owner ){
            super( station, owner, true );
        }
        
        @Override
        public void setDockable( Dockable dockable ){
            super.setDockable(dockable);
            if( dockable instanceof SplitDockStation ){
                setStation((SplitDockStation)dockable);
            }
            else{
                setStation(null);
            }
        }

        public void setStation(SplitDockStation station){
            if( this.station != null ){
                Component c = this.station.getContentPane();
                
                c.removeMouseListener( listener );
                c.removeMouseMotionListener( listener );
            }
            this.station = station;
            if( this.station != null ){
                Component c = this.station.getContentPane();
                
                c.addMouseListener( listener );
                c.addMouseMotionListener( listener );
            }
        }
        
        @Override
        public void destroy(){
            if( station != null ){
                station.removeMouseInputListener(listener);
            }
            super.destroy();
        }
    }```

...  and that is how it is applied:
```        control.putProperty(ScreenDockStation.WINDOW_FACTORY, new DefaultScreenDockWindowFactory(){
            @Override
            public ScreenDockWindow createWindow( ScreenDockStation station ){
                AbstractScreenDockWindow window;

                Window owner = station.getOwner();
                window = new CustomScreenDockDialog(station, (JFrame)owner );

                window.setShowTitle( isShowDockTitle() );
                window.setTitleIcon( getTitleIcon() );
                window.setTitleText( getTitleText() );
                return window;
            }
        });```

great! thank you; testing now;

can you please describe in javadoc the difference between

@Override
public Rectangle check(ScreenDockWindow window) {

and

@Override
public Rectangle check(ScreenDockWindow window, Rectangle target) {

I do not see first one called at all, not sure how different/same their implementations should be?

Beni:

I got it working and I understand all that needs be done in terms of location of screen stations:
http://code.google.com/p/docking-frames/source/browse/#svn/demo/trunk/docking-frames-examples/src/main/java/org/dockingframes/example/fixed_screen_dock

questions:

  1. sometimes when I move dockables around, control decides to
    dynamically create new screen-dock-station window/dialog (using provided factory);
    I know how to prevent this on the level of the dockable (like setExternalizable(false)),
    but how I do it on the level of CControl or CStation or ScreenDockStation?

  2. currently I add split-dock-stations like this:


		CStation<ScreenDockStation> screenCommon = (CStation<ScreenDockStation>) control
				.getStation(CControl.EXTERNALIZED_STATION_ID);

		CGridArea gridOne = control.createGridArea("grid one");

		control.add(gridOne);

		ScreenDockStation screen = screenCommon.getStation();

		screen.drop(gridOne.getStation());


is this correct? it feels wrong since I cross boundaries of core and common;

thank you;

Andrei

Beni:

you can run my test cases directly if you install this plugin:

http://m2eclipse.sonatype.org/installing-m2eclipse.html

and checkout eclipse projects from svn:

http://docking-frames.googlecode.com/svn/

Andrei

also remember you are an owner of the project:

http://code.google.com/p/docking-frames/

and can make changes to my tests directly

  1. The second question is more easy: it works, but you don’t need CORE API: CGridArea also implements SingleCDockable, so you can call “gridOne.setLocation( CLocation.external( ) )” or “gridOne.setExtendedMode( ExtendedMode.EXTERNALIZED );”.

[Edit: you may need to make a subclass of CGridArea and override the method “isExternalizable” such that it returns “true”]

  1. answered after dinner

There is an interface “ExtendedModeEnablement” (and some default implementations), with the property key “LocationModeManager.MODE_ENABLEMENT” you can set a factory for the current strategy. This interface decides for any Dockable (not only Common/CDockables) where it can be placed. If for example you tell that a SplitDockStation cannot be “normalized” * then the user cannot drag your screen/split-station onto your main-frame.

  • The documentation says you should not do that, but actually that is more a warning than a rule.

Alternatively a DockAcceptance (DockController.addAcceptance) can prevent almost any drag&drop operation that you don’t want (actually, the ExtendedModeEnablement is just wrapped into a DockAcceptance).

Beni:

regarding #2:

in this code:
http://code.google.com/p/docking-frames/source/browse/demo/trunk/docking-frames-examples/src/main/java/org/dockingframes/example/fixed_screen_dock/Main_3036_2.java

I am trying to setup 2 externalized CGridArea: one on left, one on right,
and then deploy there single dockable, using only COMMON;
the frame shows up; but left/right grid do not; what am I missing?

thank you;

Andrei

There are just a few calls missing:

You need to call “add(CStation, boolean)” in order to let the CControl know that “gridOne/Two” are used as station and that they should not be garbage collected. Without adding “gridOne/Two” as CStation, the framework sees two empty DockStations, and will immediately removes them because they “do not show anything”.

“Common” seldom checks whether a Dockable is also a DockStation or the other way around. So dockable stations need to added twice to a CControl, one time as Dockable, one time as Station.

(That is the default behavior that suits well for most situations, if you ever need to change it: call “DockController.setSingleParentRemover” to use your custom algorithm. But for the current example the behavior will be fine.)

control.add(gridTwo, true);```

The second issue is that you need to make "gridOne/Two" visible by calling their "setVisible" method. Just like a call to "JFrame.setBounds" does not make the JFrame visible, a call to "CDockable.setLocation" does not make it visible either.

A Dockable is visible if its parent is set (parent = null -> invisible, parent != null -> visible... unless the parent itself is invisible). That is the reason why "red" and "green" get visible once you call "deploy", "deploy" sets their parents.
```gridOne.setVisible(true);
gridTwo.setVisible(true);```

need more secret magic from you:

this change:

http://code.google.com/p/docking-frames/source/browse/demo/trunk/docking-frames-examples/src/main/java/org/dockingframes/example/fixed_screen_dock/Main_3036_2.java


		// must mark as root
		control.add(gridOne, true);
		control.add(gridTwo, true);

produces an exception:


Exception in thread "main" java.lang.IllegalArgumentException: dockable not registered
	at bibliothek.gui.dock.support.mode.ModeManager.apply(ModeManager.java:561)
	at bibliothek.gui.dock.support.mode.ModeManager.apply(ModeManager.java:504)
	at bibliothek.gui.dock.common.mode.CLocationModeManager.setLocation(CLocationModeManager.java:242)
	at bibliothek.gui.dock.common.intern.AbstractCDockable.setLocation(AbstractCDockable.java:292)
	at org.dockingframes.example.fixed_screen_dock.Main_3036_2.main(Main_3036_2.java:64)

when trying to set location:


        gridOne.setLocation(locationOne);

Uh, don’t delete the “add( gridOne/Two )” call. You need both “add” methods:

  • “add( gridOne/Two )” registers gridOne/Two as dockable and enables things like setting a location or making them visible
  • “add( gridOne/Two, true )” registers them as stations, makes sure they are not cleaned up, and allows “red” and “green” to use “gridOne/Two” as reference to their location.

works!

few suggestions:

a) probably methods should be called:
registerDockable()
registerDockStation()

b) or copy/paste above explanation into javadoc;

c) or at least link javadoc back to this forum;

you go through all this effort, but I fear your thoughs will be lost;

thank you;