All Downloads are FREE. Search and download functionalities are using the official Maven repository.

bibliothek.gui.dock.facile.menu.CloseableDockableMenuPiece Maven / Gradle / Ivy

Go to download

DockingFrames is an open source Java Swing docking framework, licenced under LGPL 2.1. This is the same distribution as the original distribution (http://www.docking-frames.org/), only reinstalled in maven

There is a newer version: 1.1.2p20b.fix-1
Show newest version
/*
 * 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
 * [email protected]
 * CH - Switzerland
 */
package bibliothek.gui.dock.facile.menu;

import java.awt.EventQueue;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.text.Collator;
import java.util.Arrays;
import java.util.Comparator;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.atomic.AtomicInteger;

import javax.swing.Icon;
import javax.swing.JCheckBoxMenuItem;

import bibliothek.gui.DockFrontend;
import bibliothek.gui.Dockable;
import bibliothek.gui.dock.event.DockFrontendAdapter;
import bibliothek.gui.dock.event.DockableListener;
import bibliothek.gui.dock.support.menu.BaseMenuPiece;
import bibliothek.gui.dock.title.DockTitle;

/**
 * A piece of a menu allowing to close or reopen some {@link Dockable}s that
 * are registered in a {@link DockFrontend}.
 * @author Benjamin Sigg
 *
 */
public class CloseableDockableMenuPiece extends BaseMenuPiece{
    /** the frontend that is currently observed */
    private DockFrontend frontend;
    
    /** a list of all items shown in the menu */
    private Map items = new HashMap();
    
    /** a listener collecting all new {@link Dockable}s of the {@link #frontend} */
    private DockableCollector collector = new DockableCollector();
    
    /** the comparator deciding how to sort the items */
    private Comparator order = new Comparator(){
    	private Collator collator = Collator.getInstance();

		public int compare( String o1, String o2 ){
			return collator.compare( o1, o2 );
		}
    };
    
    /** the identifier of the next {@link #order(int)} that will actually be executed */
    private AtomicInteger orderCommand = new AtomicInteger(0);
    
    /**
     * Creates a new piece
     */
    public CloseableDockableMenuPiece() {
    	// do nothing
    }
    
    /**
     * Creates a new piece
     * @param frontend the list of {@link Dockable}s, can be null
     */
    public CloseableDockableMenuPiece( DockFrontend frontend ) {
        setFrontend( frontend );
    }
    
    /**
     * Sets the order of the menu items. The default behavior is to order the
     * items alphabetically.
     * @param order the order, or null
     */
    public void setOrder( Comparator order ){
		this.order = order;
		reorder();
	}
    
    /**
     * Gets the order of the menu items.
     * @return the order, can be null
     */
    public Comparator getOrder(){
		return order;
	}
    
    /**
     * Asynchronously order the menu items
     */
    protected void reorder(){
    	final int identifier = orderCommand.incrementAndGet();
    	if( EventQueue.isDispatchThread() ){
	    	EventQueue.invokeLater( new Runnable(){
				public void run(){
					order( identifier );
				}
			} );
    	}
    	else{
    		order( identifier );
    	}
    }
    
    private void order( int identifier ){
    	if( identifier == orderCommand.get() && order != null ){
    		Item[] items = this.items.values().toArray( new Item[ this.items.size() ] );
    		Arrays.sort( items, new Comparator(){
    			public int compare( Item o1, Item o2 ){
    				return order.compare( o1.getText(), o2.getText() );
    			}
			});
    		
    		removeAll();
    		for( Item item : items ){
    			add( item );
    		}
    	}
    }
    
    /**
     * Gets the frontend which is observed by this piece.
     * @return the frontend, might be null
     * @see #setFrontend(DockFrontend)
     */
    public DockFrontend getFrontend() {
        return frontend;
    }
    
    /**
     * Sets the frontend which will be observed by this piece. Every
     * {@link Dockable} that is registered at the frontend will
     * get an item in the menu of this piece.
     * @param frontend the list of {@link Dockable}s, can be null
     */
    public void setFrontend( DockFrontend frontend ) {
        if( this.frontend != frontend ){
        	if( isBound() ){
	            if( this.frontend != null ){
	                this.frontend.removeFrontendListener( collector );
	                for( Item item : items.values() ){
	                    item.destroy();
	                    remove( item );
	                }
	                items.clear();
	            }
        	}
            
            this.frontend = frontend;
            
            if( isBound() ){
	            if( this.frontend != null ){
	                this.frontend.addFrontendListener( collector );
	                for( Dockable dockable : this.frontend.listDockables() ){
	                    collector.added( frontend, dockable );
	                }
	            }
            }
        }
    }
    
    @Override
    public void bind(){
	    if( !isBound() ){
	    	super.bind();
	    	
	    	if( frontend != null ){
                frontend.addFrontendListener( collector );
                for( Dockable dockable : this.frontend.listDockables() ){
                    collector.added( frontend, dockable );
                }
            }
	    }
    }
    
    @Override
    public void unbind(){
    	if( isBound() ){
    		super.unbind();
    		if( frontend != null ){
    			frontend.removeFrontendListener( collector );
    			for( Item item : items.values() ){
    				item.destroy();
    				remove( item );
    			}
    			items.clear();
    		}
    	}
    }
    
    /**
     * Creates a new item for the menu.
     * @param dockable the element which will be shown/hidden when the user
     * clicks onto the item.
     * @return the new item
     */
    protected Item create( Dockable dockable ){
        return new Item( dockable );
    }
    
    /**
     * Adds an earlier created item into the menu, subclasses might override
     * this method to add the item at a different location.
     * @param item the item to insert
     * @see #setOrder(Comparator)
     */
    protected void insert( Item item ){
        add( item );
        reorder();
    }
    
    /**
     * Ensures that dockable is visible.
     * @param dockable the element to show
     */
    protected void show( Dockable dockable ){
        frontend.show( dockable );
    }
    
    /**
     * Ensures that dockable is not visible.
     * @param dockable the element to hide
     */
    protected void hide( Dockable dockable ){
        frontend.hide( dockable );
    }
    
    /**
     * Tells whether an item should be inserted into the menu for the given
     * dockable or not.
     * @param dockable the element to check
     * @return true if there should be an item added to the menu
     */
    protected boolean include( Dockable dockable ){
        return frontend.isHideable( dockable );
    }
    
    /**
     * Ensures that dockable has an item if it is {@link #include(Dockable) included},
     * and does not have otherwise.
     * @param dockable the element whose item is to be checked
     */
    public void check( Dockable dockable ){
        if( include( dockable ) ){
            if( !items.containsKey( dockable ))
                collector.added( frontend, dockable );
        }
        else{
            if( items.containsKey( dockable )){
                collector.removed( frontend, dockable );
            }
        }
    }
    
    /**
     * A class that collects {@link Dockable}s and manages the states of the
     * {@link Item}s of the enclosing {@link CloseableDockableMenuPiece}.
     * @author Benjamin Sigg
     *
     */
    private class DockableCollector extends DockFrontendAdapter{
        @Override
        public void hidden( DockFrontend fronend, Dockable dockable ) {
            Item item = items.get( dockable );
            if( item != null ){
                item.setDockableState( false );
            }
        }
        
        @Override
        public void shown( DockFrontend frontend, Dockable dockable ) {
            Item item = items.get( dockable );
            if( item != null ){
                item.setDockableState( true );
            }
        }
        
        @Override
        public void added( DockFrontend frontend, Dockable dockable ) {
            if( include( dockable )){
                Item item = create( dockable );
                item.setDockableState( frontend.isShown( dockable ) );
                items.put( dockable, item );
                insert( item );
            }
        }
        
        @Override
        public void removed( DockFrontend frontend, Dockable dockable ) {
            Item item = items.remove( dockable );
            if( item != null ){
                item.destroy();
                remove( item );
            }
        }
        
        @Override
        public void hideable( DockFrontend frontend, Dockable dockable, boolean hideable ) {
            check( dockable );
        }
    }
    
    /**
     * An item showing the visibility state of one Dockable.
     * @author Benjamin Sigg
     */
    protected class Item extends JCheckBoxMenuItem implements DockableListener, ActionListener{
        /** the element that might be shown or hidden by this item */
        private Dockable dockable;
        
        /** whether the properties of this item are currently changing */
        private boolean onChange = false;
        
        /**
         * Creates a new item.
         * @param dockable the element that will be shown or hidden when the
         * user clicks onto this item
         */
        public Item( Dockable dockable ){
            this.dockable = dockable;
            dockable.addDockableListener( this );
            addActionListener( this );
            
            setIcon( dockable.getTitleIcon() );
            setText( dockable.getTitleText() );
        }
        
        /**
         * Sets whether the Dockable of this item is currently
         * visible or not.
         * @param visible the new state
         */
        public void setDockableState( boolean visible ){
            try{
                onChange = true;
                setSelected( visible );
            }
            finally{
                onChange = false;
            }
        }
        
        /**
         * Removes all listeners, frees as many resources as possible
         */
        public void destroy(){
            dockable.removeDockableListener( this );
            removeActionListener( this );
            setIcon( null );
            setText( "" );
        }

        public void titleBound( Dockable dockable, DockTitle title ) {
            // ignore
        }

        public void titleIconChanged( Dockable dockable, Icon oldIcon, Icon newIcon ) {
            setIcon( newIcon );
        }

        public void titleTextChanged( Dockable dockable, String oldTitle, String newTitle ) {
            setText( newTitle );
            reorder();
        }

        public void titleToolTipChanged( Dockable dockable, String oldToolTip, String newToolTip ) {
            // ignore
        }
        
        public void titleUnbound( Dockable dockable, DockTitle title ) {
            // ignore
        }
        
        public void titleExchanged( Dockable dockable, DockTitle title ) {
            // ignore
        }

        public void actionPerformed( ActionEvent e ) {
            if( !onChange ){
                if( isSelected() )
                    CloseableDockableMenuPiece.this.show( dockable );
                else
                    CloseableDockableMenuPiece.this.hide( dockable );
            }
        }
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy