/*
* 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) 2012 Herve Guillaume, 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
*
* Herve Guillaume
* rvguillaume@hotmail.com
* FR - France
*
* Benjamin Sigg
* benjamin_sigg@gmx.ch
* CH - Switzerland
*/
package bibliothek.gui.dock.station.toolbar.title;
import java.awt.Component;
import java.awt.Dimension;
import java.awt.Insets;
import java.awt.Point;
import java.util.ArrayList;
import java.util.List;
import javax.swing.Icon;
import javax.swing.JComponent;
import javax.swing.SwingUtilities;
import bibliothek.gui.Dockable;
import bibliothek.gui.dock.action.DockAction;
import bibliothek.gui.dock.action.DockActionSource;
import bibliothek.gui.dock.action.LineDockActionSource;
import bibliothek.gui.dock.themes.basic.action.BasicTitleViewItem;
import bibliothek.gui.dock.themes.basic.action.buttons.ButtonPanel;
import bibliothek.gui.dock.title.AbstractMultiDockTitle;
import bibliothek.gui.dock.title.DockTitle;
import bibliothek.gui.dock.title.DockTitleVersion;
/**
* This specialized {@link DockTitle} does not show a text or even an {@link Icon}. Instead it shows several
* {@link DockActionSource}s, all derived from a single {@link ColumnDockActionSource}.
* @author Benjamin Sigg
*/
public abstract class ColumnDockTitle extends AbstractMultiDockTitle {
private List<ButtonPanel> itemPanels = new ArrayList<ButtonPanel>();
private ButtonPanel directPanel;
private ColumnDockActionSource source;
/**
* Creates a new title.
* @param dockable the element for which this title is used
* @param origin a description telling how this title was created
*/
public ColumnDockTitle( Dockable dockable, DockTitleVersion origin ){
init( dockable, origin );
directPanel = new ButtonPanel( true ){
@Override
protected BasicTitleViewItem<JComponent> createItemFor( DockAction action, Dockable dockable ){
return ColumnDockTitle.this.createItemFor( action, dockable );
}
};
add( directPanel );
}
/**
* This listener is added to the current {@link #source} and adds or removes {@link #itemPanels}
* when necessary.
*/
private ColumnDockActionSourceListener listener = new ColumnDockActionSourceListener(){
@Override
public void reshaped( ColumnDockActionSource source ){
revalidate();
}
@Override
public void removed( ColumnDockActionSource source, DockActionSource item, int index ){
if( isBound() ) {
ButtonPanel panel = itemPanels.remove( index );
panel.set( null );
panel.setController( null );
remove( panel );
revalidate();
}
}
@Override
public void inserted( ColumnDockActionSource source, DockActionSource item, int index ){
if( isBound() ) {
createPanel( item, index );
}
}
};
private void createPanel( DockActionSource item, int index ){
ButtonPanel panel = new ButtonPanel( true ){
@Override
protected BasicTitleViewItem<JComponent> createItemFor( DockAction action, Dockable dockable ){
return ColumnDockTitle.this.createItemFor( action, dockable );
}
};
panel.set( getDockable(), item );
panel.setController( getDockable().getController() );
panel.setOrientation( getOrientation() );
panel.setToolTipText( getToolTipText() );
itemPanels.add( index, panel );
add( panel );
revalidate();
}
@Override
public void setOrientation( Orientation orientation ){
if( getOrientation() != orientation ) {
super.setOrientation( orientation );
for( ButtonPanel panel : itemPanels ) {
panel.setOrientation( orientation );
}
directPanel.setOrientation( orientation );
revalidate();
}
}
/**
* Gets the {@link ColumnDockActionSource} that should be used for finding the actions
* of <code>dockable</code>.
* @param dockable the element that is represented by this title.
* @return the source for <code>dockable</code> or <code>null</code>
*/
protected abstract ColumnDockActionSource getSourceFor( Dockable dockable );
/**
* Gets the {@link DockActionSource} which should be used for <code>dockable</code>.
* @param dockable the element whose actions are shown
* @return all the actions
*/
protected DockActionSource getActionSourceFor( Dockable dockable ){
return new LineDockActionSource( dockable.getGlobalActionOffers() );
}
@Override
public void bind(){
if( !isBound() ) {
Dockable dockable = getDockable();
source = getSourceFor( dockable );
if( source != null ) {
for( int i = 0, n = source.getSourceCount(); i < n; i++ ) {
createPanel( source.getSource( i ), i );
}
source.addListener( listener );
}
directPanel.set( dockable, getActionSourceFor( dockable ) );
}
super.bind();
}
@Override
public void unbind(){
super.unbind();
if( !isBound() ) {
if( source != null ) {
source.removeListener( listener );
for( ButtonPanel panel : itemPanels ) {
panel.set( null );
panel.setController( null );
remove( panel );
}
directPanel.set( null );
itemPanels.clear();
revalidate();
source = null;
}
}
}
@Override
protected void updateIcon(){
// ignore
}
@Override
protected void updateText(){
// ignore
}
private int getOffset( int sourceIndex ){
int offset = source.getSourceOffset( sourceIndex );
Component dockable = getDockable().getComponent();
Point point = new Point( offset, offset );
if( SwingUtilities.getRoot( this ) == SwingUtilities.getRoot( dockable ) ) {
point = SwingUtilities.convertPoint( dockable, point, this );
}
if( source.getOrientation() == bibliothek.gui.Orientation.VERTICAL ) {
return point.x;
}
else {
return point.y;
}
}
@Override
protected void doTitleLayout(){
if( source == null ) {
return;
}
Insets insets = titleInsets();
int x = insets.left;
int y = insets.top;
int width = getWidth() - insets.left - insets.right;
int height = getHeight() - insets.top - insets.bottom;
boolean horizontal = getOrientation().isHorizontal();
for( int i = 0, n = source.getSourceCount(); i < n; i++ ) {
int start = getOffset( i );
int length = source.getSourceLength( i );
ButtonPanel items = itemPanels.get( i );
Dimension[] preferred = items.getPreferredSizes();
Dimension[] directPreferred = null;
if( i+1 == n ){
directPreferred = directPanel.getPreferredSizes();
if( horizontal ){
length -= directPreferred[0].width;
}
else{
length -= directPreferred[0].height;
}
}
if( horizontal ) {
int size = 0;
int delta = 0;
for( int j = preferred.length - 1; j >= 0; j-- ) {
if( preferred[j].width <= length ) {
size = j;
delta = length - preferred[j].width;
break;
}
}
items.setVisibleActions( size );
items.setBounds( start, y, length - delta, height );
if( i+1 == n ){
int remaining = width - start - length + delta;
size = 0;
delta = 0;
for( int j = directPreferred.length - 1; j >= 0; j-- ){
if( directPreferred[j].width <= remaining ) {
size = j;
delta = remaining - directPreferred[j].width;
break;
}
}
directPanel.setVisibleActions( size );
directPanel.setBounds( x + width - remaining + delta, y, remaining - delta, height );
}
}
else {
int size = 0;
int delta = 0;
for( int j = preferred.length - 1; j >= 0; j-- ) {
if( preferred[j].height <= length ) {
size = j;
delta = length - preferred[j].height;
break;
}
}
items.setVisibleActions( size );
items.setBounds( x, start, width, length - delta );
if( i+1 == n ){
int remaining = height - start - length + delta;
size = 0;
delta = 0;
for( int j = directPreferred.length - 1; j >= 0; j-- ){
if( directPreferred[j].height <= remaining ){
size = j;
delta = remaining - directPreferred[j].height;
break;
}
}
directPanel.setVisibleActions( size );
directPanel.setBounds( x, y + height - remaining + delta, width, remaining - delta );
}
}
}
}
@Override
public Dimension getPreferredSize(){
int w = 0;
int h = 0;
if( source != null ) {
if( getOrientation().isHorizontal() ) {
for( int i = 0, n = source.getSourceCount(); i < n; i++ ) {
w = Math.max( w, getOffset( i ) + source.getSourceLength( i ) );
h = Math.max( h, itemPanels.get( i ).getPreferredSize().height );
}
}
else {
for( int i = 0, n = source.getSourceCount(); i < n; i++ ) {
w = Math.max( w, itemPanels.get( i ).getPreferredSize().width );
h = Math.max( h, getOffset( i ) + source.getSourceLength( i ) );
}
}
}
w = Math.max( w, 5 );
h = Math.max( h, 5 );
Insets insets = titleInsets();
w += insets.left + insets.right;
h += insets.top + insets.bottom;
return new Dimension( w, h );
}
}