/* * 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.station; import java.awt.Component; import java.awt.Container; import java.awt.Dimension; import java.awt.Graphics; import java.awt.Insets; import javax.swing.JComponent; import javax.swing.JLayeredPane; import javax.swing.JPanel; import bibliothek.gui.dock.util.BackgroundComponent; import bibliothek.util.Workarounds; /** * A panel which contains two children, the "base pane" and the "overlay pane".<br> * The "overlay pane" is painted above the "base pane" and all its children. It * can be used to paint arbitrary figures. Clients can change the painting * code by overriding {@link #paintOverlay(Graphics)}.<br> * Clients will add new {@link Component}s to the "content pane". Normally the * "content pane" is the same as the "base pane", but it is possible to use two * different {@link JComponent}s for them. The client that replaces a * "content pane" has to add the new panel to the "base pane". It is possible * to put some {@link Container}s between "base pane" and "content pane". * @author Benjamin Sigg * */ public class OverpaintablePanel extends JLayeredPane { /** the panel over all other children */ private Overlay overlay = new Overlay(); /** the panel on which children should be added */ private JComponent content = new JPanel(); /** the panel which is added to this {@link JLayeredPane} */ private JComponent base; /** whether the background should be painted or not */ private boolean solid = true; /** * Creates a new panel */ public OverpaintablePanel(){ base = content; content.setOpaque( false ); setLayer( base, DEFAULT_LAYER ); setLayer( overlay, DRAG_LAYER ); add( base ); add( overlay ); } /** * Tells this panel whether the background should be painted or not. If solid is <code>true</code>, * then the background is painted.<br> * This method should not be called by clients directly, this method is intended to be called by * {@link BackgroundComponent}s only. * @param solid whether to paint the background or not */ public void setSolid( boolean solid ){ this.solid = solid; setOpaque( solid ); if( base != content ){ base.setOpaque( solid ); } } /** * Tells whether the background of this panel should be painted or not. * @return <code>true</code> if the background is painted, <code>false</code> if this component * is transparent */ public boolean isSolid(){ return solid; } /** * Sets the panel on which clients should add their children. Note that * <code>content</code> is not added to the base-panel, that must be done * by the client. * @param content the contents of this panel */ public void setContentPane( JComponent content ){ if( content == null ) throw new IllegalArgumentException( "Content must not be null" ); this.content = content; setSolid( isSolid() ); } /** * Gets the layer on which new components should be inserted. * @return the layer */ public JComponent getContentPane(){ return content; } /** * Sets the panel which is added to <code>this</code>, and which is an * ancestor of the content-pane. The content-pane is replaced by * <code>base</code> when this method is called. * @param base the new base */ public void setBasePane( JComponent base ){ if( base == null ) throw new IllegalArgumentException( "Base must not be null" ); content = base; remove( this.base ); this.base = base; setLayer( base, DEFAULT_LAYER ); add( base ); setSolid( isSolid() ); } /** * The basic panel, directly added to <code>this</code>. * @return the basic panel, an ancestor of the content-pane. */ public JComponent getBasePane(){ return base; } /** * Paints the overlay over all components. * @param g the graphics to use */ protected void paintOverlay( Graphics g ){ // do nothing } @Override public Dimension getMinimumSize(){ if( isMinimumSizeSet() ){ return super.getMinimumSize(); } Dimension sizeBase = null; if( base != null ){ sizeBase = base.getMinimumSize(); } Dimension sizeOverlay = null; if( overlay != null ){ sizeOverlay = overlay.getMinimumSize(); } if( sizeBase == null && sizeOverlay == null ){ return super.getMinimumSize(); } else{ return max( sizeBase, sizeOverlay ); } } @Override public Dimension getPreferredSize(){ if( isPreferredSizeSet() ){ return super.getPreferredSize(); } Dimension sizeBase = null; if( base != null ){ sizeBase = base.getPreferredSize(); } Dimension sizeOverlay = null; if( overlay != null ){ sizeOverlay = overlay.getPreferredSize(); } if( sizeBase == null && sizeOverlay == null ){ return super.getPreferredSize(); } else{ return max( sizeBase, sizeOverlay ); } } @Override public Dimension getMaximumSize(){ if( isMaximumSizeSet() ){ return super.getMaximumSize(); } Dimension sizeBase = null; if( base != null ){ sizeBase = base.getMaximumSize(); } Dimension sizeOverlay = null; if( overlay != null ){ sizeOverlay = overlay.getMaximumSize(); } if( sizeBase == null && sizeOverlay == null ){ return super.getMaximumSize(); } else{ return min( sizeBase, sizeOverlay ); } } private Dimension min( Dimension a, Dimension b ){ if( a == null ){ return b; } if( b == null ){ return a; } return new Dimension( Math.min( a.width, b.width ), Math.min( a.height, b.height )); } private Dimension max( Dimension a, Dimension b ){ if( a == null ){ return b; } if( b == null ){ return a; } return new Dimension( Math.max( a.width, b.width ), Math.max( a.height, b.height )); } @Override public void doLayout() { Insets insets = getInsets(); int x = 0; int y = 0; int width = getWidth(); int height = getHeight(); if( insets != null ){ x = insets.left; y = insets.top; width -= insets.left + insets.right; height -= insets.top + insets.bottom; } base.setBounds( x, y, width, height ); overlay.setBounds( x, y, width, height ); } private class Overlay extends JPanel{ public Overlay(){ setLayout( null ); setOpaque( false ); Workarounds.getDefault().markAsGlassPane( this ); } @Override public boolean contains( int x, int y ) { return false; } @Override protected void paintComponent( Graphics g ) { paintOverlay( g ); } @Override public Dimension getMinimumSize(){ return new Dimension( 0, 0 ); } @Override public Dimension getPreferredSize(){ return new Dimension( 0, 0 ); } } }