Override behavior of the pushpin button


#1

Is there any way that i can change the behavior of the pushpin button? The one that causes the visible flap-dock panels to stay visible. I would like for the pushpin to cause the panel to become docked in the pane just below it. Or maybe there is already a standard way to do that?


#2

There is no standard way to do something like this, but with a some tricky and some ugly code it is possible.

Down below you have a little example application that replaces the old sticky button with a custom button. This example will put all the Dockable at the top of the frame, but it should be a good starting point for further refinments.

package test;

import java.awt.Color;
import java.awt.Component;
import java.awt.Graphics;

import javax.swing.Icon;
import javax.swing.JFrame;

import bibliothek.gui.DockStation;
import bibliothek.gui.Dockable;
import bibliothek.gui.dock.FlapDockStation;
import bibliothek.gui.dock.action.ActionGuard;
import bibliothek.gui.dock.action.DefaultActionOffer;
import bibliothek.gui.dock.action.DefaultDockActionSource;
import bibliothek.gui.dock.action.DockAction;
import bibliothek.gui.dock.action.DockActionSource;
import bibliothek.gui.dock.action.FilteredDockActionSource;
import bibliothek.gui.dock.action.LocationHint;
import bibliothek.gui.dock.action.actions.SimpleButtonAction;
import bibliothek.gui.dock.common.CControl;
import bibliothek.gui.dock.common.CLocation;
import bibliothek.gui.dock.common.DefaultSingleCDockable;
import bibliothek.gui.dock.common.event.CControlListener;
import bibliothek.gui.dock.common.intern.AbstractCDockable;
import bibliothek.gui.dock.common.intern.CDockable;
import bibliothek.gui.dock.common.intern.CommonDockable;
import bibliothek.gui.dock.station.flap.FlapDockHoldToggle;
import bibliothek.gui.dock.station.flap.button.ButtonContentAction;

public class CustomStickyButtonTest {
    public static void main( String[] args ) {
        JFrame frame = new JFrame();
        CControl control = new CControl( frame );

        hideStickyButton( control );
        installCustomButton( control );

        frame.add( control.getContentArea() );

        for( int i = 0; i < 10; i++ ) {
            DefaultSingleCDockable dockable = new DefaultSingleCDockable( "i" + i, "Title " + i );
            control.addDockable( dockable );
            dockable.setLocation( CLocation.base().normal().stack() );
            dockable.setVisible( true );
        }

        frame.setBounds( 20, 20, 800, 800 );
        frame.setDefaultCloseOperation( JFrame.EXIT_ON_CLOSE );
        frame.setVisible( true );
    }

    private static void hideStickyButton( CControl control ) {
        // it's up to you which solution you like more, personally I would go with the first one
        hideStickyButtonSolution1( control );

        // hideStickyButtonSolution2( control );
    }

    private static void hideStickyButtonSolution1( CControl control ) {
        // hide the original button by disabling the "sticky" feature on all Dockables

        control.addControlListener( new CControlListener() {
            @Override
            public void removed( CControl control, CDockable dockable ) {
            }

            @Override
            public void opened( CControl control, CDockable dockable ) {
            }

            @Override
            public void closed( CControl control, CDockable dockable ) {
            }

            @Override
            public void added( CControl control, CDockable dockable ) {
                if( dockable instanceof AbstractCDockable ) {
                    ((AbstractCDockable) dockable).setStickySwitchable( false );
                }
            }
        } );
    }

    private static void hideStickyButtonSolution2( CControl control ) {
        // hide the original button by filtering the action

        control.getController().setDefaultActionOffer( new DefaultActionOffer() {
            @Override
            public DockActionSource getSource( Dockable dockable, DockActionSource source, DockActionSource[] guards, DockActionSource parent, DockActionSource[] parents ) {
                DockActionSource all = super.getSource( dockable, source, guards, parent, parents );

                return new FilteredDockActionSource( all ) {

                    @Override
                    protected boolean include( DockAction action ) {
                        return !(action instanceof FlapDockHoldToggle);
                    }
                };
            }
        } );
    }

    private static void installCustomButton( CControl control ) {
        // installing a new "ActionGuard", which will "inject" an action at the place where the old sticky action was
        // showing up
        control.getController().addActionGuard( new ActionGuard() {
            private DockActionSource customDockAction = createCustomButtonSource();

            @Override
            public boolean react( Dockable dockable ) {
                if( !(dockable instanceof CommonDockable) ) {
                    return false;
                }

                DockStation parent = dockable.getDockParent();
                while( parent != null ) {
                    // you might want to compare "parent" with stations like "control.getContentArea().getNorth()" to
                    // create one button for each of the differnt sides.
                    if( parent instanceof FlapDockStation ) {
                        return true;
                    }
                    dockable = parent.asDockable();
                    if( dockable == null ) {
                        return false;
                    }
                    parent = dockable.getDockParent();
                }
                return false;
            }

            @Override
            public DockActionSource getSource( Dockable dockable ) {
                return customDockAction;
            }
        } );
    }

    // an "action source" is just a List with DockActions.
    private static DockActionSource createCustomButtonSource() {
        DockAction action = new MyStickyButton();

        DefaultDockActionSource source = new DefaultDockActionSource( new LocationHint( LocationHint.DIRECT_ACTION, LocationHint.LITTLE_LEFT ) );
        source.add( action );
        return source;
    }

    @ButtonContentAction
    private static class MyStickyButton extends SimpleButtonAction {
        public MyStickyButton() {
            setText( "my custom button" );
            setIcon( new Icon() {
                @Override
                public void paintIcon( Component c, Graphics g, int x, int y ) {
                    g.setColor( Color.RED );
                    g.fillRect( x, y, 16, 16 );
                }

                @Override
                public int getIconWidth() {
                    return 16;
                }

                @Override
                public int getIconHeight() {
                    return 16;
                }
            } );
        }

        public void action( Dockable dockable ) {
            ((CommonDockable) dockable).getDockable().setLocation( CLocation.base().normal().north( 0.25 ).stack() );
        }
    }
}

#3

I just wanted to reply with a thank you. This code snippet totally did the trick!