/* * 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.frontend; import java.util.*; import bibliothek.gui.DockFrontend; import bibliothek.gui.Dockable; import bibliothek.gui.dock.event.DockFrontendAdapter; import bibliothek.gui.dock.event.VetoableDockFrontendEvent; import bibliothek.gui.dock.event.VetoableDockFrontendListener; import bibliothek.gui.dock.util.DockUtilities; /** * Used by a {@link DockFrontend} to correctly handle all {@link VetoableDockFrontendEvent}s. * @author Benjamin Sigg */ public class VetoManager { /** the owner of this manager */ private DockFrontend frontend; /** the set of elements which are not yet shown but are expected to show up soon */ private Set<Dockable> expectedToShow = new HashSet<Dockable>(); /** the set of elements which are not yet hidden but are expected to hide soon */ private Set<Dockable> expectedToHide = new HashSet<Dockable>(); /** the set of elements which are shown */ private Set<Dockable> dockables = new HashSet<Dockable>(); /** A list of observers to be notified if a {@link Dockable} gets closed or opened */ private List<VetoableDockFrontendListener> vetoableListeners = new ArrayList<VetoableDockFrontendListener>(); public VetoManager( DockFrontend frontend ){ if( frontend == null ) throw new IllegalArgumentException( "Frontend must not be null" ); this.frontend = frontend; frontend.addFrontendListener( new DockFrontendAdapter(){ @Override public void shown( DockFrontend frontend, Dockable dockable ) { boolean expected = expectedToShow.remove( dockable ); if( dockables.add( dockable )){ fireShown( dockable, expected ); } } @Override public void hidden( DockFrontend fronend, Dockable dockable ) { boolean expected = expectedToHide.remove( dockable ); if( dockables.remove( dockable )){ fireHidden( dockable, expected ); } } }); } /** * Gets the owner of this manager. * @return the owner */ public DockFrontend getFrontend() { return frontend; } /** * Marks all elements of the tree with root <code>dockable</code> to be expected to hide soon. * @param dockable the root of the elements which will be hidden * @param cancelable whether the operation can be aborted * @return <code>true</code> if the operation completed successful, <code>false</code> * if the operation was aborted */ public boolean expectToHide( Dockable dockable, boolean cancelable ){ return expectToHide( DockUtilities.listDockables( dockable, true ), cancelable ); } /** * Marks all elements of <code>dockables</code> to be expected to hide soon. * @param dockables the elements which will be hidden * @param cancelable whether the operation can be aborted * @return <code>true</code> if the operation completed successful, <code>false</code> * if the operation was aborted */ public boolean expectToHide( Collection<Dockable> dockables, boolean cancelable ){ boolean cancel = fireAllHiding( dockables, cancelable ); if( cancel ){ return false; } expectedToHide.addAll( dockables ); return true; } /** * Marks all elements of the tree with root <code>dockable</code> to be expected to show soon. * @param dockable the root of the elements * @param cancelable whether the operation can be aborted * @return <code>true</code> if the operation completed successful, <code>false</code> * if the operation was aborted */ public boolean expectToShow( Dockable dockable, boolean cancelable ){ return expectToShow( DockUtilities.listDockables( dockable, true ), cancelable ); } /** * Marks all elements of <code>dockables</code> to be expected to show soon. * @param dockables the elements which will be shown * @param cancelable whether the operation can be aborted * @return <code>true</code> if the operation completed successful, <code>false</code> * if the operation was aborted */ public boolean expectToShow( Collection<Dockable> dockables, boolean cancelable ){ boolean cancel = fireAllShowing( dockables, cancelable ); if( cancel ){ return false; } expectedToShow.addAll( dockables ); return true; } /** * Adds <code>listener</code> to this frontend. The listener will be notified * when a {@link Dockable} will be or is closed. * @param listener the new listener */ public void addVetoableListener( VetoableDockFrontendListener listener ){ vetoableListeners.add( listener ); } /** * Removes <code>listener</code> from this frontend. * @param listener the listener to remove */ public void removeVetoableListener( VetoableDockFrontendListener listener ){ vetoableListeners.remove( listener ); } /** * Gets an independent array containing all currently registered * {@link VetoableDockFrontendListener}s. * @return the array of listeners */ protected VetoableDockFrontendListener[] vetoableListeners(){ return vetoableListeners.toArray( new VetoableDockFrontendListener[ vetoableListeners.size() ] ); } /** * Calls the method {@link VetoableDockFrontendListener#hiding(VetoableDockFrontendEvent)} * for all elements in the tree beginning with <code>dockable</code>. * @param dockable the root of the tree of elements to remove * @param cancelable whether the operation can be aborted * @return <code>true</code> if the operation was aborted, <code>false</code> * if not. */ protected boolean fireAllHiding( Dockable dockable, final boolean cancelable ){ if( vetoableListeners.size() == 0 ) return false; List<Dockable> list = DockUtilities.listDockables( dockable, true ); return fireAllHiding( list, cancelable ); } /** * Calls the method {@link VetoableDockFrontendListener#hiding(VetoableDockFrontendEvent)} * for all elements in <code>dockables</code> * @param dockables a list of element which will be closed * @param cancelable whether the operation can be aborted * @return <code>true</code> if the operation was aborted, <code>false</code> * if not. */ protected boolean fireAllHiding( Collection<Dockable> dockables, final boolean cancelable ){ if( vetoableListeners.size() == 0 ) return false; if( dockables.isEmpty() ) return false; VetoableDockFrontendEvent event = new VetoableDockFrontendEvent( frontend, cancelable, true, dockables.toArray( new Dockable[ dockables.size()] )); for( VetoableDockFrontendListener listener : vetoableListeners() ){ listener.hiding( event ); } return event.isCanceled(); } /** * Invokes the method {@link VetoableDockFrontendListener#hidden(VetoableDockFrontendEvent)} * for all listeners for all elements in <code>dockables</code>. * @param dockables the elements that were hidden * @param expected whether this event was expected or unexpected */ protected void fireAllHidden( Collection<Dockable> dockables, final boolean expected ){ if( !dockables.isEmpty() ){ VetoableDockFrontendEvent event = new VetoableDockFrontendEvent( frontend, false, expected, dockables.toArray( new Dockable[ dockables.size()] )); for( VetoableDockFrontendListener listener : vetoableListeners() ){ listener.hidden( event ); } } } /** * Invokes the method {@link VetoableDockFrontendListener#shown(VetoableDockFrontendEvent)} * on all listeners. * @param dockable the element that was shown * @param expected whether the event was expected or not */ protected void fireHidden( Dockable dockable, boolean expected ){ VetoableDockFrontendEvent event = new VetoableDockFrontendEvent( frontend, false, expected, dockable ); for( VetoableDockFrontendListener listener : vetoableListeners() ) listener.hidden( event ); } /** * Invokes the method {@link VetoableDockFrontendListener#hidden(VetoableDockFrontendEvent)} * for all listeners for all elements of the tree with root <code>dockable</code>. * @param dockable the element that was hidden * @param expected whether this event was expected or unexpected */ protected void fireAllHidden( Dockable dockable, final boolean expected ){ fireAllHidden( DockUtilities.listDockables( dockable, true ), expected ); } /** * Calls {@link VetoableDockFrontendListener#showing(VetoableDockFrontendEvent)} * for all elements in the tree with root <code>dockable</code>. * @param dockable the root of the tree that will become visible * @param cancelable whether the operation can be canceled * @return <code>true</code> if the operation was aborted, <code>false</code> * if the operation can continue */ protected boolean fireAllShowing( Dockable dockable, final boolean cancelable ){ if( vetoableListeners.size() == 0 ) return false; return fireAllShowing( DockUtilities.listDockables( dockable, true ), cancelable ); } /** * Calls {@link VetoableDockFrontendListener#showing(VetoableDockFrontendEvent)} * for all elements in <code>dockables</code>. * @param dockables the element to show * @param cancelable whether the operation can be canceled * @return <code>true</code> if the operation was aborted, <code>false</code> * if the operation can continue */ protected boolean fireAllShowing( Collection<Dockable> dockables, final boolean cancelable ){ if( vetoableListeners.size() == 0 ) return false; if( dockables.isEmpty() ) return false; VetoableDockFrontendEvent event = new VetoableDockFrontendEvent( frontend, cancelable, true, dockables.toArray( new Dockable[ dockables.size()] )); for( VetoableDockFrontendListener listener : vetoableListeners() ){ listener.showing( event ); } return event.isCanceled(); } /** * Invokes the method {@link VetoableDockFrontendListener#shown(VetoableDockFrontendEvent)} * for all elements in the tree with root <code>dockable</code>. * @param dockable the root of the tree that is shown * @param expected whether the event is expected or not */ protected void fireAllShown( Dockable dockable, final boolean expected ){ if( vetoableListeners.size() == 0 ) return; List<Dockable> list = DockUtilities.listDockables( dockable, true ); fireAllShown( list, expected ); } /** * Invokes the method {@link VetoableDockFrontendListener#shown(VetoableDockFrontendEvent)} * for all elements in <code>dockables</code>. * @param dockables the set of newly shown elements * @param expected whether the event is expected or not */ protected void fireAllShown( Collection<Dockable> dockables, final boolean expected ){ if( vetoableListeners.size() == 0 ) return; if( !dockables.isEmpty() ){ VetoableDockFrontendEvent event = new VetoableDockFrontendEvent( frontend, false, expected, dockables.toArray( new Dockable[ dockables.size()] )); for( VetoableDockFrontendListener listener : vetoableListeners() ){ listener.shown( event ); } } } /** * Invokes the method {@link VetoableDockFrontendListener#shown(VetoableDockFrontendEvent)} * on all listeners. * @param dockable the element that was shown * @param expected whether the event was expected or not */ protected void fireShown( Dockable dockable, boolean expected ){ VetoableDockFrontendEvent event = new VetoableDockFrontendEvent( frontend, false, expected, dockable ); for( VetoableDockFrontendListener listener : vetoableListeners() ) listener.shown( event ); } }