/*
* 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) 2008 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.themes.basic;
import java.awt.Component;
import java.awt.Container;
import java.awt.Dimension;
import java.awt.GridLayout;
import java.awt.Insets;
import java.awt.Point;
import java.util.ArrayList;
import java.util.List;
import javax.swing.BorderFactory;
import javax.swing.JComponent;
import javax.swing.SwingUtilities;
import javax.swing.border.BevelBorder;
import javax.swing.border.Border;
import bibliothek.gui.DockController;
import bibliothek.gui.DockStation;
import bibliothek.gui.Dockable;
import bibliothek.gui.dock.DockElementRepresentative;
import bibliothek.gui.dock.action.DockAction;
import bibliothek.gui.dock.action.DockActionSource;
import bibliothek.gui.dock.component.DockComponentConfiguration;
import bibliothek.gui.dock.component.DockComponentRootHandler;
import bibliothek.gui.dock.displayer.DisplayerBackgroundComponent;
import bibliothek.gui.dock.displayer.DisplayerCombinerTarget;
import bibliothek.gui.dock.displayer.DisplayerDockBorder;
import bibliothek.gui.dock.displayer.DisplayerFocusTraversalPolicy;
import bibliothek.gui.dock.displayer.DockableDisplayerHints;
import bibliothek.gui.dock.displayer.SingleTabDecider;
import bibliothek.gui.dock.event.SingleTabDeciderListener;
import bibliothek.gui.dock.focus.DockFocusTraversalPolicy;
import bibliothek.gui.dock.station.DisplayerCollection;
import bibliothek.gui.dock.station.DisplayerFactory;
import bibliothek.gui.dock.station.DockableDisplayer;
import bibliothek.gui.dock.station.DockableDisplayerListener;
import bibliothek.gui.dock.station.stack.action.DockActionDistributor;
import bibliothek.gui.dock.station.stack.action.DockActionDistributor.Target;
import bibliothek.gui.dock.station.stack.action.DockActionDistributorSource;
import bibliothek.gui.dock.station.support.CombinerSource;
import bibliothek.gui.dock.station.support.Enforcement;
import bibliothek.gui.dock.themes.ThemeManager;
import bibliothek.gui.dock.themes.border.BorderForwarder;
import bibliothek.gui.dock.title.ActionsDockTitleEvent;
import bibliothek.gui.dock.title.DockTitle;
import bibliothek.gui.dock.util.BackgroundAlgorithm;
import bibliothek.gui.dock.util.ConfiguredBackgroundPanel;
import bibliothek.gui.dock.util.PropertyKey;
import bibliothek.gui.dock.util.PropertyValue;
import bibliothek.gui.dock.util.Transparency;
import bibliothek.gui.dock.util.UIValue;
/**
* A panel which shows one {@link Dockable} and one {@link DockTitle}. The location
* of the {@link DockTitle} is always at one of the four borders (left,
* right, top, bottom). The title may be <code>null</code>, in this case only
* the <code>Dockable</code> is shown.<br>
* Clients using a displayer should try to set the {@link #setController(DockController) controller}
* and the {@link #setStation(DockStation) station} property.<br>
* Subclasses may override {@link #getComponent(Dockable)} and/or {@link #getComponent(DockTitle)}
* if they want to introduce a completely new layout needing more {@link Container Containers}.
* @see DisplayerCollection
* @see DisplayerFactory
* @author Benjamin Sigg
*/
public class BasicDockableDisplayer extends ConfiguredBackgroundPanel implements DockableDisplayer{
/** The content of this displayer */
private Dockable dockable;
/** The title on this displayer */
private DockTitle title;
/** the location of the title */
private Location location;
/** the station on which this displayer might be shown */
private DockStation station;
/** the controller for which this displayer might be used */
private DockController controller;
/** the set of hints for this displayer */
private Hints hints = new Hints();
/** whether the hint for the border of {@link DockableDisplayerHints} should be respected */
private boolean respectBorderHint = false;
/** the default value for the border hint */
private boolean defaultBorderHint = true;
/** whether to show the inner border if a single tab is in use */
private boolean singleTabShowInnerBorder = true;
/** whether to show the outer border if a single tab is in use */
private boolean singleTabShowOuterBorder = true;
/** whether the tab is shown below the title, if there is a tab and a title */
private boolean tabInside = false;
/** all listeners known to this displayer */
private List<DockableDisplayerListener> listeners = new ArrayList<DockableDisplayerListener>();
/** the background algorithm of this panel */
private Background background = new Background();
/** the border strategy of this panel */
private DisplayerBorder baseBorder;
/** the border strategy of the content panel of this displayer */
private DisplayerBorder contentBorder;
/** this listener gets added to the current {@link SingleTabDecider} */
private SingleTabDeciderListener singleTabListener = new SingleTabDeciderListener(){
public void showSingleTabChanged( SingleTabDecider source, Dockable dockable ){
if( dockable == BasicDockableDisplayer.this.dockable ){
updateDecorator();
}
}
};
/** the current {@link SingleTabDecider} */
private PropertyValue<SingleTabDecider> decider = new PropertyValue<SingleTabDecider>( SingleTabDecider.SINGLE_TAB_DECIDER ){
@Override
protected void valueChanged( SingleTabDecider oldValue, SingleTabDecider newValue ){
if( oldValue != null )
oldValue.removeSingleTabDeciderListener( singleTabListener );
if( newValue != null )
newValue.addSingleTabDeciderListener( singleTabListener );
updateDecorator();
}
};
/** decorates this displayer */
private BasicDockableDisplayerDecorator decorator;
/** a listener added to {@link #decorator} */
private BasicDockableDisplayerDecoratorListener decoratorListener = new BasicDockableDisplayerDecoratorListener(){
public void moveableElementChanged( BasicDockableDisplayerDecorator decorator ){
fireMoveableElementChanged();
}
};
/** the result {@link SingleTabDecider#showSingleTab(DockStation, Dockable)} returned */
private boolean singleTabShowing;
/** whether an update of the decorator is pending */
private boolean pendingForcedUpdateDecorator = false;
/** Tells whether to use a {@link DockActionDistributorSource} */
private boolean stacked = false;
/** the panel that shows the content of this displayer */
private DisplayerContentPane content;
/** notifies clients about the {@link Component}s of this displayer */
private DockComponentRootHandler rootHandler;
/**
* Creates a new displayer
* @param station the station for which this displayer is needed
*/
public BasicDockableDisplayer( DockStation station ){
this( station, null, null );
}
/**
* Creates a new displayer, sets the title and the content.
* @param station the station for which this displayer is needed
* @param dockable the content, may be <code>null</code>
* @param title the title, may be <code>null</code>
*/
public BasicDockableDisplayer( DockStation station, Dockable dockable, DockTitle title ){
this( station, dockable, title, Location.TOP );
}
/**
* Creates a new displayer, sets the title, its location and the
* content.
* @param station the station for which this displayer is needed
* @param dockable the content, may be <code>null</code>
* @param title the title of <code>dockable</code>, can be <code>null</code>
* @param location the location of the title, can be <code>null</code>
*/
public BasicDockableDisplayer( DockStation station, Dockable dockable, DockTitle title, Location location ){
super( new GridLayout( 1, 1 ), Transparency.DEFAULT );
init( station, dockable, title, location );
}
/**
* Creates a new displayer but does not set the properties of the
* displayer. Subclasses may call {@link #init(DockStation, Dockable, DockTitle, bibliothek.gui.dock.station.DockableDisplayer.Location) init}
* to initialize all variables of the new displayer.
* @param station the station for which this displayer is needed
* @param initialize <code>true</code> if all properties should be set
* to default, <code>false</code> if nothing should happen, and
* {@link #init(DockStation, Dockable, DockTitle, bibliothek.gui.dock.station.DockableDisplayer.Location) init}
* will be called.
*/
protected BasicDockableDisplayer( DockStation station, boolean initialize ){
super( new GridLayout( 1, 1 ), Transparency.DEFAULT );
if( initialize ){
init( station, null, null, Location.TOP );
}
}
/**
* Initializes all properties of this DockableDisplayer. This method should
* only be called once, by a constructor of a subclass which invoked
* <code>{@link #BasicDockableDisplayer(DockStation, boolean) DockableDisplayer( false )}</code>.
* @param station the station for which this displayer is needed
* @param dockable the content, may be <code>null</code>
* @param title the title of <code>dockable</code>, can be <code>null</code>
* @param location the location of the title, can be <code>null</code>
*/
protected void init( DockStation station, Dockable dockable, DockTitle title, Location location ){
// content.setOpaque( false );
content = createContentPane();
content.setBackground( background );
setDecorator( new MinimalDecorator() );
setBackground( background );
setTitleLocation( location );
setStation( station );
setDockable( dockable );
setTitle( title );
setFocusable( true );
setFocusCycleRoot( true );
setFocusTraversalPolicy( new DockFocusTraversalPolicy( new DisplayerFocusTraversalPolicy( this ), true ));
baseBorder = new DisplayerBorder( this, "basic.base" );
contentBorder = new DisplayerBorder( content, "basic.content" );
rootHandler = createRootHandler();
rootHandler.addRoot( getComponent() );
}
/**
* Creates the {@link DockComponentRootHandler} for this displayer. The root handler is required to inform the client
* about all the {@link Component}s that are related to this displayer.
* @return the new root handler
*/
protected DockComponentRootHandler createRootHandler(){
return new DockComponentRootHandler( this ) {
protected TraverseResult shouldTraverse( Component component ) {
// do not visit title or Dockable
DockTitle title = getTitle();
if( title != null && title.getComponent() == component ){
return TraverseResult.EXCLUDE;
}
Dockable dockable = getDockable();
if( dockable != null && dockable.getComponent() == component ){
return TraverseResult.EXCLUDE;
}
return TraverseResult.INCLUDE_CHILDREN;
}
};
}
/**
* Creates a new {@link DisplayerContentPane} which will be used to show the contents of this
* displayer.
* @return the new content pane, not <code>null</code>
*/
protected DisplayerContentPane createContentPane(){
return new DisplayerContentPane();
}
/**
* Exchanges the decorator of this displayer.
* @param decorator the new decorator
*/
protected void setDecorator( BasicDockableDisplayerDecorator decorator ){
if( decorator == null )
throw new IllegalArgumentException( "decorator must not be null" );
if( this.decorator != null ){
this.decorator.setDockable( null, null );
this.decorator.setController( null );
this.decorator.removeDecoratorListener( decoratorListener );
}
this.decorator = decorator;
this.decorator.addDecoratorListener( decoratorListener );
this.decorator.setController( controller );
resetDecorator();
if( title != null ){
title.changed( new ActionsDockTitleEvent( dockable, decorator.getActionSuggestion() ) );
}
fireMoveableElementChanged();
revalidate();
repaint();
}
/**
* Replaces the current {@link BasicDockableDisplayerDecorator decorator} if necessary.
*/
protected void updateDecorator(){
updateDecorator( false );
}
/**
* Replaces the current {@link BasicDockableDisplayerDecorator decorator} if necessary.
* @param force whether to force an update
*/
protected void updateDecorator( boolean force ){
if( force ){
pendingForcedUpdateDecorator = true;
}
if( dockable != null && station != null ){
boolean decision = decider.getValue().showSingleTab( station, dockable );
if( pendingForcedUpdateDecorator || decision != singleTabShowing ){
pendingForcedUpdateDecorator = false;
singleTabShowing = decision;
if( singleTabShowing )
setDecorator( createTabDecorator() );
else if( isStacked() )
setDecorator( createStackedDecorator() );
else
setDecorator( createMinimalDecorator() );
}
updateBorder();
}
}
/**
* Tells whether this displayer currently is showing a single tab.
* @return whether a tab is shown
*/
public boolean isSingleTabShowing(){
return singleTabShowing;
}
/**
* Tells this displayer that it is used inside a tabbed environment. This displayer will call
* {@link #createStackedDecorator()} instead of {@link #createMinimalDecorator()}.
* @param stacked whether this displayer is part of a stack of displayers
*/
public void setStacked( boolean stacked ){
if( this.stacked != stacked ){
this.stacked = stacked;
updateDecorator( true );
}
}
/**
* Tells this displayer that it is used inside a tabbed environment. This displayer will call
* {@link #createStackedDecorator()} instead of {@link #createMinimalDecorator()}.
* @return whether this displayer is part of a stack of displayers
*/
public boolean isStacked(){
return stacked;
}
/**
* Creates a new {@link MinimalDecorator} that will be shown on this displayer.
* @return the new decorator
*/
protected BasicDockableDisplayerDecorator createMinimalDecorator(){
return new MinimalDecorator();
}
/**
* Creates a new decorator that will be shown in this displayer if the displayer is
* shown alongside a tab {@link #setStacked(boolean)}. The default implementation
* return {@link #createMinimalDecorator()}. Subclasses may call {@link #createStackedDecorator(PropertyKey)}
* to easily create a fitting decorator.
* @return the new decorator
* @see #createStackedDecorator(PropertyKey)
* @see #setStacked(boolean)
*/
protected BasicDockableDisplayerDecorator createStackedDecorator(){
return createMinimalDecorator();
}
/**
* Creates a new {@link MinimalDecorator} that uses a restricted set of {@link DockAction}s.
* @param distributor the key to the filter for the actions
* @return the new decorator
*/
protected BasicDockableDisplayerDecorator createStackedDecorator( final PropertyKey<DockActionDistributor> distributor ){
return new MinimalDecorator(){
private DockActionDistributorSource source = new DockActionDistributorSource( Target.TITLE, distributor );
@Override
public void setDockable( Component content, Dockable dockable ){
super.setDockable( content, dockable );
source.setDockable( dockable );
}
@Override
public DockActionSource getActionSuggestion(){
return source;
}
};
}
/**
* Creates a new {@link TabDecorator} that will be shown on this displayer.
* @return the new decorator
*/
protected BasicDockableDisplayerDecorator createTabDecorator(){
return new TabDecorator( station, null );
}
public void setController( DockController controller ) {
rootHandler.setController( null );
this.controller = controller;
decider.setProperties( controller );
decorator.setController( controller );
background.setController( controller );
baseBorder.setController( controller );
contentBorder.setController( controller );
resetDecorator();
rootHandler.setController( controller );
}
public DockController getController() {
return controller;
}
public void setComponentConfiguration( DockComponentConfiguration configuration ) {
rootHandler.setConfiguration( configuration );
}
public DockComponentConfiguration getComponentConfiguration() {
return rootHandler.getConfiguration();
}
public void addDockableDisplayerListener( DockableDisplayerListener listener ){
listeners.add( listener );
}
public void removeDockableDisplayerListener( DockableDisplayerListener listener ){
listeners.remove( listener );
}
/**
* Gets a list of all listeners currently registered at this displayer.
* @return the list of listeners
*/
protected DockableDisplayerListener[] listeners(){
return listeners.toArray( new DockableDisplayerListener[ listeners.size() ] );
}
/**
* Calls {@link DockableDisplayerListener#moveableElementChanged(DockableDisplayer)} on any
* listener that is registered.
*/
protected void fireMoveableElementChanged(){
for( DockableDisplayerListener listener : listeners() ){
listener.moveableElementChanged( this );
}
}
public void setStation( DockStation station ) {
this.station = station;
updateDecorator();
}
public DockStation getStation() {
return station;
}
public Dockable getDockable() {
return dockable;
}
public void setDockable( Dockable dockable ) {
if( this.dockable != null ){
this.dockable.configureDisplayerHints( null );
}
hints.setShowBorderHint( null );
this.dockable = dockable;
updateDecorator();
resetDecorator();
if( dockable != null ){
this.dockable.configureDisplayerHints( hints );
}
revalidate();
}
/**
* Resets the decorator, this method removes all {@link Component}s from this displayer, then adds them again
* in the order that is necessary according to the current settings
*/
protected void resetDecorator(){
removeAll();
if( tabInside ){
if( dockable == null ){
content.setDockable( null );
decorator.setDockable( null, null );
}
else{
content.setDockable( null );
decorator.setDockable( getComponent( dockable ), dockable );
content.setDockable( decorator.getComponent() );
}
add( content );
}
else{
if( dockable == null ){
content.setDockable( null );
}
else{
content.setDockable( getComponent( dockable ) );
}
decorator.setDockable( content, dockable );
Component newComponent = decorator.getComponent();
if( newComponent != null ){
add( newComponent );
}
}
}
public Location getTitleLocation() {
return location;
}
public void setTitleLocation( Location location ) {
if( location == null )
location = Location.TOP;
this.location = location;
content.setTitleLocation( location );
if( title != null )
title.setOrientation( orientation( location ));
revalidate();
}
/**
* Determines the orientation of a {@link DockTitle} according to its
* location on this displayer.
* @param location the location on this displayer
* @return the orientation
*/
protected DockTitle.Orientation orientation( Location location ){
switch( location ){
case TOP: return DockTitle.Orientation.NORTH_SIDED;
case BOTTOM: return DockTitle.Orientation.SOUTH_SIDED;
case LEFT: return DockTitle.Orientation.WEST_SIDED;
case RIGHT: return DockTitle.Orientation.EAST_SIDED;
}
return null;
}
public DockTitle getTitle() {
return title;
}
public void setTitle( DockTitle title ) {
this.title = title;
if( title == null ){
content.setTitle( null );
}
else{
content.setTitle( getComponent( title ) );
}
if( title != null ){
title.setOrientation( orientation( location ));
if( decorator != null ){
title.changed( new ActionsDockTitleEvent( dockable, decorator.getActionSuggestion() ) );
}
}
fireMoveableElementChanged();
revalidate();
}
public DockElementRepresentative getMoveableElement(){
if( title != null ){
return title;
}
if( decorator != null ){
DockElementRepresentative result = decorator.getMoveableElement();
if( result != null ){
return result;
}
}
return getDockable();
}
public Point getTitleCenter() {
DockElementRepresentative moveable = getMoveableElement();
if( moveable == null ){
return null;
}
Component component = moveable.getComponent();
if( !SwingUtilities.isDescendingFrom( component, getComponent() )){
return null;
}
Point topLeft = new Point( 0, 0 );
topLeft = SwingUtilities.convertPoint( component, topLeft, getComponent() );
Dimension size = component.getSize();
return new Point( topLeft.x + size.width/2, topLeft.y + size.height/2 );
}
/**
* Gets the Component which should be used to layout the current
* Dockable.
* @param dockable the current Dockable, never <code>null</code>
* @return the component representing <code>dockable</code>
*/
protected Component getComponent( Dockable dockable ){
return dockable.getComponent();
}
/**
* Gets the Component which should be used to layout the current
* DockTitle.
* @param title the current DockTitle, never <code>null</code>
* @return the component representing <code>title</code>
*/
protected Component getComponent( DockTitle title ){
return title.getComponent();
}
public boolean titleContains( int x, int y ){
DockTitle title = getTitle();
if( title == null )
return false;
Component component = getComponent( title );
Point point = new Point( x, y );
point = SwingUtilities.convertPoint( this, point, component );
point.x -= component.getX();
point.y -= component.getY();
return component.contains( point );
}
public Component getComponent(){
return this;
}
public Insets getDockableInsets() {
Insets insets = getInsets();
if( insets == null )
insets = new Insets(0,0,0,0);
Insets decorator = this.decorator.getDockableInsets();
insets.left += decorator.left;
insets.right += decorator.right;
insets.top += decorator.top;
insets.bottom += decorator.bottom;
if( title == null && dockable == null )
return insets;
if( title == null ){
return insets;
}
else if( dockable != null ){
Dimension preferred = getComponent( title ).getPreferredSize();
if( location == Location.LEFT ){
insets.left += preferred.width;
}
else if( location == Location.RIGHT ){
insets.right += preferred.width;
}
else if( location == Location.BOTTOM ){
insets.bottom += preferred.height;
}
else{
insets.top += preferred.height;
}
}
return insets;
}
/**
* Gets the set of hints for displaying this component.
* @return the set of hints
*/
protected Hints getHints() {
return hints;
}
/**
* Tells this displayer whether the show border hint of
* {@link #getHints()} should be respected or not. The default value
* is <code>false</code>.
* @param respectBorderHint <code>true</code> if the hint should be respected,
* <code>false</code> if not.
*/
public void setRespectBorderHint( boolean respectBorderHint ) {
if( this.respectBorderHint != respectBorderHint ){
this.respectBorderHint = respectBorderHint;
updateBorder();
}
}
/**
* Whether the show border hint is respected by this displayer.
* @return <code>true</code> if the hint is respected
* @see #setRespectBorderHint(boolean)
*/
public boolean isRespectBorderHint() {
return respectBorderHint;
}
/**
* Sets the default value for the show border hint.
* @param defaultBorderHint the default value
*/
public void setDefaultBorderHint( boolean defaultBorderHint ) {
if( this.defaultBorderHint != defaultBorderHint ){
this.defaultBorderHint = defaultBorderHint;
updateBorder();
}
}
/**
* Gets the default value for the show border hint.
* @return the default value
*/
public boolean getDefaultBorderHint() {
return defaultBorderHint;
}
/**
* Sets whether an inner border should be shown if a single tab is in use.
* @param singleTabShowInnerBorder whether the inner border should be visible
*/
public void setSingleTabShowInnerBorder( boolean singleTabShowInnerBorder ){
this.singleTabShowInnerBorder = singleTabShowInnerBorder;
updateBorder();
}
/**
* Tells whether an inner border is shown if a single tab is in use.
* @return whether the border is shown
*/
public boolean isSingleTabShowInnerBorder(){
return singleTabShowInnerBorder;
}
/**
* Sets whether an outer border should be shown if a single tab is in use.
* @param singleTabShowOuterBorder whether the outer border should be visible
*/
public void setSingleTabShowOuterBorder( boolean singleTabShowOuterBorder ){
this.singleTabShowOuterBorder = singleTabShowOuterBorder;
updateBorder();
}
/**
* Tells whether an outer border is shown if a single tab is in use.
* @return whether the border is shown
*/
public boolean isSingleTabShowOuterBorder(){
return singleTabShowOuterBorder;
}
/**
* Tells whether the tab is shown below the title, if there is a tab and a title.
* @return the location of the tab in respect to the title, the default value is <code>false</code>
*/
public boolean isTabInside(){
return tabInside;
}
/**
* Sets the location of the tab (if present) in respect to the title (if present).
* @param tabInside <code>true</code> if the tab is to be shown nearer to the center than the title
*/
public void setTabInside( boolean tabInside ){
this.tabInside = tabInside;
resetDecorator();
}
@Override
public void updateUI(){
super.updateUI();
updateBorder();
}
/**
* Called when the hint, whether a border should be shown or not, has changed.
*/
protected void updateBorder(){
if( singleTabShowing ){
if( singleTabShowInnerBorder )
setContentBorder( getDefaultBorder() );
else
setContentBorder( null );
if( singleTabShowOuterBorder )
setBaseBorder( getDefaultBorder() );
else
setBaseBorder( null );
}
else{
setContentBorder( null );
if( respectBorderHint ){
boolean show = hints.getShowBorderHint();
if( show ){
setBaseBorder( getDefaultBorder() );
}
else{
setBaseBorder( null );
}
}
else{
if( defaultBorderHint )
setBaseBorder( getDefaultBorder() );
else
setBaseBorder( null );
}
}
}
/**
* Sets the border that wraps around the entire displayer.
* @param border the new border, can be <code>null</code>
*/
public void setBaseBorder( Border border ){
if( baseBorder != null ){
baseBorder.setBorder( border );
}
}
/**
* Sets the border that wraps around the content component.
* @param border the new border, can be <code>null</code>
*/
public void setContentBorder( Border border ){
if( contentBorder != null ){
contentBorder.setBorder( border );
}
}
public DisplayerCombinerTarget prepareCombination( CombinerSource source, Enforcement force ){
if( decorator instanceof TabDecorator ){
TabDisplayerCombinerTarget target = new TabDisplayerCombinerTarget( this, ((TabDecorator)decorator).getStackComponent(), source, force );
if( target.isValid() ){
return target;
}
}
return null;
}
/**
* Gets the default border for this displayer. That can either be
* a new object or an old border. It should not be <code>null</code>.
* The standard implementation just returns a new instance of of
* {@link BevelBorder}.
* @return the default border to be used on this displayer
*/
protected Border getDefaultBorder(){
return BorderFactory.createBevelBorder( BevelBorder.RAISED );
}
/**
* This implementation of {@link DockableDisplayerHints} forwards
* any changes to its {@link BasicDockableDisplayer}.
* @author Benjamin Sigg
*/
protected class Hints implements DockableDisplayerHints{
private Boolean border;
public DockStation getStation(){
return station;
}
public void setShowBorderHint( Boolean border ) {
if( this.border != border ){
this.border = border;
updateBorder();
}
}
/**
* Gets the hint that tells whether the border should be shown or not.
* @return whether the border should be shown
*/
public boolean getShowBorderHint() {
if( border != null )
return border.booleanValue();
return defaultBorderHint;
}
}
/**
* The background of this {@link BasicDockableDisplayer}.
* @author Benjamin Sigg
*/
private class Background extends BackgroundAlgorithm implements DisplayerBackgroundComponent{
/**
* Creates a new object
*/
public Background(){
super( DisplayerBackgroundComponent.KIND, ThemeManager.BACKGROUND_PAINT + ".displayer");
}
public Component getComponent(){
return BasicDockableDisplayer.this;
}
public DockableDisplayer getDisplayer(){
return BasicDockableDisplayer.this;
}
}
/**
* The border of this displayer.
* @author Benjamin Sigg
*/
protected class DisplayerBorder extends BorderForwarder implements DisplayerDockBorder{
/**
* Creates a new object.
* @param target the component whose border will be set
* @param idSuffix suffix for the identifier of this {@link UIValue}
*/
public DisplayerBorder( JComponent target, String idSuffix ){
super( DisplayerDockBorder.KIND, ThemeManager.BORDER_MODIFIER + ".displayer." + idSuffix, target );
}
public DockableDisplayer getDisplayer(){
return BasicDockableDisplayer.this;
}
}
}