package bibliothek.gui.dock.support.menu;
import java.awt.Component;
import java.util.List;
import javax.swing.JPopupMenu;
/**
* A piece which envelops another piece with separators.
* @author Benjamin Sigg
*/
public class SeparatingMenuPiece extends MenuPiece{
/** whether to make a separator above this menupiece or not */
private boolean topSeparator = false;
/** whether to make a separator below this menupiece or not */
private boolean bottomSeparator = false;
/** whether to show a separator when there are no items in this menupiece */
private boolean emptySeparator = false;
/** the separator shown at the top */
private Component separatorTop = null;
/** the separator shown at the bottom */
private Component separatorBottom = null;
/** the source of items */
private MenuPiece piece;
/** a listener used to add or remove items */
private Listener listener = new Listener();
/**
* Creates a new piece
*/
public SeparatingMenuPiece(){
this( null );
}
/**
* Creates a new piece
* @param topSeparator whether to show a separator at the top
* @param emptySeparator whether to show a separator if <code>piece</code> is empty
* @param bottomSeparator whether to show a separator at the bottom
*/
public SeparatingMenuPiece( boolean topSeparator, boolean emptySeparator, boolean bottomSeparator ){
this( null, topSeparator, emptySeparator, bottomSeparator );
}
/**
* Creates a new piece
* @param piece the piece which might be covered by separators
*/
public SeparatingMenuPiece( MenuPiece piece ){
this( piece, false, false, false );
}
/**
* Creates a new piece
* @param piece the piece which might be covered by separators
* @param topSeparator whether to show a separator at the top
* @param emptySeparator whether to show a separator if <code>piece</code> is empty
* @param bottomSeparator whether to show a separator at the bottom
*/
public SeparatingMenuPiece( MenuPiece piece, boolean topSeparator, boolean emptySeparator, boolean bottomSeparator ){
setPiece( piece );
setTopSeparator( topSeparator );
setEmptySeparator( emptySeparator );
setBottomSeparator( bottomSeparator );
}
/**
* Gets the piece which is embraced by separators.
* @return the piece
*/
public MenuPiece getPiece(){
return piece;
}
@Override
public void bind(){
super.bind();
piece.bind();
}
@Override
public void unbind(){
super.unbind();
piece.unbind();
}
/**
* Sets the piece which will be embraced by separators.
* @param piece the child of this piece
*/
public void setPiece( MenuPiece piece ){
if( this.piece != piece ){
if( this.piece != null ){
listener.remove( piece, 0, piece.getItemCount() );
this.piece.setParent( null );
piece.removeListener( listener );
}
this.piece = piece;
if( this.piece != null ){
piece.setParent( this );
piece.addListener( listener );
listener.insert( piece, 0, piece.items() );
}
}
}
@Override
public int getItemCount(){
if( piece == null ){
return getSeparatorCount();
}
return piece.getItemCount() + getSeparatorCount();
}
@Override
public void fill( List<Component> items ){
if( piece == null || piece.getItemCount() == 0 ){
if( emptySeparator )
items.add( getEmptySeparator() );
}
else{
if( topSeparator )
items.add( getTopSeparator() );
piece.fill( items );
if( bottomSeparator )
items.add( getBottomSeparator() );
}
}
/**
* Gets the number of separators which were added by this piece.
* @return the number of separators
*/
protected int getSeparatorCount(){
if( piece != null && piece.getItemCount() > 0 ){
if( topSeparator && bottomSeparator )
return 2;
if( topSeparator || bottomSeparator )
return 1;
return 0;
}
else{
if( emptySeparator )
return 1;
return 0;
}
}
/**
* Tells whether there is a separator below this piece.
* @return <code>true</code> if there is a separator
* @see #setBottomSeparator(boolean)
*/
public boolean isBottomSeparator() {
return bottomSeparator;
}
/**
* Sets whether there should be a separator added to the menu after
* the contents described in this piece. Note that there might not be
* any separator if this piece is empty.
* @param bottomSeparator <code>true</code> if there should be a separator
*/
public void setBottomSeparator( boolean bottomSeparator ) {
if( this.bottomSeparator != bottomSeparator ){
this.bottomSeparator = bottomSeparator;
putUpSeparators();
MenuPiece parent = getParent();
if( parent != null ){
if( piece != null && piece.getItemCount() > 0 ){
if( bottomSeparator ){
fireInsert( getItemCount(), getBottomSeparator() );
}
else{
fireRemove( getItemCount()-1, 1 );
}
}
}
}
}
/**
* Tells whether there should be a single separator shown when this
* piece is empty.
* @return <code>true</code> if there is a separator
*/
public boolean isEmptySeparator() {
return emptySeparator;
}
/**
* Sets whether there should be a separator shown when this piece
* is empty.
* @param emptySeparator <code>true</code> if a separator should be
* made visible
*/
public void setEmptySeparator( boolean emptySeparator ) {
if( this.emptySeparator != emptySeparator ){
this.emptySeparator = emptySeparator;
putUpSeparators();
if( piece == null || piece.getItemCount() == 0 ){
if( emptySeparator ){
fireInsert( 0, getEmptySeparator() );
}
else{
fireRemove( 0, 1 );
}
}
}
}
/**
* Tells whether there is a separator shown above the content of this
* piece.
* @return <code>true</code> if there is a separator
*/
public boolean isTopSeparator() {
return topSeparator;
}
/**
* Sets whether there should be a separator shown above the content of
* this piece. Note that there might not be any separator if this piece
* is empty.
* @param topSeparator <code>true</code> if the separator should be shown
*/
public void setTopSeparator( boolean topSeparator ) {
if( this.topSeparator != topSeparator ){
this.topSeparator = topSeparator;
putUpSeparators();
if( piece != null && piece.getItemCount() > 0 ){
if( topSeparator ){
fireInsert( 0, getTopSeparator() );
}
else{
fireRemove( 0, 1 );
}
}
}
}
/**
* Gets the separator which is shown at the top.
* @return the separator or <code>null</code> if no separator is needed
*/
private Component getTopSeparator(){
return separatorTop;
}
/**
* Gets the separator which is shown at the bottom.
* @return the separator or <code>null</code> if no separator is needed
*/
private Component getBottomSeparator(){
return separatorBottom;
}
/**
* Gets the separator which is shown at when this piece is empty.
* @return the separator or <code>null</code> if no separator is needed
*/
private Component getEmptySeparator(){
if( separatorTop != null )
return separatorTop;
else
return separatorBottom;
}
/**
* Makes sure that there all separators needed for the menu are available.
*/
private void putUpSeparators(){
boolean top = topSeparator;
boolean bottom = bottomSeparator;
if( emptySeparator ){
if( !top && !bottom )
top = true;
}
if( top && separatorTop == null )
separatorTop = new JPopupMenu.Separator();
else if( !top && separatorTop != null )
separatorTop = null;
if( bottom && separatorBottom == null )
separatorBottom = new JPopupMenu.Separator();
else if( !top && separatorBottom != null )
separatorBottom = null;
}
/**
* A listener to all children, forwarding any call of inserting or removing
* items.
* @author Benjamin Sigg
*/
private class Listener implements MenuPieceListener{
public void insert( MenuPiece child, int index, Component... component ){
if( component.length > 0 ){
int count = piece.getItemCount() - component.length;
if( count == 0 ){
if( emptySeparator )
fireRemove( 0, 1 );
if( bottomSeparator )
fireInsert( 0, getBottomSeparator() );
if( topSeparator )
fireInsert( 0, getTopSeparator() );
}
if( topSeparator )
index++;
fireInsert( index, component );
}
}
public void remove( MenuPiece child, int index, int length ){
if( length > 0 ){
if( topSeparator )
index++;
fireRemove( index, length );
if( child.getItemCount() == 0 ){
if( topSeparator && bottomSeparator ){
fireRemove( 0, 2 );
}
else if( topSeparator || bottomSeparator ){
fireRemove( 0, 1 );
}
if( emptySeparator )
fireInsert( 0, getEmptySeparator() );
}
}
}
}
}