bibliothek.gui.dock.title.AbstractDockTitle Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of docking-frames-core Show documentation
Show all versions of docking-frames-core Show documentation
${project.name} is base or core library
/*
* 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.title;
import java.awt.Color;
import java.awt.Component;
import java.awt.ContainerOrderFocusTraversalPolicy;
import java.awt.Dimension;
import java.awt.Font;
import java.awt.Graphics;
import java.awt.Insets;
import java.awt.Point;
import java.awt.Rectangle;
import java.util.ArrayList;
import java.util.List;
import javax.swing.Icon;
import javax.swing.JComponent;
import javax.swing.border.Border;
import javax.swing.event.MouseInputListener;
import bibliothek.gui.DockController;
import bibliothek.gui.Dockable;
import bibliothek.gui.dock.DockElement;
import bibliothek.gui.dock.action.ActionPopup;
import bibliothek.gui.dock.action.DockAction;
import bibliothek.gui.dock.action.DockActionSource;
import bibliothek.gui.dock.action.view.ViewTarget;
import bibliothek.gui.dock.event.DockHierarchyEvent;
import bibliothek.gui.dock.event.DockHierarchyListener;
import bibliothek.gui.dock.event.DockTitleEvent;
import bibliothek.gui.dock.event.DockableListener;
import bibliothek.gui.dock.themes.ThemeManager;
import bibliothek.gui.dock.themes.basic.action.BasicTitleViewItem;
import bibliothek.gui.dock.themes.basic.action.buttons.ButtonPanel;
import bibliothek.gui.dock.themes.border.BorderModifier;
import bibliothek.gui.dock.themes.font.TitleFont;
import bibliothek.gui.dock.util.BackgroundAlgorithm;
import bibliothek.gui.dock.util.BackgroundPanel;
import bibliothek.gui.dock.util.DockProperties;
import bibliothek.gui.dock.util.PropertyValue;
import bibliothek.gui.dock.util.UIValue;
import bibliothek.gui.dock.util.color.AbstractDockColor;
import bibliothek.gui.dock.util.color.ColorManager;
import bibliothek.gui.dock.util.font.AbstractDockFont;
import bibliothek.gui.dock.util.font.FontManager;
import bibliothek.gui.dock.util.font.FontModifier;
import bibliothek.gui.dock.util.swing.OrientedLabel;
import bibliothek.util.Condition;
import bibliothek.util.Path;
/**
* An abstract implementation of {@link DockTitle}. This title can have
* an icon, a title-text and some small buttons to display {@link DockAction actions}.
* The icon is at the top or left edge, the text in the middle, and the actions
* at the lower or the right edge of the title. If the orientation of the
* title is set to {@link DockTitle.Orientation vertical}, the text will be rotated
* by 90 degrees.
* This title has also an {@link ActionPopup} which will appear when the user
* presses the right mouse-button. The popup shows a list of all actions known
* to this title.
* The whole logic a {@link DockTitle} needs is implemented in this class,
* but subclasses may add graphical features - like a border or another
* background.
* Subclasses may override {@link #getInnerInsets()} to add a space between
* border and contents of this title.
*
* @author Benjamin Sigg
*
*/
public class AbstractDockTitle extends BackgroundPanel implements DockTitle {
/** Insets of the size 1,2,1,2 */
private static final Insets DEFAULT_INSETS_HORIZONTAL = new Insets( 0, 1, 0, 1 );
/** Insets of the size 2,1,2,1 */
private static final Insets DEFAULT_INSETS_VERTICAL = new Insets( 1, 0, 1, 0 );
/** The {@link Dockable} for which this title is shown */
private Dockable dockable;
/** A label for the title-text */
private OrientedLabel label = new OrientedLabel(){
@Override
protected void updateFonts(){
AbstractDockTitle.this.updateFonts();
}
};
/** A panel that displays the action-buttons of this title */
private ButtonPanel itemPanel;
/**
* A listener added to the owned {@link Dockable}. The listener changes the
* title-text and the icon of this title.
*/
private Listener listener = new Listener();
/** The creator of this title */
private DockTitleVersion origin;
/** true
if this title is currently selected, false
otherwise */
private boolean active = false;
/** true
if this title is currently bound to a {@link Dockable} */
private boolean bound = false;
/** Whether the layout should be horizontal or vertical */
private Orientation orientation = Orientation.FREE_HORIZONTAL;
/** The icon which is shown on this title */
private Icon icon;
/** number of pixels to paint between icon and text */
private int iconTextGap = 0;
/** the colors used by this title */
private List colors = new ArrayList();
/** the fonts used by this title */
private List fonts = new ArrayList();
/** the fonts which are used automatically */
private List conditionalFonts;
/** the background of this title */
private Background background = new Background();
/** the current border, can be null
*/
private TitleBorder border;
/** tells how to paint the text on this title */
private PropertyValue orientationConverter = new PropertyValue( DockTitle.ORIENTATION_STRATEGY ){
protected void valueChanged( OrientationToRotationStrategy oldValue, OrientationToRotationStrategy newValue ){
if( oldValue != null ){
oldValue.removeListener( orientationListener );
oldValue.uninstall( AbstractDockTitle.this );
}
if( newValue != null ){
newValue.install( AbstractDockTitle.this );
newValue.addListener( orientationListener );
}
updateLabelRotation();
}
};
/** a listener added to the current {@link OrientationToRotationStrategy} represented by {@link #orientationConverter} */
private OrientationToRotationStrategyListener orientationListener = new OrientationToRotationStrategyListener(){
public void rotationChanged( Dockable dockable, DockTitle title ){
if( title == AbstractDockTitle.this || title == null ){
if( dockable == AbstractDockTitle.this.dockable || dockable == null ){
updateLabelRotation();
}
}
}
};
/**
* Constructs a new title
* @param dockable the Dockable which is the owner of this title
* @param origin the version which was used to create this title
*/
public AbstractDockTitle( Dockable dockable, DockTitleVersion origin ){
this( dockable, origin, true );
}
/**
* Standard constructor
* @param dockable The Dockable whose title this will be
* @param origin The version which was used to create this title
* @param showMiniButtons true
if the actions of the Dockable
* should be shown, false
if they should not be visible
*/
public AbstractDockTitle( Dockable dockable, DockTitleVersion origin, boolean showMiniButtons ){
super( true, false );
init( dockable, origin, showMiniButtons );
}
/**
* Constructor which does not do anything. Subclasses should call
* {@link #init(Dockable, DockTitleVersion, boolean)} to initialize
* the title.
*/
protected AbstractDockTitle(){
super( true, false );
}
/**
* Initializer called by the constructor.
* @param dockable The Dockable whose title this will be
* @param origin The version which was used to create this title
* @param showMiniButtons true
if the actions of the Dockable
* should be shown, false
if they should not be visible
*/
protected void init( Dockable dockable, DockTitleVersion origin, boolean showMiniButtons ){
this.dockable = dockable;
// this.showMiniButtons = showMiniButtons;
this.origin = origin;
label.setBackground( background );
setBackground( background );
setLayout( null );
add( label );
setActive( false );
//
// if( showMiniButtons ){
// itemPanel = new ButtonPanel( true ){
// @Override
// protected BasicTitleViewItem createItemFor( DockAction action, Dockable dockable ){
// return AbstractDockTitle.this.createItemFor( action, dockable );
// }
// };
// itemPanel.setOpaque( false );
// add( itemPanel );
// }
//
setFocusTraversalPolicyProvider( true );
setFocusTraversalPolicy( new ContainerOrderFocusTraversalPolicy(){
@Override
protected boolean accept( Component component ) {
return component != AbstractDockTitle.this && super.accept( component );
}
});
setOpaque( false );
setShowMiniButtons( showMiniButtons );
}
/**
* Tells whether this titel is able to show any {@link DockAction}.
* @return true
if {@link DockAction}s are enabled
* @see #setShowMiniButtons(boolean)
*/
public boolean isShowMiniButtons(){
return itemPanel != null;
}
/**
* Enables or disables {@link DockAction}s for this title.
* @param showMiniButtons whether to show actions or not
*/
public void setShowMiniButtons( boolean showMiniButtons ){
if( showMiniButtons ){
if( itemPanel == null ){
itemPanel = new ButtonPanel( true ){
@Override
protected BasicTitleViewItem createItemFor( DockAction action, Dockable dockable ){
return AbstractDockTitle.this.createItemFor( action, dockable );
}
};
itemPanel.setOpaque( false );
itemPanel.setOrientation( getOrientation() );
itemPanel.setToolTipText( getToolTipText() );
add( itemPanel );
if( isBound() ){
itemPanel.set( getDockable(), getActionSourceFor( getDockable() ) );
}
}
}
else{
if( itemPanel != null ){
itemPanel.set( null );
remove( itemPanel );
}
}
}
/**
* Sets the number of pixels to paint between icon and text.
* @param iconTextGap the number of pixels to paint
*/
public void setIconTextGap( int iconTextGap ){
this.iconTextGap = iconTextGap;
revalidate();
}
/**
* Gets the number of pixels to paint between icon and text
* @return the number of pixels
*/
public int getIconTextGap(){
return iconTextGap;
}
/**
* Adds a color to the list of colors, this title will ensure that
* color
gets connected to a {@link ColorManager} as soon
* as this title is bound.
* @param color the new color
*/
protected void addColor( AbstractDockColor color ){
colors.add( color );
if( bound ){
color.connect( getDockable().getController() );
}
}
/**
* Removes a color from this title
* @param color the color to remove
*/
protected void removeColor( AbstractDockColor color ){
colors.remove( color );
color.connect( null );
}
/**
* Adds a font to the list of fonts, this title will ensure that
* font
gets connected to a {@link FontManager} as soon
* as this title is bound.
* @param font the new font
*/
protected void addFont( AbstractDockFont font ){
fonts.add( font );
if( bound ){
font.connect( getDockable().getController() );
}
}
/**
* Removes a font from this title.
* @param font the font to remove
*/
protected void removeFont( AbstractDockFont font ){
fonts.remove( font );
font.connect( null );
}
/**
* Adds a new conditional font to this title, the conditional font will
* be applied to {@link #setFont(Font)} when its condition
* is met. If there is more than one font whose condition is met, then the
* first one that was registered is used.
* @param id the id of the font which is to be used
* @param kind what kind of title this is
* @param condition the condition to met
* @param backup to be used when there is not font set in the {@link FontManager}
*/
protected void addConditionalFont( String id, Path kind, Condition condition, FontModifier backup ){
ConditionalFont font = new ConditionalFont( id, kind, condition, backup );
addFont( font );
if( conditionalFonts == null )
conditionalFonts = new ArrayList();
conditionalFonts.add( font );
updateFonts();
}
/**
* Removes all fonts which were set using {@link #addConditionalFont(String, Path, Condition, FontModifier)}
*/
protected void removeAllConditionalFonts(){
if( conditionalFonts != null ){
for( ConditionalFont font : conditionalFonts ){
removeFont( font );
}
conditionalFonts = null;
updateFonts();
}
}
/**
* Gets the location and the size of the icon.
* @return the bounds or null
if no icon is registered
*/
public Rectangle getIconBounds(){
if( icon == null )
return null;
Insets insets = titleInsets();
if( orientation.isVertical() ){
int width = getWidth() - insets.left - insets.right;
return new Rectangle( insets.left + (width - icon.getIconWidth())/2, insets.top, icon.getIconWidth(), icon.getIconHeight() );
}
else{
int height = getHeight() - insets.top - insets.bottom;
return new Rectangle( insets.left, insets.top + (height - icon.getIconHeight()) / 2, icon.getIconWidth(), icon.getIconHeight() );
}
}
@Override
public void paintBackground( Graphics g ){
paintBackground( g, this );
}
/**
* Paints the whole background of this title. The default implementation
* just fills the background with the background color of component
.
* @param g the graphics context used to paint
* @param component the {@link Component} which represents this title
*/
protected void paintBackground( Graphics g, JComponent component ){
g.setColor( component.getBackground() );
g.fillRect( 0, 0, component.getWidth(), component.getHeight() );
}
@Override
public void paintForeground( Graphics g ){
paintForeground( g, this );
}
/**
* Paints the whole foreground of this title. The default implementation only paints an icon.
* @param g the graphics context to use
* @param component the {@link Component} which represents this title
*/
protected void paintForeground( Graphics g, JComponent component ){
if( icon != null ){
Insets insets = titleInsets();
if( orientation.isVertical() ){
int width = getWidth() - insets.left - insets.right;
icon.paintIcon( this, g, insets.left + (width - icon.getIconWidth())/2, insets.top );
}
else{
int height = getHeight() - insets.top - insets.bottom;
icon.paintIcon( this, g, insets.left,
insets.top + (height - icon.getIconHeight()) / 2 );
}
}
}
/**
* Sets the icon of this title. The icon is shown on the top or the left
* edge.
* @param icon the icon, can be null
*/
protected void setIcon( Icon icon ){
this.icon = icon;
revalidate();
repaint();
}
/**
* Gets the icon of this title.
* @return the icon or null
* @see #setIcon(Icon)
*/
protected Icon getIcon(){
return icon;
}
/**
* Sets the text of this title. The text either painted horizontally or
* vertically.
* @param text the text or null
*/
protected void setText( String text ){
label.setText( text );
repaint();
}
/**
* Gets the text which is shown on this title.
* @return the text
*/
protected String getText(){
return label.getText();
}
/**
* Sets the tooltip that will be shown on this title.
* @param text the new tooltip, can be null
*/
protected void setTooltip( String text ){
setToolTipText( text );
label.setToolTipText( text );
if( itemPanel != null )
itemPanel.setToolTipText( text );
}
public void setOrientation( Orientation orientation ) {
this.orientation = orientation;
if( itemPanel != null ){
itemPanel.setOrientation( orientation );
}
updateLabelRotation();
revalidate();
}
private void updateLabelRotation(){
label.setRotation( orientationConverter.getValue().convert( getOrientation(), this ));
}
/**
* Gets the current orientation.
* @return the orientation
* @see #setOrientation(bibliothek.gui.dock.title.DockTitle.Orientation)
*/
public Orientation getOrientation() {
return orientation;
}
public DockTitleVersion getOrigin() {
return origin;
}
@Override
public void setForeground( Color fg ) {
super.setForeground( fg );
if( label != null )
label.setForeground( fg );
}
@Override
public void setBackground( Color fg ) {
super.setBackground( fg );
if( label != null )
label.setBackground( fg );
}
@Override
public void setFont( Font font ) {
super.setFont( font );
if( label != null )
label.setFont( font );
}
public void setFontModifier( FontModifier modifier ) {
label.setFontModifier( modifier );
}
@Override
public Dimension getMinimumSize() {
if( icon != null )
return new Dimension( icon.getIconWidth(), icon.getIconHeight() );
Dimension preferred = getPreferredSize();
int min = Math.min( preferred.width, preferred.height );
return new Dimension( min, min );
}
/**
* Sets the border and the {@link BorderModifier} that should be used by this title.
* @param key the identifier of the modifier or null
* @param border the default title, can be null
*/
public void setBorder( String key, Border border ){
if( this.border != null ){
if( key == null || !this.border.id.equals( key )){
this.border.setController( null );
this.border = null;
}
}
if( this.border == null && key != null ){
this.border = new TitleBorder( key );
if( bound ){
this.border.setController( getOrigin().getController() );
}
}
if( this.border == null ){
setBorder( border );
}
else{
this.border.setBorder( border );
}
}
/**
* Gets the insets that have to be applied between the border and the
* content (icon, text, actions) of this title. Subclasses may use this method to
* create free space in which they can paint additional items.
* @return the insets, not null
*/
protected Insets getInnerInsets(){
if( getOrientation().isHorizontal() )
return DEFAULT_INSETS_HORIZONTAL;
else
return DEFAULT_INSETS_VERTICAL;
}
private Insets titleInsets(){
Insets insets = getInsets();
if( insets == null ){
return getInnerInsets();
}
else{
insets = new Insets( insets.top, insets.left, insets.bottom, insets.right );
}
Insets inner = getInnerInsets();
insets.top += inner.top;
insets.bottom += inner.bottom;
insets.left += inner.left;
insets.right += inner.right;
return insets;
}
@Override
public void doLayout(){
super.doLayout();
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;
Dimension labelPreferred;
String text = getText();
if( text == null || text.length() == 0 ){
labelPreferred = new Dimension( 5, 5 );
}
else{
labelPreferred = label.getPreferredSize();
}
if( orientation.isHorizontal() ){
if( icon != null ){
x += icon.getIconWidth() + iconTextGap;
width -= icon.getIconWidth() + iconTextGap;
}
if( itemPanel != null && itemPanel.getItemCount() > 0 ){
Dimension[] buttonPreferred = itemPanel.getPreferredSizes();
int remaining = width - labelPreferred.width;
int count = buttonPreferred.length-1;
while( count > 0 && buttonPreferred[count].width > remaining )
count--;
itemPanel.setVisibleActions( count );
int buttonWidth = buttonPreferred[count].width;
int buttonX = width - buttonWidth;
label.setBounds( x, y, buttonX, height );
itemPanel.setBounds( x + buttonX, y, width - buttonX, height );
}
else
label.setBounds( x, y, width, height );
}
else{
if( icon != null ){
y += icon.getIconWidth() + iconTextGap;
height -= icon.getIconWidth() + iconTextGap;
}
if( itemPanel != null && itemPanel.getItemCount() > 0 ){
Dimension[] buttonPreferred = itemPanel.getPreferredSizes();
int remaining = height - labelPreferred.height;
int count = buttonPreferred.length-1;
while( count > 0 && buttonPreferred[count].height > remaining )
count--;
itemPanel.setVisibleActions( count );
int buttonHeight = buttonPreferred[count].height;
int buttonY = height - buttonHeight;
label.setBounds( x, y, width, buttonY );
itemPanel.setBounds( x, y + buttonY, width, height - buttonY );
}
else
label.setBounds( x, y, width, height );
}
}
public Component getComponent() {
return this;
}
public void addMouseInputListener( MouseInputListener listener ) {
addMouseListener( listener );
addMouseMotionListener( listener );
label.addMouseListener( listener );
label.addMouseMotionListener( listener );
}
public void removeMouseInputListener( MouseInputListener listener ) {
removeMouseListener( listener );
removeMouseMotionListener( listener );
label.removeMouseListener( listener );
label.removeMouseMotionListener( listener );
}
public Point getPopupLocation( Point click, boolean popupTrigger ){
if( popupTrigger )
return click;
boolean restrained = getText() == null || getText().length() == 0;
Rectangle icon = getIconBounds();
if( icon != null ){
if( icon.contains( click )){
if( restrained ){
// icon must not be the whole title
int size = getWidth() * getHeight();
if( itemPanel != null )
size -= itemPanel.getWidth() * itemPanel.getHeight();
if( size <= 2 * icon.width * icon.height )
return null;
}
if( getOrientation().isHorizontal() )
return new Point( icon.x, icon.y + icon.height );
else
return new Point( icon.x + icon.width, icon.y );
}
}
return null;
}
public Dockable getDockable() {
return dockable;
}
public DockElement getElement() {
return getDockable();
}
public boolean isUsedAsTitle() {
return true;
}
public boolean shouldTransfersFocus(){
return true;
}
public boolean shouldFocus(){
return true;
}
/**
* Sets whether this title should be painted as focused or not.
* @param active true
if the {@link Dockable} of this title
* has the focus.
*/
public void setActive( boolean active ) {
this.active = active;
}
public void changed( DockTitleEvent event ) {
setActive( event.isActive() );
}
public boolean isActive(){
return active;
}
@Override
public Dimension getPreferredSize() {
Dimension preferred;
if( (getText() == null || getText().length() == 0 ) ){
preferred = new Dimension( 5, 5 );
}
else{
preferred = label.getPreferredSize();
}
Insets insets = titleInsets();
if( orientation.isHorizontal() ){
int width = 0;
int height = 0;
if( icon != null ){
width = icon.getIconWidth();
height = icon.getIconHeight();
}
height = Math.max( height, preferred.height );
width += preferred.width;
if( itemPanel != null ){
Dimension items = itemPanel.getPreferredSize();
height = Math.max( height, items.height );
width += items.width;
}
if( icon == null )
width = Math.max( width, 2*height );
preferred = new Dimension( width + iconTextGap + insets.left + insets.right,
height + insets.top + insets.bottom );
}
else{
int width = 0;
int height = 0;
if( icon != null ){
width = icon.getIconWidth();
height = icon.getIconHeight();
}
width = Math.max( width, preferred.width );
height += preferred.height;
if( itemPanel != null ){
Dimension items = itemPanel.getPreferredSize();
width = Math.max( width, items.width );
height += items.height;
}
if( icon == null )
height = Math.max( height, 2*width );
preferred = new Dimension( width + insets.left + insets.right,
height + iconTextGap + insets.top + insets.bottom );
}
if( preferred.width < 10 )
preferred.width = 10;
if( preferred.height < 10 )
preferred.height = 10;
return preferred;
}
/**
* Creates a new item for action
which will be shown on this title.
* @param action The action which will be triggered by the button
* @param dockable The {@link Dockable} which will be affected by the action
* @return the new graphical representation of the action
*/
protected BasicTitleViewItem createItemFor( DockAction action, Dockable dockable ){
return dockable.getController().getActionViewConverter().createView(
action, ViewTarget.TITLE, dockable );
}
/**
* Gets a list of all actions which will be shown on this title.
* @param dockable the owner of the actions
* @return the list of actions
*/
protected DockActionSource getActionSourceFor( Dockable dockable ){
return dockable.getGlobalActionOffers();
}
public void bind() {
if( bound )
throw new IllegalArgumentException( "Do not call bound twice!" );
bound = true;
if( itemPanel != null ){
itemPanel.set( dockable, getActionSourceFor( dockable ) );
}
dockable.addDockableListener( listener );
DockController controller = getDockable().getController();
if( controller != null ){
for( AbstractDockColor color : colors )
color.connect( controller );
for( AbstractDockFont font : fonts )
font.connect( controller );
orientationConverter.setProperties( controller );
}
background.setController( controller );
if( border != null ){
border.setController( controller );
}
updateText();
updateIcon();
updateTooltip();
revalidate();
}
public void unbind() {
if( !bound )
throw new IllegalArgumentException( "Do not call unbind twice" );
bound = false;
dockable.removeDockableListener( listener );
if( itemPanel != null ){
itemPanel.set( null );
}
for( AbstractDockColor color : colors )
color.connect( null );
for( AbstractDockFont font : fonts )
font.connect( null );
orientationConverter.setProperties( (DockProperties)null );
if( border != null ){
border.setController( null );
}
setText( "" );
setIcon( null );
setTooltip( null );
background.setController( null );
}
/**
* Called when the icon of this title should be updated. This title
* never calls {@link #setIcon(Icon)} directly, it always calls this method
* which then calls {@link #setIcon(Icon)} (the only exception: on
* unbinding the icon is set to null
)
*/
protected void updateIcon(){
setIcon( dockable.getTitleIcon() );
}
/**
* Called when the text of this title should be updated. This title
* never calls {@link #setText(String)} directly, it always calls this method
* which then calls {@link #setText(String)} (the only exception: on
* unbinding the text is set to null
)
*/
protected void updateText(){
setText( dockable.getTitleText() );
}
/**
* Called when the tooltip of this title should be updated. This
* title never calls {@link #setTooltip(String)} directly, it always
* calls this method which then calls {@link #setTooltip(String)} (the
* only exception: on unbinding the tooltip is set to null
)
*/
protected void updateTooltip(){
setTooltip( dockable.getTitleToolTip() );
}
/**
* Tells whether this title is bound to a {@link Dockable} or not.
* @return true if the title is {@link #bind() bound}, false
* {@link #unbind() otherwise}
*/
public boolean isBound(){
return bound;
}
/**
* Checks the state of this title and may replace the font of the title.
*/
protected void updateFonts(){
if( conditionalFonts != null ){
FontModifier modifier = null;
for( ConditionalFont font : conditionalFonts ){
if( font.getState() ){
modifier = font.value();
break;
}
}
setFontModifier( modifier );
}
}
/**
* A font that is only used when a condition is met.
* @author Benjamin Sigg
*/
private class ConditionalFont extends TitleFont{
private Condition condition;
public ConditionalFont( String id, Path kind, Condition condition, FontModifier backup ){
super( id, AbstractDockTitle.this, kind, backup );
this.condition = condition;
}
/**
* Gets whether the condition is met or not.
* @return true
if this font should be used
*/
public boolean getState(){
return condition.getState();
}
@Override
protected void changed( FontModifier oldValue, FontModifier newValue ) {
updateFonts();
}
}
/**
* A listener to the {@link Dockable} of this title.
* @author Benjamin Sigg
*/
private class Listener implements DockableListener, DockHierarchyListener{
public void titleIconChanged( Dockable dockable, Icon oldIcon, Icon newIcon ) {
updateIcon();
updateText();
}
public void titleTextChanged( Dockable dockable, String oldTitle, String newTitle ) {
updateIcon();
updateText();
}
public void titleToolTipChanged( Dockable dockable, String oldTooltip, String newTooltip ) {
updateTooltip();
}
public void titleUnbound( Dockable dockable, DockTitle title ) {
// do nothing
}
public void titleBound( Dockable dockable, DockTitle title ) {
// do nothing
}
public void titleExchanged( Dockable dockable, DockTitle title ) {
// do nothing
}
public void controllerChanged( DockHierarchyEvent event ) {
DockController controller = event.getDockable().getController();
for( AbstractDockColor color : colors )
color.connect( controller );
}
public void hierarchyChanged( DockHierarchyEvent event ) {
// do nothing
}
}
/**
* Represents the background of this {@link DockTitle}.
* @author Benjamin Sigg
*/
private class Background extends BackgroundAlgorithm implements DockTitleBackgroundComponent{
public Background(){
super( DockTitleBackgroundComponent.KIND, ThemeManager.BACKGROUND_PAINT + ".title" );
}
public DockTitle getTitle(){
return AbstractDockTitle.this;
}
public Component getComponent(){
return getTitle().getComponent();
}
}
/**
* Represents this title as {@link UIValue} to get a {@link BorderModifier}
* @author Benjamin Sigg
*/
private class TitleBorder implements TitleDockBorder{
/** the identifier of this border */
private String id;
/** the current modifier */
private BorderModifier modifier;
/** the source of all values */
private DockController controller;
/** the default border */
private Border border;
/**
* Creates a new wrapper
* @param id the identifier of this {@link UIValue}
*/
public TitleBorder( String id ){
this.id = id;
}
public DockTitle getTitle(){
return AbstractDockTitle.this;
}
public void set( BorderModifier value ){
if( value != modifier ){
modifier = value;
update();
}
}
/**
* Sets the default border
* @param border the default border, can be null
*/
public void setBorder( Border border ){
if( this.border != border ){
this.border = border;
update();
}
}
private void update(){
if( modifier == null ){
AbstractDockTitle.this.setBorder( border );
}
else{
AbstractDockTitle.this.setBorder( modifier.modify( border ) );
}
}
/**
* Sets the controller to observe for a value.
* @param controller the controller, can be null
*/
public void setController( DockController controller ){
if( this.controller != null ){
this.controller.getThemeManager().remove( this );
}
this.controller = controller;
if( this.controller == null ){
set( null );
}
else{
this.controller.getThemeManager().add( id, TitleDockBorder.KIND, ThemeManager.BORDER_MODIFIER_TYPE, this );
}
}
}
}