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.
but it seems you explainend how to make a Dockable glued to the DockStation - which I also need;
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?
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;
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?).
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;
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?
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;
}
});```
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?
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”]
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).
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?
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);```
// 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)
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.