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

bibliothek.gui.dock.station.stack.DefaultStackDockComponent Maven / Gradle / Ivy

The 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.station.stack;

import java.awt.Component;
import java.awt.Dimension;
import java.awt.Point;
import java.awt.Rectangle;
import java.awt.event.MouseEvent;
import java.util.ArrayList;
import java.util.List;

import javax.swing.Icon;
import javax.swing.JTabbedPane;
import javax.swing.SwingUtilities;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;
import javax.swing.event.MouseInputAdapter;

import bibliothek.gui.DockController;
import bibliothek.gui.Dockable;
import bibliothek.gui.dock.DockElement;
import bibliothek.gui.dock.DockElementRepresentative;
import bibliothek.gui.dock.action.ActionPopup;
import bibliothek.gui.dock.action.DockActionSource;
import bibliothek.gui.dock.control.RemoteRelocator;
import bibliothek.gui.dock.control.RemoteRelocator.Reaction;
import bibliothek.gui.dock.disable.TabDisablingStrategyObserver;
import bibliothek.gui.dock.station.stack.tab.layouting.TabPlacement;
import bibliothek.gui.dock.util.SimpleDockElementRepresentative;


/**
 * The standard-implementation of {@link StackDockComponent}. This implementation
 * uses a {@link JTabbedPane} to display its children.
 * 
 * @author Janni Kovacs
 * @author Benjamin Sigg
 * @see StackDockComponent
 * @see JTabbedPane
 */
public class DefaultStackDockComponent extends JTabbedPane implements StackDockComponent {
	/** The Dockables shown on this component and their RemoteRelocators to control drag&drop operations */
	private List dockables = new ArrayList();
	
	/** The controller for which this component is shown */
	private DockController controller;
	
	/** the tab to which mouse-events are currently redirected */
	private Tab mouseTarget;
	
	/** listeners to be informed if the selection changes */
	private List listeners = new ArrayList();
	
	/** keeps track of all tabs that need to be disabled */
	private TabDisablingStrategyObserver tabDisabling = new TabDisablingStrategyObserver(){
		@Override
		public void setDisabled( Dockable dockable, boolean disabled ){
			int index = indexOf( dockable );
			if( index >= 0 ){
				setEnabledAt( index, !disabled );
			}
		}
	};
	
	/**
	 * Constructs the component, sets the location of the tabs to bottom.
	 */
    public DefaultStackDockComponent(){
        super(BOTTOM);
        
        Listener listener = new Listener();
        addMouseListener( listener );
        addMouseMotionListener( listener );
        addChangeListener( listener );
        
        setOpaque( false );
    }
    
    public void addStackDockComponentListener( StackDockComponentListener listener ){
    	listeners.add( listener );
    }
    
    public void removeStackDockComponentListener( StackDockComponentListener listener ){
    	listeners.remove( listener );
    }
    
    public void setDockTabPlacement( TabPlacement tabSide ){
	    switch( tabSide ){
	    	case BOTTOM_OF_DOCKABLE:
	    		setTabPlacement( BOTTOM );
	    		break;
	    	case LEFT_OF_DOCKABLE:
	    		setTabPlacement( LEFT );
	    		break;
	    	case TOP_OF_DOCKABLE:
	    		setTabPlacement( TOP );
	    		break;
	    	case RIGHT_OF_DOCKABLE:
	    		setTabPlacement( RIGHT );
	    		break;
	    }
    }
    
    public TabPlacement getDockTabPlacement(){
    	switch( getTabPlacement() ){
    		case BOTTOM:
    			return TabPlacement.BOTTOM_OF_DOCKABLE;
    		case LEFT:
    			return TabPlacement.LEFT_OF_DOCKABLE;
    		case RIGHT:
    			return TabPlacement.RIGHT_OF_DOCKABLE;
    		case TOP:
    			return TabPlacement.TOP_OF_DOCKABLE;
    	}
    	
    	throw new IllegalStateException( "unknown position: " + getTabPlacement() );
    }
    
    public void insertTab(String title, Icon icon, Component comp, Dockable dockable, int index) {
        insertTab(title, icon, comp, (String)null, index);
        Tab tab = createTab( dockable );
        dockables.add( index, tab );
        tab.setController( controller );
        tabDisabling.add( dockable );
    }
    
    /**
     * Creates a new representation of a tab on this component.
     * @param dockable the element which is represented by the tab
     * @return the new tab
     */
    protected Tab createTab( Dockable dockable ){
        return new Tab( dockable );
    }

	public void addTab( String title, Icon icon, Component comp, Dockable dockable ){
		addTab( title, icon, comp );
		Tab tab = createTab( dockable );
        dockables.add( tab );
        tab.setController( controller );
        tabDisabling.add( dockable );
	}
	
	public Dockable getDockableAt( int index ){
		return dockables.get( index ).getDockable();
	}
	
	/**
	 * The structure of the {@link JTabbedPane} does not allow its tabs to recognized as {@link DockElementRepresentative}, 
	 * hence this method always returns null.
	 * @param index ignored
	 * @return null
	 */
	public DockElementRepresentative getTabAt( int index ){
		return null;
	}
	
	public void moveTab( int source, int destination ){
		if( source == destination ){
			return;
		}
		if( destination < 0 || destination >= getTabCount() ){
			throw new ArrayIndexOutOfBoundsException();
		}
		int selected = getSelectedIndex();
		
		String title = getTitleAt( source );
		String tooltip = getToolTipTextAt( source );
		Icon icon = getIconAt( source );
		Component comp = getComponentAt( source );
		Dockable dockable = dockables.get( source ).getDockable();
		
		remove( source );
		insertTab( title, icon, comp, dockable, destination );
		setTooltipAt( destination, tooltip );
		
		if( selected == source ){
			selected = destination;
		}
		else if( selected > source && selected <= destination ){
			selected++;
		}
		setSelectedIndex( selected );
	}
    
    @Override
    public void removeAll(){
    	for( Tab tab : dockables ){
    	    tab.setController( null );
    	    tabDisabling.remove( tab.getDockable() );
    	}
        super.removeAll();
    	dockables.clear();
    }
    
    @Override
    public void remove( int index ){
    	Tab tab = dockables.remove( index );
        tab.setController( null );
        tabDisabling.remove( tab.getDockable() );
        super.remove( index );
    }

    public Component getComponent() {
        return this;
    }
    
    @Override
    public void setTitleAt( int index, String title ){
    	super.setTitleAt( index, title == null ? "" : title );
    }
    
    public void setTooltipAt( int index, String newTooltip ) {
        setToolTipTextAt( index, newTooltip );
    }

	public void setController( DockController controller ){
		if( this.controller != controller ){
			if( mouseTarget != null ){
				if( mouseTarget.relocator != null ){
					mouseTarget.relocator.cancel();
				}
				mouseTarget = null;
			}
			
			this.controller = controller;
			tabDisabling.setController( controller );
			
		    for( Tab tab : dockables ){
		        tab.setController( controller );
		    }
		}
	}
	
	public boolean hasBorder() {
	    return true;
	}
	
	public boolean isSingleTabComponent(){
		return false;
	}
	
	public DockElementRepresentative createDefaultRepresentation( DockElement target ){
		return new SimpleDockElementRepresentative( target, this );
	}
	
	public int getIndexOfTabAt( Point mouseLocation ){
		for( int i = 0, n = getTabCount(); inull
	     * if this tab is no longer used, or when the connection to a 
	     * {@link DockController} is lost.
	     * @param controller the new source of information, can be null
	     */
	    public void setController( DockController controller ){
	        if( controller == null )
	            relocator = null;
	        else
	            relocator = controller.getRelocator().createRemote( dockable );
	    }

	    public void popup( MouseEvent event ){
	    	if( !event.isConsumed() && event.isPopupTrigger() ){
	    		super.popup( event );
	    	}
	    }
	    
		protected DockActionSource getActions(){
			return dockable.getGlobalActionOffers();
		}

		@Override
		protected Object getSource(){
			return this;
		}
		
		protected boolean isEnabled(){
			return true;
		}
	}
	
	/**
	 * A listener to the enclosing component, using some {@link RemoteRelocator}
	 * to do drag & drop operations.
	 * @author Benjamin Sigg
	 */
	private class Listener extends MouseInputAdapter implements ChangeListener{
		public void stateChanged( ChangeEvent e ){
			for( StackDockComponentListener listener : listeners.toArray( new StackDockComponentListener[ listeners.size() ] )){
				listener.selectionChanged( DefaultStackDockComponent.this );
			}
		}
		
		/**
		 * Updates the value of {@link DefaultStackDockComponent#mouseTarget relocator}
		 * @param x the x-coordinate of the mouse
		 * @param y the y-coordinate of the mouse
		 * @param searchDockable if true, then a new current relocator can be
		 * selected, otherwise the relocator may only be canceled by not exchanged
		 * @param forceSearch if true then a search is always made, even if the user is
		 * not allowed to move a tab anyways
		 */
		private void updateRelocator( int x, int y, boolean searchDockable, boolean forceSearch ){
		    boolean allowed = controller == null || !controller.getRelocator().isDragOnlyTitle();
		    
			if( mouseTarget != null ){
			    if( !allowed ){
			        mouseTarget.relocator.cancel();
			        if( !forceSearch ){
			        	mouseTarget = null;
			        }
			    }
			    
				return;
			}
			
			if( !allowed && !forceSearch ){
			    return;
			}
			
			if( searchDockable ){
				for( int i = 0, n = getTabCount(); i




© 2015 - 2024 Weber Informatics LLC | Privacy Policy