/* * 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.station.screen.window; import java.awt.Component; import java.awt.Dimension; import java.awt.Insets; import java.awt.Point; import java.awt.Rectangle; import java.util.ArrayList; import java.util.List; import javax.swing.SwingUtilities; import bibliothek.gui.DockController; import bibliothek.gui.DockStation; import bibliothek.gui.Dockable; import bibliothek.gui.dock.ScreenDockStation; import bibliothek.gui.dock.station.DockableDisplayer; import bibliothek.gui.dock.station.DockableDisplayerListener; import bibliothek.gui.dock.station.StationChildHandle; import bibliothek.gui.dock.station.screen.ScreenDockFullscreenStrategy; import bibliothek.gui.dock.station.screen.ScreenDockWindow; import bibliothek.gui.dock.station.screen.ScreenDockWindowListener; import bibliothek.gui.dock.themes.ThemeManager; import bibliothek.gui.dock.title.DockTitle; import bibliothek.gui.dock.util.BackgroundAlgorithm; import bibliothek.gui.dock.util.BackgroundPaint; /** * A window that uses a {@link DockableDisplayer} to show the {@link Dockable}. * @author Benjamin Sigg */ public abstract class DisplayerScreenDockWindow implements ScreenDockWindow { /** the owner of this station */ private ScreenDockStation station; /** the dockable shown on this station */ private StationChildHandle handle; /** all listeners known to this window */ private List<ScreenDockWindowListener> listeners = new ArrayList<ScreenDockWindowListener>(); /** a listener to the current {@link DockableDisplayer} */ private DockableDisplayerListener displayerListener = new DockableDisplayerListener(){ public void discard( DockableDisplayer displayer ){ discardDisplayer(); } public void moveableElementChanged( DockableDisplayer displayer ){ updateTitleMover(); } }; /** the controller in whose realm this window works */ private DockController controller; /** whether the {@link DockTitle} should be shown */ private boolean showTitle = true; /** strategy for handling fullscreen mode */ private ScreenDockFullscreenStrategy strategy; /** boundaries used in normal mode */ private Rectangle normalBounds; /** the algorithm that paints the background */ private Background background = new Background(); /** a helper class moving the entire window if the title is dragged by the mouse */ private WindowMover titleMover; /** the configuration that was used to create this window */ private WindowConfiguration configuration; /** whether {@link #configuration} has been applied */ private boolean configured = false; /** * Creates a new window * @param station the owner of this window, not <code>null</code> * @param configuration default configuration of this window, cannot be changed once the window is * created */ public DisplayerScreenDockWindow( ScreenDockStation station, WindowConfiguration configuration ){ if( station == null ) throw new IllegalArgumentException( "station must not be null" ); this.station = station; this.configuration = configuration; } /** * Called the first time when a {@link Dockable} is set. * @param configuration the configuration that is to be applied */ protected void init( WindowConfiguration configuration ){ if( configuration.isMoveOnTitleGrab() ){ titleMover = createTitleMover(); titleMover.setAllowDragAndDrop( configuration.isAllowDragAndDropOnTitle() ); titleMover.setResetOnDropable( configuration.isResetOnDropable() ); } } /** * Tells whether this window can be moved by grabbing the title. * @return whether a {@link WindowMover} has been created */ protected boolean isMoveOnTitleGrab(){ return titleMover != null; } /** * Creates a new {@link WindowMover} which is used to move this window if the {@link DockTitle} * is dragged by the mouse. This method is only called if {@link WindowConfiguration#isMoveOnTitleGrab()} * returns true. * @return the new mover, can be <code>null</code> */ protected WindowMover createTitleMover(){ return new WindowMover( this ); } public void addScreenDockWindowListener( ScreenDockWindowListener listener ){ listeners.add( listener ); } public void removeScreenDockWindowListener( ScreenDockWindowListener listener ){ listeners.remove( listener ); } /** * Gets a list of all listeners that are currently registered. * @return all listeners */ protected ScreenDockWindowListener[] listeners(){ return listeners.toArray( new ScreenDockWindowListener[ listeners.size() ] ); } /** * Informs all listeners that the fullscreen state changed */ protected void fireFullscreenChanged(){ for( ScreenDockWindowListener listener : listeners() ){ listener.fullscreenStateChanged( this ); } } /** * Informs all listeners that the visibility state changed */ protected void fireVisibilityChanged(){ for( ScreenDockWindowListener listener : listeners() ){ listener.visibilityChanged( this ); } } /** * Informs all listeners that the current size or position changed */ protected void fireShapeChanged(){ for( ScreenDockWindowListener listener : listeners() ){ listener.shapeChanged( this ); } } /** * Informs all listeners that this window wants to be closed */ protected void fireWindowClosing(){ for( ScreenDockWindowListener listener : listeners() ){ listener.windowClosing( this ); } } /** * Forces the subclass of this window to show <code>displayer</code>. Only * one displayer should be shown at any time. A new displayer replaces * an old one. * @param displayer the displayer to show or <code>null</code> to remove * the current displayer */ protected abstract void showDisplayer( DockableDisplayer displayer ); /** * Gets the component on which {@link ScreenDockWindow#setWindowBounds(java.awt.Rectangle, boolean)} * is applied. * @return the base component */ protected abstract Component getWindowComponent(); /** * Sets the algorithm that paints the background of this window. * @param background the algorithm, may be <code>null</code> */ protected abstract void setBackground( BackgroundAlgorithm background ); /** * Sets whether the {@link DockTitle} should be shown or not. * @param showTitle <code>true</code> if the title should be visible, * <code>false</code> otherwise */ public void setShowTitle( boolean showTitle ) { if( this.showTitle != showTitle ){ this.showTitle = showTitle; if( handle != null ){ if( showTitle ){ handle.setTitleRequest( station.getTitleVersion() ); } else{ handle.setTitleRequest( null ); } } } } /** * Tells whether the {@link DockTitle} is generally shown. * @return <code>true</code> if the title is shown */ public boolean isShowTitle() { return showTitle; } public Dockable getDockable() { if( handle == null ) return null; return handle.getDockable(); } public DockableDisplayer getDockableDisplayer(){ if( handle == null ){ return null; } return handle.getDisplayer(); } public void setDockable( Dockable dockable ) { if( dockable != null && !configured ){ init( configuration ); configured = true; } // remove old displayer if( handle != null ){ DockableDisplayer displayer = handle.getDisplayer(); displayer.removeDockableDisplayerListener( displayerListener ); handle.destroy(); updateTitleMover(); handle = null; } // add new displayer DockableDisplayer displayer = null; if( dockable != null ){ handle = new StationChildHandle( station, station.getDisplayers(), dockable, showTitle ? station.getTitleVersion() : null ){ @Override protected void updateTitle( DockTitle title ){ super.updateTitle( title ); updateTitleMover(); } }; handle.updateDisplayer(); displayer = handle.getDisplayer(); displayer.addDockableDisplayerListener( displayerListener ); updateTitleMover(); } showDisplayer( displayer ); } /** * Gets the configuration which was used to set up this window. * @return the configuration, should not be modified by clients or subclasses */ public WindowConfiguration getConfiguration(){ return configuration; } /** * If there is a {@link #titleMover}, then this method updates the element of the mover. It first * tries to set a {@link DockTitle}, if not available the method tries to find other elements like * a tab. */ private void updateTitleMover(){ if( titleMover != null ){ if( handle != null && handle.getDisplayer() != null ){ titleMover.setElement( handle.getDisplayer().getMoveableElement() ); } else{ titleMover.setElement( null ); } } } /** * Replaces the current {@link DockableDisplayer} with a new instance. */ protected void discardDisplayer(){ DockableDisplayer displayer = handle.getDisplayer(); displayer.removeDockableDisplayerListener( displayerListener ); handle.updateDisplayer(); displayer = handle.getDisplayer(); displayer.addDockableDisplayerListener( displayerListener ); showDisplayer( displayer ); } public void setFullscreenStrategy( ScreenDockFullscreenStrategy strategy ) { this.strategy = strategy; } public boolean isFullscreen() { if( strategy == null ){ if( isVisible() ){ throw new IllegalStateException( "no strategy available" ); } else{ return false; } } return strategy.isFullscreen( this ); } public void setFullscreen( boolean fullscreen ) { if( strategy == null ){ throw new IllegalStateException( "no strategy available" ); } boolean state = isFullscreen(); if( state != fullscreen ){ strategy.setFullscreen( this, fullscreen ); fireFullscreenChanged(); } } public void setNormalBounds( Rectangle bounds ) { this.normalBounds = bounds; } public Rectangle getNormalBounds() { return normalBounds; } public Dimension getMinimumWindowSize(){ return getWindowComponent().getMinimumSize(); } public void setController( DockController controller ) { // remove old DockTitle if( handle != null ){ if( this.controller != null ){ handle.setTitleRequest( null ); } } background.setController( controller ); this.controller = controller; // create new DockTitle if( handle != null ){ if( this.controller != null && isShowTitle() ){ handle.setTitleRequest( station.getTitleVersion() ); } } } public Point getTitleCenter(){ if( handle == null ){ return null; } DockableDisplayer displayer = handle.getDisplayer(); if( displayer == null ){ return null; } Point center = displayer.getTitleCenter(); if( center == null ){ return null; } Component base = getWindowComponent(); if( base == null ) return null; return SwingUtilities.convertPoint( displayer.getComponent(), center, base ); } public Point getOffsetDrop() { if( handle == null ) return null; DockableDisplayer displayer = handle.getDisplayer(); if( displayer == null ) return null; Insets insets = getDockableInsets(); return new Point( insets.left, insets.top ); } public Point getOffsetMove() { if( handle == null ) return null; DockableDisplayer displayer = handle.getDisplayer(); if( displayer == null ) return null; DockTitle title = displayer.getTitle(); if( title == null ) return null; Component base = getWindowComponent(); if( base == null ) return null; Point zero = new Point( 0, 0 ); zero = SwingUtilities.convertPoint( title.getComponent(), zero, base ); return zero; } public boolean inTitleArea( int x, int y ){ if( handle == null ) return false; DockableDisplayer displayer = handle.getDisplayer(); if( displayer == null ) return false; Point point = new Point( x, y ); SwingUtilities.convertPointFromScreen( point, displayer.getComponent() ); return displayer.titleContains( point.x, point.y ); } public boolean inCombineArea( int x, int y ) { return inTitleArea( x, y ); } public boolean contains( int x, int y ){ Component component = getWindowComponent(); Point point = new Point( x, y ); SwingUtilities.convertPointFromScreen( point, component ); return component.contains( point ); } /** * Gets the controller in whose realm this window is used. * @return the controller, can be <code>null</code> */ public DockController getController() { return controller; } public ScreenDockStation getStation(){ return station; } /** * The algorithm that paints the background of this window. * @author Benjamin Sigg */ protected class Background extends BackgroundAlgorithm implements ScreenDockWindowBackgroundComponent{ public Background(){ super( ScreenDockWindowBackgroundComponent.KIND, ThemeManager.BACKGROUND_PAINT + ".station.screen" ); } @Override public void set( BackgroundPaint value ){ super.set( value ); if( getPaint() == null ){ setBackground( null ); } else{ setBackground( this ); } } public ScreenDockWindow getWindow(){ return DisplayerScreenDockWindow.this; } public DockStation getStation(){ return getWindow().getStation(); } public Component getComponent(){ return getWindowComponent(); } } }