Adding items to the end of existing pop menu

Hi,

Is there a recommended way to add menu items to a CDockable’s title bar popup, but to the end of the existing popupmenu (mine are from DefaultSingleCDockable’s)?

I can add an action in my DefaultSingleCDockable’ subclass constructor, but this puts the item at the top of the list (I guess Minimize, Maximize, Extern etc. aren’t yet built at this point?).

I’ve tried overriding createCommonDockable(), but that leads to an infinite loop when I try to add an action.
(you’ve probably guessed I’m using the Common API)

Any ideas are much appreciated.

Thanks!
Peter

These menu items are created by so called "DockActionSource"s. Several sources contribute to one Dockable. Using the DefaultCDockable you have only access to one source, and the items of that one source are always put in front of the other items.

But you can create a new class implementing the interface “ActionGuard” and install it through “CControl().intern().getController().addActionGuard(…)”. This ActionGuard would look out for the CommonDockable which represents the Dockable where you want to add new actions. Then it would create a DockActionSource with a location hint set to “RIGHT_OF_ALL”. The framework would then add the actions of the your DockActionSource to the title too. I can write you an example tomorrow, if you wish.

Hi,

Many thanks for your quick reply!

In the current scenario (where items are added to the front of the list), these also show up in the title bar (I was wondering how to filter/modify this, but that’s a different issue).

When I was looking in the forum for a solution I noticed mention of ActionGuard, and even tried some example code with it, but it seemed to always be with the core library and I couldn’t get it to work with the Common lib - but this is probably my lack of awareness of how to do this.

If you can post a sample, that would be fantastic! It should prove useful for others trying similar things.

Many Thanks!
midiman

Here is an example with the Common lib. The actions are added to the “red” dockable only, and they do not show up in the title.


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

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

import bibliothek.gui.DockController;
import bibliothek.gui.Dockable;
import bibliothek.gui.dock.action.ActionGuard;
import bibliothek.gui.dock.action.DefaultDockActionSource;
import bibliothek.gui.dock.action.DockActionSource;
import bibliothek.gui.dock.action.LocationHint;
import bibliothek.gui.dock.action.actions.SimpleButtonAction;
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.DefaultSingleCDockable;
import bibliothek.gui.dock.common.SingleCDockable;
import bibliothek.gui.dock.common.action.CButton;
import bibliothek.gui.dock.common.intern.CDockable;
import bibliothek.gui.dock.common.intern.CommonDockable;

public class Dock31 {
    public static void main( String[] args ){
    	// setting up the frame...
        JFrame frame = new JFrame();
        frame.setBounds( 20, 20, 500, 500 );
        frame.setDefaultCloseOperation( JFrame.EXIT_ON_CLOSE );
        
        final CControl control = new CControl( frame );
        
        // at this point we install three new ActionGuards
        DockController controller = control.intern().getController();
        
        controller.addActionGuard( new CustomActionGuard( "New action to the left", LocationHint.VERY_LEFT ) );
        controller.addActionGuard( new CustomActionGuard( "New action to the middle", LocationHint.MIDDLE ) );
        controller.addActionGuard( new CustomActionGuard( "New action to the right", LocationHint.VERY_RIGHT ) );
        
        // and add a standard CAction to red, just to have some reference of where actions normally go
        final DefaultSingleCDockable red = create( "red", Color.RED );
        red.addAction( new CButton("Standard action", new RectIcon() ) {
			protected void action(){
				// ignore	
			}
		});
        
        final DefaultSingleCDockable green = create( "green", Color.GREEN );
        
        CGrid grid = new CGrid( control );
        grid.add( 0, 0, 1, 1, red );
        grid.add( 1, 0, 1, 1, green );
        control.getContentArea().deploy( grid );
        
        frame.add( control.getContentArea() );
        
        frame.setVisible( true );
    }
    
    public static DefaultSingleCDockable create( final String title, Color color ){
        JPanel panel = new JPanel();
        panel.setOpaque(true);
        panel.setBackground(color);

        DefaultSingleCDockable singleDockable = new DefaultSingleCDockable(title, title, panel);
        
        return singleDockable;
    }
    
    // This is our custom ActionGuard.
    public static class CustomActionGuard implements ActionGuard{
    	private DefaultDockActionSource source;
    	
    	public CustomActionGuard( String text, LocationHint.Hint location ){
    		// setting up the action we are going to use later
    		source = new DefaultDockActionSource( new LocationHint( LocationHint.ACTION_GUARD, location ));
    		source.add( new MenuOnlyAction( text ) );
    	}
    	
		public DockActionSource getSource( Dockable dockable ){
			// it would also be perfectly ok to call "new DefaultDockActionSource" and 
			// "new MenuOnlyAction" in this method, there is no need to always return
			// the same object.
			return source;
		}

		// only add the our new actions to those SingleCDockables with identifier "red"
		public boolean react( Dockable dockable ){
			if( dockable instanceof CommonDockable ){
				CDockable cdockable = ((CommonDockable)dockable).getDockable();
				if( cdockable instanceof SingleCDockable ){
					return ((SingleCDockable)cdockable).getUniqueId().equals( "red" );
				}
			}
			return false;
		}    	
    }
    
    // this is the kind of action we are going to add to the "red" dockable
    public static class MenuOnlyAction extends SimpleButtonAction{
    	public MenuOnlyAction( String text ){
    		setText( text );
    	}
    	
    	@Override
    	public <V> V createView( ViewTarget<V> target, ActionViewConverter converter, Dockable dockable ){
    		if( target == ViewTarget.TITLE ){
    			// don't show up on a title
    			return null;
    		}
    		
    		return super.createView( target, converter, dockable );
    	}
    }
    
    public static class RectIcon implements Icon{
		public int getIconHeight(){
			return 16;
		}

		public int getIconWidth(){
			return 16;
		}

		public void paintIcon( Component c, Graphics g, int x, int y ){
			g.setColor( Color.RED );
			g.fillRect( x, y, 16, 16 );
		}    	
    }
}```

Hi Beni,

You are an absolute star! Your sample code is a real, proper solution - thank you so much for this! I don’t think I would’ve ended up with that on my own.
On behalf of everyone that makes use of your excellent library: Thanks!

Peter