How to justify left/top the action buttons ?

I use SplitDockStation into another SplitDockStation and also it’s difficult to understand which maximize button to use depending on the panel to be enlarge.
Is it possible to justify left (or top) the action buttons instead of right (or bottom) ?

Many thanks in advance

I am not certain I did understand your question.

The location of the actions is hard coded in most places, and can not be changed easily. I would really need to know what exactly you want to change where. A screenshot might help.

The order of actions can be switched by playing around with the “DockActionSource” (see the second snippet of code in this answer).

You have an application that works like this?

package test;

import javax.swing.JFrame;

import bibliothek.gui.dock.common.CControl;
import bibliothek.gui.dock.common.CGrid;
import bibliothek.gui.dock.common.CGridArea;
import bibliothek.gui.dock.common.DefaultSingleCDockable;
import bibliothek.gui.dock.common.SingleCDockable;

public class NestedSplitDockStations {
    public static void main( String[] args ) {
        JFrame frame = new JFrame( "title" );
        frame.setDefaultCloseOperation( JFrame.EXIT_ON_CLOSE );

        CControl control = new CControl( frame );
        frame.add( control.getContentArea() );

        CGridArea nested = control.createGridArea( "nested" );
        nested.setTitleShown( true );
        nested.setTitleText( "Nested" );

        CGrid base = new CGrid( control );
        base.add( 0, 0, 1, 1, create( "Left" ) );
        base.add( 1, 0, 1, 1, nested );
        control.getContentArea().deploy( base );
        
        CGrid nestedGrid = new CGrid( control );
        nestedGrid.add( 0, 0, 1, 1, create("Top") );
        nestedGrid.add( 0, 1, 1, 1, create("Down") );
        nested.deploy( nestedGrid );
        
        frame.setBounds( 100, 100, 800, 800 );
        frame.setVisible( true );
    }

    private static SingleCDockable create( String title ) {
        DefaultSingleCDockable dockable = new DefaultSingleCDockable( title, title );
        return dockable;
    }
}

One solution could just be to call …

nested.setMaximizingArea( false );

… because that would ensure that all the “maximize” buttons have the same effect.


Or you might want to replace the default action by a custom action (with new icons, etc). A general solution could look like this:

[code]
package test;

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

import javax.swing.JFrame;

import bibliothek.gui.DockStation;
import bibliothek.gui.Dockable;
import bibliothek.gui.dock.SplitDockStation;
import bibliothek.gui.dock.action.AbstractDockActionSource;
import bibliothek.gui.dock.action.DefaultActionOffer;
import bibliothek.gui.dock.action.DockAction;
import bibliothek.gui.dock.action.DockActionSource;
import bibliothek.gui.dock.action.LocationHint;
import bibliothek.gui.dock.common.CControl;
import bibliothek.gui.dock.common.CGrid;
import bibliothek.gui.dock.common.CGridArea;
import bibliothek.gui.dock.common.DefaultSingleCDockable;
import bibliothek.gui.dock.common.SingleCDockable;
import bibliothek.gui.dock.common.action.CButton;
import bibliothek.gui.dock.common.action.core.CommonSimpleButtonAction;
import bibliothek.gui.dock.common.action.predefined.CMaximizeAction;
import bibliothek.gui.dock.common.intern.CDockable;
import bibliothek.gui.dock.common.intern.CommonDockable;
import bibliothek.gui.dock.common.mode.ExtendedMode;
import bibliothek.gui.dock.event.DockActionSourceListener;

public class NestedSplitDockStations {
public static void main( String[] args ) {
JFrame frame = new JFrame( “title” );
frame.setDefaultCloseOperation( JFrame.EXIT_ON_CLOSE );

    CControl control = new CControl( frame );

    // adding an "ActionOffer" lets us take control over the way actions are generated
    control.getController().addActionOffer( new CustomActionOffer( control ) );

    frame.add( control.getContentArea() );

    CGridArea nested = control.createGridArea( "nested" );
    nested.setTitleShown( true );

    CGrid base = new CGrid( control );
    base.add( 0, 0, 1, 1, create( "Left" ) );
    base.add( 1, 0, 1, 1, nested );
    control.getContentArea().deploy( base );

    CGrid nestedGrid = new CGrid( control );
    nestedGrid.add( 0, 0, 1, 1, create( "Top" ) );
    nestedGrid.add( 0, 1, 1, 1, create( "Down" ) );
    nested.deploy( nestedGrid );

    frame.setBounds( 100, 100, 800, 800 );
    frame.setVisible( true );
}

private static SingleCDockable create( String title ) {
    DefaultSingleCDockable dockable = new DefaultSingleCDockable( title, title );
    return dockable;
}

private static class CustomActionOffer extends DefaultActionOffer {
    private CControl control;

    public CustomActionOffer( CControl control ) {
        this.control = control;
    }

    @Override
    public boolean interested( Dockable dockable ) {
        // we are only interested in the dockables that are child of two SplitDockStations
        return isNested( dockable ) && dockable instanceof CommonDockable;
    }

    @Override
    public DockActionSource getSource( Dockable dockable, DockActionSource source, DockActionSource[] guards, DockActionSource parent, DockActionSource[] parents ) {
        // just get the actions like we would normally...
        DockActionSource base = super.getSource( dockable, source, guards, parent, parents );
        CDockable cdockable = ((CommonDockable) dockable).getDockable();

        // ... but then replace the "maximize" button with our custom button
        return new ReplacingDockActionSource( cdockable, base, control );
    }
}

private static class ReplacingDockActionSource extends AbstractDockActionSource implements DockActionSourceListener {
    private DockActionSource base;
    private CButton replacedAction;

    public ReplacingDockActionSource( CDockable dockable, DockActionSource base, CControl control ) {
        this.base = base;

        // our replacement button for the "maximize" action
        replacedAction = new CButton( "Replaced", null );
        replacedAction.setShowTextOnButtons( true );
        replacedAction.addActionListener( new ActionListener() {
            @Override
            public void actionPerformed( ActionEvent e ) {
                dockable.setExtendedMode( ExtendedMode.MAXIMIZED );
            }
        } );
    }

    @Override
    public void addDockActionSourceListener( DockActionSourceListener listener ) {
        if( !hasListeners() ) {
            base.addDockActionSourceListener( this );
        }
        super.addDockActionSourceListener( listener );
    }

    @Override
    public void removeDockActionSourceListener( DockActionSourceListener listener ) {
        super.removeDockActionSourceListener( listener );
        if( !hasListeners() ) {
            base.removeDockActionSourceListener( this );
        }
    }

    @Override
    public void actionsAdded( DockActionSource source, int firstIndex, int lastIndex ) {
        fireAdded( firstIndex, lastIndex );
    }

    @Override
    public void actionsRemoved( DockActionSource source, int firstIndex, int lastIndex ) {
        fireRemoved( firstIndex, lastIndex );
    }

    @Override
    public LocationHint getLocationHint() {
        return base.getLocationHint();
    }

    @Override
    public int getDockActionCount() {
        return base.getDockActionCount();
    }

    @Override
    public DockAction getDockAction( int index ) {
        DockAction action = base.getDockAction( index );
        if( action instanceof CommonSimpleButtonAction ) {
            if( ((CommonSimpleButtonAction) action).getAction() instanceof CMaximizeAction ) {
                action = replacedAction.intern();
            }
        }
        return action;
    }

    @Override
    public Iterator<DockAction> iterator() {
        return new Iterator<DockAction>() {
            private int index = 0;

            @Override
            public DockAction next() {
                return getDockAction( index++ );
            }

            @Override
            public boolean hasNext() {
                return index < getDockActionCount();
            }
        };
    }

}

private static boolean isNested( Dockable dockable ) {
    DockStation parent = dockable.getDockParent();
    int count = 0;

    while( parent != null ) {
        if( parent instanceof SplitDockStation ) {
            count++;
        }
        dockable = parent.asDockable();
        if( dockable == null ) {
            parent = null;
        } else {
            parent = dockable.getDockParent();
        }
    }

    return count > 1;
}

}[/code]

Or to replace just the action of one Dockable:

dockable.putAction( CDockable.ACTION_KEY_MAXIMIZE, action );

Thanks for your answer. I would try it.

To be more clear, I have

and I would have something like this

I found the infoBounds is moved deltaX pixels in apply() method from MenuLineLayoutPossibility,

int deltaX = calculateDeltaX( order, item, itemWidth, availableWidth );

switch case INFO, force deltaX = 10; seems to work.

Alright, you are speaking about the tabs.

You might want to have a look at the class “StackTabLayoutExample”, it shows how to arrange tabs and buttons.

For your application, configuring the layout like this should help:

        /* Creating the new layout manager... */
        MenuLineLayout layoutManager = new MenuLineLayout();
        /* ... and configuring it. This manager can be configured by setting the MenuLineLayoutFactory. */
        layoutManager.setFactory( new DefaultMenuLineLayoutFactory(){
            /* This method is responsible for choosing order and size of the various items that may show up */
            public MenuLineLayoutOrder createOrder( MenuLineLayout layout, TabPane pane ){
                MenuLineLayoutOrder order = new MenuLineLayoutOrder( Item.TABS, Item.MENU, Item.INFO );
                /* The parameters we set are, from left to right:
                 *  - The item to modify
                 *  - Weight: how much empty space belongs to the item
                 *  - Alignment: whether the item will show at the left or the right end of the empty space
                 *  - Fill: whether the item gets stretched to fill up the empty space */
                order.setConstraints( Item.TABS, 0.0f, 0.0f, 0.0f );
                order.setConstraints( Item.MENU, 0.0f, 0.0f, 0.0f );
                order.setConstraints( Item.INFO, 1.0f, 0.0f, 0.0f );
                return order;
            }
        });
        /* And we need to set the current layout manager using the DockProperties */
        ccontrol.putProperty( TabPane.LAYOUT_MANAGER, layoutManager );

Thanks a lot Beni and congratulations for this library.
It’s exactly what I was trying to do.

I have another question, I will ask it in a new post…