/* * 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 * benjamin_sigg@gmx.ch * CH - Switzerland */ package bibliothek.gui.dock.themes; import javax.swing.LookAndFeel; import javax.swing.SwingUtilities; import bibliothek.gui.DockController; import bibliothek.gui.DockStation; import bibliothek.gui.DockTheme; import bibliothek.gui.Dockable; import bibliothek.gui.dock.StackDockStation; import bibliothek.gui.dock.dockable.DockableMovingImageFactory; import bibliothek.gui.dock.event.UIListener; import bibliothek.gui.dock.focus.DockableSelection; import bibliothek.gui.dock.station.Combiner; import bibliothek.gui.dock.station.DisplayerFactory; import bibliothek.gui.dock.station.DockableDisplayer; import bibliothek.gui.dock.station.StationPaint; import bibliothek.gui.dock.station.span.Span; import bibliothek.gui.dock.station.span.SpanFactory; import bibliothek.gui.dock.station.stack.StackDockComponent; import bibliothek.gui.dock.station.stack.StackDockComponentFactory; import bibliothek.gui.dock.station.stack.StackDockComponentParent; import bibliothek.gui.dock.station.stack.tab.layouting.TabPlacement; import bibliothek.gui.dock.themes.basic.BasicColorScheme; import bibliothek.gui.dock.themes.basic.BasicCombiner; import bibliothek.gui.dock.themes.basic.BasicDisplayerFactory; import bibliothek.gui.dock.themes.basic.BasicDockTitleFactory; import bibliothek.gui.dock.themes.basic.BasicDockableSelection; import bibliothek.gui.dock.themes.basic.BasicMovingImageFactory; import bibliothek.gui.dock.themes.basic.BasicSpanFactory; import bibliothek.gui.dock.themes.basic.BasicStackDockComponent; import bibliothek.gui.dock.themes.basic.BasicStationPaint; import bibliothek.gui.dock.themes.color.ExtendingColorScheme; import bibliothek.gui.dock.title.DockTitle; import bibliothek.gui.dock.title.DockTitleFactory; import bibliothek.gui.dock.title.DockTitleManager; import bibliothek.gui.dock.util.DockProperties; import bibliothek.gui.dock.util.NullPriorityValue; import bibliothek.gui.dock.util.Priority; import bibliothek.gui.dock.util.PropertyKey; import bibliothek.gui.dock.util.PropertyValue; import bibliothek.gui.dock.util.color.ColorManager; import bibliothek.gui.dock.util.property.DynamicPropertyFactory; /** * A {@link DockTheme theme} that does not install anything and uses the * default-implementations off all factories. It is possible to replace * any of the factories. * @author Benjamin Sigg */ @ThemeProperties( nameBundle="theme.basic", descriptionBundle="theme.basic.description", authors={"Benjamin Sigg"}, webpages={}) public class BasicTheme implements DockTheme{ /** combines several Dockables */ private NullPriorityValue<Combiner> combiner = new NullPriorityValue<Combiner>(); /** paints on stations */ private NullPriorityValue<StationPaint> paint = new NullPriorityValue<StationPaint>(); /** creates panels for Dockables */ private NullPriorityValue<DisplayerFactory> displayerFactory = new NullPriorityValue<DisplayerFactory>(); /** creates titles Dockables */ private NullPriorityValue<DockTitleFactory> titleFactory = new NullPriorityValue<DockTitleFactory>(); /** selects the image which should be displayed when moving a dockable*/ private NullPriorityValue<DockableMovingImageFactory> movingImage = new NullPriorityValue<DockableMovingImageFactory>(); /** the factory used to create components for {@link StackDockStation} */ private NullPriorityValue<StackDockComponentFactory> stackDockComponentFactory = new NullPriorityValue<StackDockComponentFactory>(); /** the side at which tabs are normally shown */ private NullPriorityValue<TabPlacement> tabPlacement = new NullPriorityValue<TabPlacement>(); /** how spans are created */ private NullPriorityValue<SpanFactory> spanFactory = new NullPriorityValue<SpanFactory>(); /** extensions used by this theme */ private DockThemeExtension[] extensions; /** the key to set the {@link ColorScheme} of this theme */ public static final PropertyKey<ColorScheme> BASIC_COLOR_SCHEME = new PropertyKey<ColorScheme>( "dock.ui.BasicTheme.ColorScheme", new DynamicPropertyFactory<ColorScheme>(){ public ColorScheme getDefault( PropertyKey<ColorScheme> key, DockProperties properties ){ return new BasicColorScheme(); } }, true ); /** the color scheme used in this theme */ private PropertyValue<ColorScheme> colorScheme = new PropertyValue<ColorScheme>( BASIC_COLOR_SCHEME ){ @Override protected void valueChanged( ColorScheme oldValue, ColorScheme newValue ) { updateColors(); } }; /** how to select a new focused dockable */ private NullPriorityValue< DockableSelection> selection = new NullPriorityValue<DockableSelection>(); /** the controller which is installed */ private DockController controller; /** a listener waiting for changed {@link LookAndFeel}s */ private UIListener uiListener = new UIListener(){ public void updateUI( DockController controller ){ BasicTheme.this.updateUI(); } public void themeChanged(DockController controller, DockTheme oldTheme, DockTheme newTheme) { // ignore } public void themeWillChange(DockController controller, DockTheme oldTheme, DockTheme newTheme) { // ignore } }; /** * Creates a new <code>BasicTheme</code>. */ public BasicTheme() { setCombiner( new BasicCombiner(), Priority.DEFAULT ); setPaint( new BasicStationPaint(), Priority.DEFAULT ); setDisplayerFactory( new BasicDisplayerFactory(), Priority.DEFAULT ); setTitleFactory( new BasicDockTitleFactory(), Priority.DEFAULT ); setMovingImageFactory( new BasicMovingImageFactory(), Priority.DEFAULT ); setStackDockComponentFactory( new StackDockComponentFactory(){ public StackDockComponent create( StackDockComponentParent station ) { return new BasicStackDockComponent( station ); } }, Priority.DEFAULT ); setDockableSelection( new BasicDockableSelection(), Priority.DEFAULT ); setTabPlacement( TabPlacement.BOTTOM_OF_DOCKABLE, Priority.DEFAULT ); setSpanFactory( new BasicSpanFactory( 250, 250 ), Priority.DEFAULT ); } public void install( DockController controller, DockThemeExtension[] extensions ){ this.extensions = extensions; for( DockThemeExtension extension : extensions ){ extension.install( controller, this ); } install( controller ); for( DockThemeExtension extension : extensions ){ extension.installed( controller, this ); } } /** * Installs the basic items of this theme, ignoring any {@link DockThemeExtension}. * @param controller the new owner of this theme */ protected void install( DockController controller ){ if( this.controller != null ) throw new IllegalStateException( "Theme is already in use" ); this.controller = controller; controller.getThemeManager().addUIListener( uiListener ); updateUI(); controller.getProperties().set( StackDockStation.COMPONENT_FACTORY, stackDockComponentFactory.get(), Priority.THEME ); controller.getProperties().set( StackDockStation.TAB_PLACEMENT, tabPlacement.get(), Priority.THEME ); controller.getProperties().set( DockTheme.SPAN_FACTORY, spanFactory.get(), Priority.THEME ); colorScheme.setProperties( controller ); updateColors(); } public void uninstall( DockController controller ){ if( this.controller != controller ) throw new IllegalArgumentException( "Trying to uninstall a controller which is not installed" ); controller.getProperties().unset( StackDockStation.COMPONENT_FACTORY, Priority.THEME ); controller.getProperties().unset( StackDockStation.TAB_PLACEMENT, Priority.THEME ); controller.getProperties().unset( DockTheme.SPAN_FACTORY, Priority.THEME ); controller.getColors().clear( Priority.THEME ); controller.getThemeManager().removeUIListener( uiListener ); colorScheme.setProperties( (DockProperties)null ); for( DockThemeExtension extension : extensions ){ extension.uninstall( controller, this ); } this.controller = null; } /** * Called when the {@link LookAndFeel} changed, should update colors, fonts, ... */ public void updateUI(){ if( selection != null ){ SwingUtilities.updateComponentTreeUI( selection.get().getComponent() ); } } /** * Called when the the colors of the {@link ColorManager} have to be updated. This method reads * the current {@link ColorScheme} and installs it using * {@link ColorManager#setScheme(Priority, bibliothek.gui.dock.util.UIScheme)} with a priority * of {@link Priority#CLIENT}.<br> * This method changed its behavior in version 1.1.0p3, subclasses no longer need to override it. All colors * can now be created lazily and automatically in exactly the moment when they are needed. */ protected void updateColors(){ if( controller != null ){ ColorScheme scheme = colorScheme.getValue(); if( scheme != null ){ scheme = new ExtendingColorScheme( scheme, controller ); } controller.getColors().setScheme( Priority.THEME, scheme ); } } /** * Gets the currently installed controller * @return the controller */ public DockController getController(){ return controller; } /** * Sets the key that will be used to read the {@link ColorScheme} of this * theme from the {@link DockProperties}. * @param key the new key, not <code>null</code> * @see #setColorScheme(ColorScheme) */ protected void setColorSchemeKey( PropertyKey<ColorScheme> key ){ if( key == null ) throw new IllegalArgumentException( "key must not be null" ); colorScheme.setKey( key ); } /** * Sets the currently used set of colors. The colors of all {@link DockController}s * will change immediately. * @param colorScheme the new scheme, <code>null</code> will * activate the default color scheme. */ public void setColorScheme( ColorScheme colorScheme ) { this.colorScheme.setValue( colorScheme ); } /** * Gets the currently used color scheme * @return the scheme */ public ColorScheme getColorScheme() { return colorScheme.getValue(); } /** * Sets the factory which will be used to create components for * {@link StackDockStation}. Note that this property has to be set * before the theme is installed. Otherwise it will take no effect. * @param stackDockComponentFactory the factory or <code>null</code> */ public void setStackDockComponentFactory( StackDockComponentFactory stackDockComponentFactory ) { setStackDockComponentFactory( stackDockComponentFactory, Priority.CLIENT ); } /** * Sets the factory which will be used to create components for * {@link StackDockStation}. Note that this property has to be set * before the theme is installed. Otherwise it will take no effect. * @param stackDockComponentFactory the factory or <code>null</code> * @param priority the importance of the new setting (whether it should override existing settings or not). */ public void setStackDockComponentFactory( StackDockComponentFactory stackDockComponentFactory, Priority priority ) { this.stackDockComponentFactory.set( priority, stackDockComponentFactory ); } /** * Sets the factory which will be used to create new {@link Span}s. Note that this property * has to be set before the theme is installed, otherwise it will take not effect. * @param factory the new factory, can be <code>null</code> */ public void setSpanFactory( SpanFactory factory ){ setSpanFactory( factory, Priority.CLIENT ); } /** * Sets the factory which will be used to create new {@link Span}s. Note that this property * has to be set before the theme is installed. Otherwise it will take no effect. * @param factory the factory or <code>null</code> * @param priority the importance of the new setting (whether it should override existing settings or not). */ public void setSpanFactory( SpanFactory factory, Priority priority ){ this.spanFactory.set( priority, factory ); } /** * Sets the movingImage-property. The movingImage is needed to show an * image when the user grabs a {@link Dockable} * @param movingImage the new factory */ public void setMovingImageFactory( DockableMovingImageFactory movingImage ) { setMovingImageFactory( movingImage, Priority.CLIENT ); } /** * Sets the movingImage-property. The movingImage is needed to show an * image when the user grabs a {@link Dockable} * @param movingImage the new factory * @param priority the importance of the new setting (whether it should override existing settings or not). */ public void setMovingImageFactory( DockableMovingImageFactory movingImage, Priority priority ) { this.movingImage.set( priority, movingImage ); } /** * Sets the {@link Combiner} of this theme. The combiner is used to * merge two Dockables. * @param combiner the combiner */ public void setCombiner( Combiner combiner ) { setCombiner( combiner, Priority.CLIENT ); } /** * Sets the {@link Combiner} of this theme. The combiner is used to * merge two Dockables. * @param combiner the combiner * @param priority the importance of the new setting (whether it should override existing settings or not). */ public void setCombiner( Combiner combiner, Priority priority ) { this.combiner.set( priority, combiner ); } /** * Sets the {@link StationPaint} of this theme. The paint is used to * draw markings on stations. * @param paint the paint */ public void setPaint( StationPaint paint ) { setPaint( paint, Priority.CLIENT ); } /** * Sets the {@link StationPaint} of this theme. The paint is used to * draw markings on stations. * @param paint the paint * @param priority the importance of the new setting (whether it should override existing settings or not). */ public void setPaint( StationPaint paint, Priority priority ) { this.paint.set( priority, paint ); } /** * Sets the {@link DisplayerFactory} of this theme. The factory is needed * to create {@link DockableDisplayer}. * @param factory the factory */ public void setDisplayerFactory( DisplayerFactory factory ) { setDisplayerFactory( factory, Priority.CLIENT ); } /** * Sets the {@link DisplayerFactory} of this theme. The factory is needed * to create {@link DockableDisplayer}. * @param factory the factory * @param priority the importance of the new setting (whether it should override existing settings or not). */ public void setDisplayerFactory( DisplayerFactory factory, Priority priority ) { displayerFactory.set( priority, factory ); } /** * Sets the {@link DockTitleFactory} of this theme. The factory is * used to create {@link DockTitle DockTitles} for some Dockables. * @param titleFactory the factory */ public void setTitleFactory( DockTitleFactory titleFactory ) { setTitleFactory( titleFactory, Priority.CLIENT ); } /** * Sets the {@link DockTitleFactory} of this station. The factory is * used to create {@link DockTitle DockTitles} for some Dockables. * @param titleFactory the factory * @param priority the importance of the new setting (whether it should override existing settings or not). */ public void setTitleFactory( DockTitleFactory titleFactory, Priority priority ) { this.titleFactory.set( priority, titleFactory ); if( controller != null ){ controller.getDockTitleManager().registerTheme( DockTitleManager.THEME_FACTORY_ID, this.titleFactory.get() ); } } /** * Sets how the user can select the focused {@link Dockable}. * @param selection the new selector */ public void setDockableSelection( DockableSelection selection ){ setDockableSelection( selection, Priority.CLIENT ); } /** * Sets how the user can select the focused {@link Dockable}. * @param selection the new selector * @param priority the importance of the new setting (whether it should override existing settings or not). */ public void setDockableSelection( DockableSelection selection, Priority priority ){ this.selection.set( priority, selection ); } /** * Sets the side at which tabs are to be displayed. This method has to * be called before a {@link DockController} is installed, otherwise the * settings has no effect. * @param tabPlacement the side at which to show tabs, may be <code>null</code> to * use the default value */ public void setTabPlacement( TabPlacement tabPlacement ){ setTabPlacement( tabPlacement, Priority.CLIENT ); } /** * Sets the side at which tabs are to be displayed. This method has to * be called before a {@link DockController} is installed, otherwise the * settings has no effect. * @param tabPlacement the side at which to show tabs, may be <code>null</code> to * use the default value * @param priority the importance of the new setting (whether it should override existing settings or not). */ public void setTabPlacement( TabPlacement tabPlacement, Priority priority ){ this.tabPlacement.set( priority, tabPlacement ); } /** * Gets the side at which tabs are displayed. * @return the side with the tabs, may be <code>null</code> */ public TabPlacement getTabPlacement(){ return tabPlacement.get(); } public DockableMovingImageFactory getMovingImageFactory( DockController controller ) { return movingImage.get(); } public Combiner getCombiner( DockStation station ) { return combiner.get(); } public StationPaint getPaint( DockStation station ) { return paint.get(); } public DisplayerFactory getDisplayFactory( DockStation station ) { return displayerFactory.get(); } public DockTitleFactory getTitleFactory( DockController controller ) { return titleFactory.get(); } public DockableSelection getDockableSelection( DockController controller ) { return selection.get(); } }