Popup menu on a StackDockStation

Hi,

I’m using eclipse theme and I want to add a popup menu on a StackDockStation.As I implement it the menu is not shown everywhere on this station. It is not shown on the the tab info.

import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.FlowLayout;

import javax.swing.JButton;
import javax.swing.JComponent;
import javax.swing.JFrame;
import javax.swing.JMenuItem;
import javax.swing.JPanel;
import javax.swing.JPopupMenu;

import bibliothek.extension.gui.dock.theme.EclipseTheme;

import bibliothek.gui.DockController;
import bibliothek.gui.dock.DefaultDockable;
import bibliothek.gui.dock.StackDockStation;
import bibliothek.gui.dock.station.stack.StackDockComponent;


public class PopupOnStackDockStation {

    public PopupOnStackDockStation() {
        JFrame frame = new JFrame();
        frame.setSize(600, 500);

        JPopupMenu popupMenu = new JPopupMenu();
        JMenuItem menu = new JMenuItem("MenuItem");
        popupMenu.add(menu);

        DockController controller = new DockController();
        controller.setTheme(new EclipseTheme());
        StackDockStation station = new StackDockStation();
        station.getComponent().setBackground(Color.RED);
        frame.add(station.getComponent(), BorderLayout.CENTER);
        controller.add(station);

        for (int i = 0; i < 2; i++) {
            JPanel panel = new JPanel(new FlowLayout());
            panel.add(new JButton("Button"));
            station.drop(new DefaultDockable(panel, "Dockable " + i));
        }
        ((JComponent) ((StackDockComponent) station.getStackComponent()).getComponent()).setComponentPopupMenu(popupMenu);
        frame.setVisible(true);
    }


    public static void main(String[] args) {
        new PopupOnStackDockStation();
    }
}


Thanks,

The MouseEvent gets processed by the Dockables and tabs - if there are any. If I run your code the popup menu appears at some places (right of the tabs). What exactly is your goal with this menu?

Maybe override “getDirectActionOffers” of StackDockStation, this way you can add DockAction’s to the children of the station (but there are other, easier ways to get actions onto Dockables, e.g. the ActionGuards).

Hi Beni,

I want the popup menu to be shown even if I right click on the title of the Dockable. Currently if I right click on the tab with title “Dockable 1” the popup didn’t appear, but if I right click on right of the dockable the popup menu appear, as you noticed in the example.

Thanks,

An ActionGuard and a modified DockAction can do that:


import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.FlowLayout;

import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;

import bibliothek.extension.gui.dock.theme.EclipseTheme;
import bibliothek.gui.DockController;
import bibliothek.gui.Dockable;
import bibliothek.gui.dock.DefaultDockable;
import bibliothek.gui.dock.StackDockStation;
import bibliothek.gui.dock.action.ActionGuard;
import bibliothek.gui.dock.action.DefaultDockActionSource;
import bibliothek.gui.dock.action.DockActionSource;
import bibliothek.gui.dock.action.actions.SimpleButtonAction;
import bibliothek.gui.dock.action.view.ActionViewConverter;
import bibliothek.gui.dock.action.view.ViewTarget;

public class Dock9 {

    public static void main(String[] args) {
        JFrame frame = new JFrame();
        frame.setDefaultCloseOperation( JFrame.EXIT_ON_CLOSE );
        frame.setSize(600, 500);

        DockController controller = new DockController();
        controller.addActionGuard( new MenuGuard() );
        
        controller.setTheme(new EclipseTheme());
        StackDockStation station = new StackDockStation();
        station.getComponent().setBackground(Color.RED);
        frame.add(station.getComponent(), BorderLayout.CENTER);
        controller.add(station);

        for (int i = 0; i < 2; i++) {
            JPanel panel = new JPanel(new FlowLayout());
            panel.add(new JButton("Button"));
            station.drop(new DefaultDockable(panel, "Dockable " + i));
        }
        
        frame.setVisible(true);
    }
    
    private static class MenuGuard implements ActionGuard{
    	private DockActionSource source;
    	
    	public MenuGuard(){
    		source = new DefaultDockActionSource( new MenuItem( "alpha" ), new MenuItem( "beta" ) );
    	}
    	
		@Override
		public DockActionSource getSource( Dockable dockable ){
			return source;
		}

		@Override
		public boolean react( Dockable dockable ){
			return dockable.getDockParent() instanceof StackDockStation || dockable instanceof StackDockStation;
		}
    }
    
    private static class MenuItem extends SimpleButtonAction{
    	public MenuItem( String text ){
			setText( text );
		}
    	
    	@Override
    	public <V> V createView( ViewTarget<V> target, ActionViewConverter converter, Dockable dockable ){
    		if( target == ViewTarget.MENU || target == ViewTarget.DROP_DOWN ){
    			return super.createView( target, converter, dockable );
    		}
    		else{
    			return null;
    		}
    	}
    }
}```

Hi,

Thank you for your answer
In my case, I have multiple “StackDockStation” and on each station I have a different menu.

Before upgrading to version 1.0.8, I was able to set a popup menu on all the “StackDockStation” by adding a popup menu on stackDockStation.getStackComponent();.

I was unable to set a popup menu on the whole “StackDockStation” in version 1.0.8 after the tab mechanism has been reimplemented

In the current version panels/components can get replaced any time. Keeping track of some popup-menu, repositioning it when necessary or forward events to it, would be hard. And since there is already a mechanism that can show popup menus (including any custom JComponent, sub-menus, etc…), I don’t see the point in supporting “old style” popup-menus.

If you have a lot of popup-menus already written, I can offer you a converter from popup-menu to DockActions. Unfortunatelly the menu will be destroyed in the process, I hope you can easily create new ones.


import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.FlowLayout;
import java.awt.event.ActionListener;

import javax.swing.JButton;
import javax.swing.JComponent;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JPopupMenu;

import bibliothek.extension.gui.dock.theme.EclipseTheme;
import bibliothek.gui.DockController;
import bibliothek.gui.Dockable;
import bibliothek.gui.dock.DefaultDockable;
import bibliothek.gui.dock.StackDockStation;
import bibliothek.gui.dock.action.ActionGuard;
import bibliothek.gui.dock.action.DefaultDockActionSource;
import bibliothek.gui.dock.action.DockAction;
import bibliothek.gui.dock.action.DockActionSource;
import bibliothek.gui.dock.action.view.ActionViewConverter;
import bibliothek.gui.dock.action.view.ViewTarget;
import bibliothek.gui.dock.themes.basic.action.menu.MenuViewItem;

public class Dock11 {

    public static void main(String[] args) {
        JFrame frame = new JFrame();
        frame.setDefaultCloseOperation( JFrame.EXIT_ON_CLOSE );
        frame.setSize(600, 500);

        DockController controller = new DockController();
        controller.addActionGuard( new MenuGuard() );
        
        controller.setTheme(new EclipseTheme());
        StackDockStation station = new StackDockStation();
        
        station.getComponent().setBackground(Color.RED);
        frame.add(station.getComponent(), BorderLayout.CENTER);
        controller.add(station);

        for (int i = 0; i < 2; i++) {
            JPanel panel = new JPanel(new FlowLayout());
            panel.add(new JButton("Button"));
            station.drop(new DefaultDockable(panel, "Dockable " + i));
        }
        
        frame.setVisible(true);
    }
    
    public static JPopupMenu getPopupMenu(StackDockStation station){
    	JPopupMenu menu = new JPopupMenu();
    	menu.add( "one" );
    	menu.add( "two" );
    	menu.addSeparator();
    	menu.add( "three" );
    	return menu;
    }
    
    private static class MenuGuard implements ActionGuard{
    	public DockActionSource getSource( Dockable dockable ){
    		StackDockStation station;
    		if( dockable instanceof StackDockStation ){
    			station = (StackDockStation)dockable;
    		}
    		else{
    			station = (StackDockStation)dockable.getDockParent();
    		}
    		
    		JPopupMenu menu = getPopupMenu( station );
    		DefaultDockActionSource source = new DefaultDockActionSource();
    		for( int i = 0, n = menu.getComponentCount(); i<n; i++ ){
    			source.add( new MenuItem( (JComponent)menu.getComponent( i ) ) );
    		}
    		return source;
		}

		public boolean react( Dockable dockable ){
			return dockable.getDockParent() instanceof StackDockStation || dockable instanceof StackDockStation;
		}
    }
    
    private static class MenuItem implements DockAction{
    	private JComponent item;
    	
    	public MenuItem( JComponent item ){
			this.item = item;
		}
    	
    	@Override
    	public void bind( Dockable dockable ){
	    	// ignore	
    	}
    	
    	@Override
    	public boolean trigger( Dockable dockable ){
	    	// ignore
    		return false;
    	}
    	
    	@Override
    	public void unbind( Dockable dockable ){
	    	// ignore	
    	}
    	
    	@SuppressWarnings("unchecked")
		@Override
    	public <V> V createView( ViewTarget<V> target, ActionViewConverter converter, Dockable dockable ){
    		if( target == ViewTarget.MENU ){
    			return (V)new MenuViewItem<JComponent>() {
					public void addActionListener( ActionListener listener ){
						// ignore
					}

					public void removeActionListener( ActionListener listener ){
						// ignore
					}

					public void bind(){
						// ignore
					}

					public DockAction getAction(){
						return MenuItem.this;
					}

					public JComponent getItem(){
						return item;
					}

					public void unbind(){
						// ignore
					}
				};
    		}
    		else{
    			return null;
    		}
    	}
    }
}```