(1) That one is easy, just call the “cancel” method like this
@Override
public boolean keyTyped( CDockable source, KeyEvent event ) {
return false;
}
@Override
public boolean keyReleased( CDockable source, KeyEvent event ) {
return false;
}
@Override
public boolean keyPressed( CDockable source, KeyEvent event ) {
if( event.getKeyCode() == KeyEvent.VK_ESCAPE ) {
control.getController().getRelocator().cancel();
return true;
}else{
return false;
}
}
} );```
You are right, this could be a nice little enhancement. I did put it on my todo-list.
*** Edit ***
(2) Yes, the "DockStationDropLayer" is responsible for deciding which station gets the Dockable. I can add a hook that allows clients to override the default behavior, currently you would need to replace the entire StackDockStation which is possible but a lot of work.
(3) You can implement the interface "DockRelactorMode" and the "VetoableDockRelocatorListener" to achieve such an effect. Like in the code below.
The "DockRelocatorMode" is invoked whenever the mouse is moved in a way that looks like a "drag&drop" operation. It is "activated" while a drag&drop operation actually is in progress or about to start, but only if the "shouldBeActive" method returned true. The "VetoableDockRelocatorListener" may be used to cancel any work that is done during or before a drag&drop operation.
``` StopEverything stop = new StopEverything();
control.getController().getRelocator().addMode( stop );
control.getController().getRelocator().addVetoableDockRelocatorListener( stop );
public class StopEverything extends VetoableDockRelocatorAdapter implements DockRelocatorMode{
private ModifierMask mask = new ModifierMask( KeyEvent.ALT_DOWN_MASK );
private boolean active;
@Override
public boolean shouldBeActive( DockController controller, int modifiers ) {
return !mask.matches( modifiers );
}
@Override
public void setActive( DockController controller, boolean active ) {
this.active = active;
}
@Override
public void searched( DockRelocatorEvent event ) {
if( active ){
event.forbid();
System.out.println("not allowed, alt not pressed");
}
}
}
*** Edit ***
(4) uh, never trust documentation.
Toolbars are managed by the “ToolbarStrategy”, which can be replaced by a custom strategy. You could define a strategy like the one below, which will allow any Dockable to be moved into the toolbar:
public boolean isToolbarPart(Dockable dockable) {
if( isSpecialDockable( dockable )){
return true;
}
return super.isToolbarPart( dockable );
}
public Dockable ensureToolbarLayer(DockStation station, Dockable dockable) {
if( isSpecialDockable( dockable )){
// "dockable" can now act as button, or as toolbar, or as group of toolbars... certainly more code is required to get "nice" behavior
return dockable;
}
return super.ensureToolbarLayer( station, dockable );
}
private boolean isSpecialDockable( Dockable dockable ){
// here you can write down any condition you would like to decide which Dockable can
// be put onto a toolbar.
return dockable instanceof CommonDockable;
}
} );```
If you add a "CDockableStateListener" to your "CDockables" and override the method "extendedModeChanged", then you will even receive an event if a Dockable is put into the toolbar.
You may actually insert a FlapDockStation between toolbar and Dockable, to get an effect that looks like the Dockable was added to the toolbar. Like in the code below. But when you run the example you will notice one or two issues and exceptions. This is certainly a feature that does not work out of the box, and it would need some work to function properly. Still, at least it is not completely impossible.
```package test;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JSpinner;
import javax.swing.SpinnerDateModel;
import bibliothek.gui.DockStation;
import bibliothek.gui.Dockable;
import bibliothek.gui.dock.FlapDockStation;
import bibliothek.gui.dock.FlapDockStation.Direction;
import bibliothek.gui.dock.common.CControl;
import bibliothek.gui.dock.common.DefaultSingleCDockable;
import bibliothek.gui.dock.common.event.CDockableStateListener;
import bibliothek.gui.dock.common.intern.CDockable;
import bibliothek.gui.dock.common.intern.DefaultCommonDockable;
import bibliothek.gui.dock.common.mode.ExtendedMode;
import bibliothek.gui.dock.common.theme.ThemeMap;
import bibliothek.gui.dock.dockable.DockableStateEvent;
import bibliothek.gui.dock.dockable.DockableStateListener;
import bibliothek.gui.dock.station.toolbar.DefaultToolbarStrategy;
import bibliothek.gui.dock.station.toolbar.ToolbarStrategy;
import bibliothek.gui.dock.toolbar.CToolbarContentArea;
import bibliothek.gui.dock.toolbar.CToolbarItem;
public class ToolbarTest {
public static void main( String[] args ) {
JFrame frame = new JFrame();
frame.setDefaultCloseOperation( JFrame.EXIT_ON_CLOSE );
final CControl control = new CControl(frame);
control.setTheme(ThemeMap.KEY_ECLIPSE_THEME);
control.putProperty( ToolbarStrategy.STRATEGY, new DefaultToolbarStrategy(){
public boolean isToolbarPart(Dockable dockable) {
if( isSpecialDockable( dockable )){
return true;
}
return super.isToolbarPart( dockable );
}
public Dockable ensureToolbarLayer(DockStation station, final Dockable dockable) {
if( isSpecialDockable( dockable )){
final FlapDockStation parent = new FlapDockStation();
parent.setAutoDirection( false );
parent.setDirection( Direction.SOUTH );
parent.addDockableStateListener( new DockableStateListener() {
@Override
public void changed( DockableStateEvent event ) {
if( parent.getDockParent() != null && parent.getController() != null ){
if( dockable.getDockParent() != parent ){
parent.add( dockable );
}
}
}
} );
return parent;
}
return super.ensureToolbarLayer( station, dockable );
}
private boolean isSpecialDockable( Dockable dockable ){
// here you can write down any condition you would like to decide which Dockable can
// be put onto a toolbar.
return dockable instanceof DefaultCommonDockable;
}
} );
// some other stuff
CToolbarContentArea toolbarArea = new CToolbarContentArea(control, "base");
control.addStationContainer(toolbarArea);
frame.add(toolbarArea);
JSpinner timeSpinner = new JSpinner(new SpinnerDateModel());
JSpinner.DateEditor timeEditor = new JSpinner.DateEditor(timeSpinner, "mm:ss.SSS");
timeSpinner.setEditor(timeEditor);
CToolbarItem prefToolbarItem = new CToolbarItem("pref");
prefToolbarItem.setLocation(toolbarArea.getNorthToolbar().getStationLocation());
prefToolbarItem.setItem(timeSpinner);
control.addDockable(prefToolbarItem);
prefToolbarItem.setVisible(true);
// adding the special Dockable
DefaultSingleCDockable specialDockable = new DefaultSingleCDockable( "a", "Aaaa" );
control.addDockable( specialDockable );
specialDockable.add( new JButton( "ABC" ) );
specialDockable.setVisible( true );
specialDockable.addCDockableStateListener( new CDockableStateListener() {
@Override
public void visibilityChanged( CDockable dockable ) {
// ignore
}
@Override
public void extendedModeChanged( CDockable dockable, ExtendedMode mode ) {
System.out.println(mode.getModeIdentifier());
}
} );
frame.setBounds( 20, 20, 600, 600 );
frame.setVisible( true );
}
}