/* * Bibliothek - DockingFrames * Library built on Java/Swing, allows the user to "drag and drop" * panels containing any Swing-Component the developer likes to add. * * Copyright (C) 2007 Benjamin Sigg * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA * * Benjamin Sigg * benjamin_sigg@gmx.ch * CH - Switzerland */ package bibliothek.gui.dock.control; import java.awt.Component; import java.awt.Point; import java.awt.event.MouseEvent; import java.util.HashMap; import java.util.Map; import javax.swing.SwingUtilities; import bibliothek.gui.DockController; import bibliothek.gui.Dockable; import bibliothek.gui.dock.DockElementRepresentative; import bibliothek.gui.dock.action.ActionPopup; import bibliothek.gui.dock.action.ActionPopupSuppressor; import bibliothek.gui.dock.action.DockAction; import bibliothek.gui.dock.action.DockActionSource; import bibliothek.gui.dock.action.popup.DefaultActionPopupMenuFactory; import bibliothek.gui.dock.action.popup.ActionPopupMenuFactory; import bibliothek.gui.dock.event.DockControllerRepresentativeListener; /** * Manages the popup menus, adds a listeners to all {@link DockElementRepresentative}s to open popup menus * when the user makes a right click. * @author Benjamin Sigg */ public class PopupController implements DockControllerRepresentativeListener{ /** tells which Dockable has which listener */ private Map<DockElementRepresentative, ComponentObserver> listeners = new HashMap<DockElementRepresentative, ComponentObserver>(); /** the controller for which this popup-controller works */ private DockController controller; /** this factory creates the menus that are popping up */ private ActionPopupMenuFactory factory = new DefaultActionPopupMenuFactory(); /** tells which popups are to be shown */ private ActionPopupSuppressor popupSuppressor = ActionPopupSuppressor.ALLOW_ALWAYS; /** if set, then popup menus may be opened during drag and drop operations */ private boolean allowOnMove = false; /** if set, then empty menus can be opened */ private boolean allowEmpty = false; /** * Creates a new popup-controller. * @param controller the controller for which this instance works */ public PopupController( DockController controller ){ if( controller == null ) throw new IllegalArgumentException( "controller must not be null" ); this.controller = controller; controller.addRepresentativeListener( this ); } public void representativeAdded( DockController controller, DockElementRepresentative representative ) { if( representative.getElement().asDockable() != null ){ ComponentObserver observer = new ComponentObserver( representative ); listeners.put( representative, observer ); representative.addMouseInputListener( observer ); } } public void representativeRemoved( DockController controller, DockElementRepresentative representative ) { if( representative.getElement().asDockable() != null ){ ComponentObserver observer = listeners.remove( representative ); if( observer != null ){ representative.removeMouseInputListener( observer ); } } } /** * Gets the {@link DockController} for which this {@link PopupController} works. * @return the owner of this controller */ public DockController getController(){ return controller; } /** * Sets the factory which creates new menus that pop up. * @param factory the factory creating menus, not <code>null</code> */ public void setPopupMenuFactory( ActionPopupMenuFactory factory ){ if( factory == null ){ throw new IllegalArgumentException( "the factory must not be null" ); } this.factory = factory; } /** * Gets the factory which is responsible for creating new menus. * @return the factory, never <code>null</code> */ public ActionPopupMenuFactory getPopupMenuFactory(){ return factory; } /** * Gets the guard which decides, which popups should be allowed. * @return the guard * @see #setPopupSuppressor(ActionPopupSuppressor) */ public ActionPopupSuppressor getPopupSuppressor() { return popupSuppressor; } /** * Sets the guard which decides, which popups with {@link DockAction DockActions} * are allowed to show up, and which popups will be suppressed. * @param popupSuppressor the guard */ public void setPopupSuppressor( ActionPopupSuppressor popupSuppressor ) { if( popupSuppressor == null ) throw new IllegalArgumentException( "suppressor must not be null" ); this.popupSuppressor = popupSuppressor; } /** * If set, then empty menus are still opened. The {@link ActionPopupSuppressor} or the * {@link ActionPopupMenuFactory} may however catch the empty menu and hide it. * @param allowEmpty if set to <code>false</code>, empty menus can never be shown */ public void setAllowEmptyMenu( boolean allowEmpty ){ this.allowEmpty = allowEmpty; } /** * Tells whether empty menus can be shown. * @return <code>true</code> if empty menus can be shown */ public boolean isAllowEmptyMenu(){ return allowEmpty; } /** * Sets whether menus can be opened during drag and drop operations. This property should * be remain <code>false</code> and only be set to <code>true</code> for very special occasions. * @param allowOnMove whether menus can be opened during drag and drop operations */ public void setAllowOnMove( boolean allowOnMove ){ this.allowOnMove = allowOnMove; } /** * Tells whether menus can be opened during drag and drop operations * @return <code>true</code> if menus can be opened all the time */ public boolean isAllowOnMove(){ return allowOnMove; } /** * A mouse listener opening a popup menu when necessary. * @author Benjamin Sigg */ private static class ComponentObserver extends ActionPopup{ /** the representation of the element for which this might open a popup */ private DockElementRepresentative representative; /** whether currently the mouse gets clicked */ private boolean onMouseClick = false; /** * Creates a new observer * @param representative the element which represents the {@link Dockable} * of this observer */ public ComponentObserver( DockElementRepresentative representative ){ super( true ); this.representative = representative; } @Override public void mouseClicked( MouseEvent e ){ if( isMenuOpen() ) return; if( isEnabled() && e.getClickCount() == 1 ){ try{ onMouseClick = true; popup( e.getComponent(), e.getX(), e.getY() ); } finally{ onMouseClick = false; } } } @Override protected Point getPopupLocation( Component owner, Point location ) { location = new Point( location ); location = SwingUtilities.convertPoint( owner, location, representative.getComponent() ); location = representative.getPopupLocation( location, !onMouseClick ); if( location == null ) return null; else location = new Point( location ); return SwingUtilities.convertPoint( representative.getComponent(), location, owner ); } @Override protected Dockable getDockable() { return representative.getElement().asDockable(); } @Override protected DockActionSource getActions() { return getDockable().getGlobalActionOffers(); } @Override protected Object getSource(){ return representative; } @Override protected boolean isEnabled() { return true; } } }