My question is how can I implement ‘Close all’ and ‘Close others’ actions in a MultipleCDockable like the ones in Eclipse ?
In fact 2 questions here :
By ‘like the ones in Eclipse’, I mean actions available in the popup menu when right clicking on a tab, but not available in the title.
How to close all the dockables ? I’ve tried things like in CCloseAction and CloseAction, but for dockables in the result of CControlRegister.getDockables(). But not sure that it is really the solution.
The solution may not be obvious, but this little example application should show you everything you need to know. In this case “Close Others” means “Close all Dockable which have the same parent” (e.g. are in the same stack).
import javax.swing.JFrame;
import bibliothek.gui.DockStation;
import bibliothek.gui.Dockable;
import bibliothek.gui.dock.action.view.ActionViewConverter;
import bibliothek.gui.dock.action.view.ViewTarget;
import bibliothek.gui.dock.common.CControl;
import bibliothek.gui.dock.common.CGrid;
import bibliothek.gui.dock.common.DefaultMultipleCDockable;
import bibliothek.gui.dock.common.action.CAction;
import bibliothek.gui.dock.common.action.CButton;
import bibliothek.gui.dock.common.action.core.CommonSimpleButtonAction;
import bibliothek.gui.dock.common.intern.CDockable;
import bibliothek.gui.dock.common.intern.CommonDockable;
import bibliothek.gui.dock.common.theme.ThemeMap;
public class CloseTest {
public static void main(String[] args) {
// set up a frame with some content...
JFrame frame = new JFrame();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
CControl control = new CControl( frame );
control.setTheme( ThemeMap.KEY_ECLIPSE_THEME );
frame.add( control.getContentArea() );
CGrid grid = new CGrid( control );
for( int i = 0; i < 4; i++ ){
grid.add( 0, 0, 1, 1, createDockable( 2*i ));
grid.add( 1, 0, 1, 1, createDockable( 2*i+1 ));
}
control.getContentArea().deploy( grid );
frame.setBounds( 20, 20, 400, 300 );
frame.setVisible( true );
}
private static CDockable createDockable( int index ){
DefaultMultipleCDockable dockable = new DefaultMultipleCDockable( null );
dockable.setCloseable( true );
dockable.setRemoveOnClose( true );
dockable.setTitleText( "Dockable " + index );
// here we add our new special action to the dockable.
dockable.addAction( new CloseOthersAction( dockable ));
return dockable;
}
// This is, as the name suggests, a button that closes other dockables.
// A CButton is actually a wrapper around a DockAction, we need to access the DockAction if we
// want to limit the places where the action shows up.
private static class CloseOthersAction extends CButton{
private CDockable dockable;
public CloseOthersAction( CDockable dockable ){
// prevent standard initialization of the action by calling the protected constructor
super( null );
// initialize with a modified action
init( new MenuOnlySimpleAction( this ) );
this.dockable = dockable;
setText( "Close Others" );
}
@Override
protected void action() {
super.action();
// We need to access the Core API to find out which other Dockables exist.
DockStation parent = dockable.intern().getDockParent();
// Because closing a Dockable may remove the parent DockStation, we first collect all the
// Dockables we may later close
Dockable[] children = new Dockable[ parent.getDockableCount() ];
for( int i = 0; i < children.length; i++ ){
children** = parent.getDockable( i );
}
for( Dockable child : children ){
// we are not interested in things like entire stacks, or our own Dockable. So let's do
// some checks before closing a Dockable
if( child instanceof CommonDockable ){
CDockable cChild = ((CommonDockable)child).getDockable();
if( cChild != dockable ){
cChild.setVisible( false );
}
}
}
}
}
private static class MenuOnlySimpleAction extends CommonSimpleButtonAction{
public MenuOnlySimpleAction( CAction action ){
super( action );
}
@Override
public <V> V createView( ViewTarget<V> target, ActionViewConverter converter, Dockable dockable ) {
// This method creates the view (e.g. a JMenuItem) for this DockAction. Since we do not want
// to show it up everywhere, we just ignore some places (targets).
if( ViewTarget.TITLE == target ){
return null;
}
return super.createView(target, converter, dockable);
}
}
}
One last question. To run the code, I had to manually install version 1.1.1 of common and core, because it is not available on maven central. Any reason for this ? Did I miss something ?
[QUOTE=bcantin]Thank you. That’s exactly what I need.
One last question. To run the code, I had to manually install version 1.1.1 of common and core, because it is not available on maven central. Any reason for this ? Did I miss something ?
Thanks again.[/QUOTE]
Ok, I’ve found your statement about maven and 1.1.1 (in the thread concerning 1.1.2). I’ll do it manually.
Your solution is close to what I would do, but you will have some bad side-effects from calling “setActionOffers”: you will no longer be able to show any other custom actions.
By extending DefaultMultipleCDockable you can create a DockActionSource that includes the “real” close action:
import javax.swing.JFrame;
import bibliothek.gui.DockStation;
import bibliothek.gui.Dockable;
import bibliothek.gui.dock.action.DefaultDockActionSource;
import bibliothek.gui.dock.action.DockActionSource;
import bibliothek.gui.dock.action.MultiDockActionSource;
import bibliothek.gui.dock.action.view.ActionViewConverter;
import bibliothek.gui.dock.action.view.ViewTarget;
import bibliothek.gui.dock.common.CControl;
import bibliothek.gui.dock.common.CGrid;
import bibliothek.gui.dock.common.DefaultMultipleCDockable;
import bibliothek.gui.dock.common.MultipleCDockableFactory;
import bibliothek.gui.dock.common.action.CAction;
import bibliothek.gui.dock.common.action.CButton;
import bibliothek.gui.dock.common.action.CSeparator;
import bibliothek.gui.dock.common.action.core.CommonSimpleButtonAction;
import bibliothek.gui.dock.common.intern.CDockable;
import bibliothek.gui.dock.common.intern.CommonDockable;
import bibliothek.gui.dock.common.intern.DefaultCommonDockable;
import bibliothek.gui.dock.common.intern.action.CloseActionSource;
import bibliothek.gui.dock.common.theme.ThemeMap;
public class CloseTest {
public static void main(String[] args) {
// set up a frame with some content...
JFrame frame = new JFrame();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
CControl control = new CControl( frame );
control.setTheme( ThemeMap.KEY_ECLIPSE_THEME );
frame.add( control.getContentArea() );
CGrid grid = new CGrid( control );
for( int i = 0; i < 4; i++ ){
grid.add( 0, 0, 1, 1, createDockable( 2*i ));
grid.add( 1, 0, 1, 1, createDockable( 2*i+1 ));
}
control.getContentArea().deploy( grid );
frame.setBounds( 20, 20, 400, 300 );
frame.setVisible( true );
}
private static CDockable createDockable( int index ){
DefaultMultipleCDockable dockable = new CloseableDefaultMultipleCDockable( null );
dockable.setTitleText( "Dockable " + index );
return dockable;
}
// our special Dockable for setting up additional actions at an unusual place
private static class CloseableDefaultMultipleCDockable extends DefaultMultipleCDockable{
public CloseableDefaultMultipleCDockable( MultipleCDockableFactory<? extends CloseableDefaultMultipleCDockable, ?> factory ) {
super( factory );
setCloseable( true );
setRemoveOnClose( true );
}
@Override
protected DefaultCommonDockable createCommonDockable() {
// note: this method is called from a super constructor!
// this is the "real" close action
DockActionSource defaultCloseAction = getClose();
// we create a list of additional actions.
DefaultDockActionSource additionalCloseActions = new DefaultDockActionSource();
additionalCloseActions.add(CSeparator.MENU_SEPARATOR.intern());
// actually the CloseOthersAction class would no longer need to extend CButton, extending
// SimpleButtonAction would be enough. But let's not change our first example.
additionalCloseActions.add(new CloseOthersAction(this).intern());
// we combine (group) our actions in one list of actions
MultiDockActionSource closeActions = new MultiDockActionSource( defaultCloseAction.getLocationHint() );
closeActions.add( additionalCloseActions );
closeActions.add( defaultCloseAction );
// and we create the new Core Dockable using our new list of actions
return new DefaultCommonDockable( this, closeActions );
}
}
// This is, as the name suggests, a button that closes other dockables.
// A CButton is actually a wrapper around a DockAction, we need to access the DockAction if we
// want to limit the places where the action shows up.
private static class CloseOthersAction extends CButton{
private CDockable dockable;
public CloseOthersAction( CDockable dockable ){
// prevent standard initialization of the action by calling the protected constructor
super( null );
// initialize with a modified action
init( new MenuOnlySimpleAction( this ) );
this.dockable = dockable;
setText( "Close Others" );
}
@Override
protected void action() {
super.action();
// We need to access the Core API to find out which other Dockables exist.
DockStation parent = dockable.intern().getDockParent();
// Because closing a Dockable may remove the parent DockStation, we first collect all the
// Dockables we may later close
Dockable[] children = new Dockable[ parent.getDockableCount() ];
for( int i = 0; i < children.length; i++ ){
children** = parent.getDockable( i );
}
for( Dockable child : children ){
// we are not interested in things like entire stacks, or our own Dockable. So let's do
// some checks before closing a Dockable
if( child instanceof CommonDockable ){
CDockable cChild = ((CommonDockable)child).getDockable();
if( cChild != dockable ){
cChild.setVisible( false );
}
}
}
}
}
private static class MenuOnlySimpleAction extends CommonSimpleButtonAction{
public MenuOnlySimpleAction( CAction action ){
super( action );
}
@Override
public <V> V createView( ViewTarget<V> target, ActionViewConverter converter, Dockable dockable ) {
// This method creates the view (e.g. a JMenuItem) for this DockAction. Since we do not want
// to show it up everywhere, we just ignore some places (targets).
if( ViewTarget.TITLE == target ){
return null;
}
return super.createView(target, converter, dockable);
}
}
}