/* * 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) 2011 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.stack.tab; import java.awt.Component; import java.awt.Dimension; import java.awt.Point; import java.awt.Rectangle; import java.util.ArrayList; import java.util.List; import bibliothek.gui.Dockable; import bibliothek.gui.dock.station.stack.tab.layouting.LayoutBlock; import bibliothek.gui.dock.station.stack.tab.layouting.MenuLayoutBlock; import bibliothek.gui.dock.station.stack.tab.layouting.Size; import bibliothek.gui.dock.station.stack.tab.layouting.TabPlacement; import bibliothek.gui.dock.station.stack.tab.layouting.TabsLayoutBlock; /** * Represents one of the {@link TabPane}s that are managed by a {@link MenuLineLayout}. * @author Benjamin Sigg */ public class MenuLineLayoutPane extends AbstractTabLayoutManagerPane{ private MenuLayoutBlock menu; private LayoutBlock info; private TabsLayoutBlock tabs; private MenuLineLayout layout; /** * Creates new layout information for <code>pane</code>. * @param layout the layout using this pane * @param pane the owner of this information */ public MenuLineLayoutPane( MenuLineLayout layout, TabPane pane ){ super( pane ); this.layout = layout; menu = layout.getFactory().createMenu( layout, pane ); info = layout.getFactory().createInfo( layout, pane ); tabs = layout.getFactory().createTabs( layout, pane ); } /** * Gets the tabs that are shown on this pane. * @return the tabs */ public TabsLayoutBlock getTabs(){ return tabs; } /** * Gets the info {@link Component} that is shown on this pane. * @return the info component */ public LayoutBlock getInfo(){ return info; } /** * Gets the menu that is shown on this pane. * @return the menu */ public MenuLayoutBlock getMenu(){ return menu; } /** * Calculates the preferred size to show all elements. * @return the preferred size */ public Dimension getPreferredSize(){ List<MenuLineLayoutPossibility> layouts = listLayouts(); Dimension bestSize = new Dimension( 0, 0 ); Dimension dockableSize = new Dimension(); TabPane pane = getPane(); for( Dockable dockable : pane.getDockables()){ Dimension size = pane.getPreferredSize( dockable ); dockableSize.width = Math.max( dockableSize.width, size.width ); dockableSize.height = Math.max( dockableSize.height, size.height ); } if( getPane().getDockTabPlacement().isHorizontal() ){ for( MenuLineLayoutPossibility layout : layouts ){ if( layout.isPreferred() ){ Dimension size = layout.getSize(); if( size.width > bestSize.width ){ bestSize = size; } } } bestSize.width = Math.max( bestSize.width, dockableSize.width ); bestSize.height += dockableSize.height; } else{ for( MenuLineLayoutPossibility layout : layouts ){ if( layout.isPreferred() ){ Dimension size = layout.getSize(); if( size.height > bestSize.height ){ bestSize = size; } } } bestSize.width += dockableSize.width; bestSize.height = Math.max( bestSize.height, dockableSize.height ); } return bestSize; } /** * Calculates the minimal size required. * @return the minimal size */ public Dimension getMinimumSize(){ List<MenuLineLayoutPossibility> layouts = listLayouts(); Dimension bestSize = null; Dimension dockableSize = new Dimension(); TabPane pane = getPane(); for( Dockable dockable : pane.getDockables()){ Dimension size = pane.getMinimumSize( dockable ); dockableSize.width = Math.max( dockableSize.width, size.width ); dockableSize.height = Math.max( dockableSize.height, size.height ); } if( getPane().getDockTabPlacement().isHorizontal() ){ for( MenuLineLayoutPossibility layout : layouts ){ Dimension size = layout.getSize(); if( bestSize == null || size.width < bestSize.width ){ bestSize = size; } } if(isUseSmallMinimumSize()){ bestSize.width = dockableSize.width; } else{ bestSize.width = Math.max( bestSize.width, dockableSize.width ); } bestSize.height += dockableSize.height; } else{ for( MenuLineLayoutPossibility layout : layouts ){ Dimension size = layout.getSize(); if( bestSize == null || size.height < bestSize.height ){ bestSize = size; } } bestSize.width += dockableSize.width; if(isUseSmallMinimumSize()){ bestSize.height = dockableSize.height; } else{ bestSize.height = Math.max( bestSize.height, dockableSize.height ); } } return bestSize; } /** * Informs this layout that it is no longer used and can release any * resource. */ public void destroy(){ getPane().destroyMenu( menu.getMenu() ); } /** * Gets the {@link MenuLineLayout} that is using this pane. * @return the layout, not <code>null</code> */ public MenuLineLayout getLayout(){ return layout; } /** * Searches the index of the tab beneath <code>mouseLocation</code>. * @param mouseLocation the location of the mouse * @return the index of the tab beneath <code>mouseLocation</code> or <code>-1</code> */ public int getIndexOfTabAt( Point mouseLocation ){ return tabs.getIndexOfTabAt( mouseLocation ); } /** * Updates the number of shown tabs and the boundaries of tabs, menu * and info. */ public void layout(){ AxisConversion conversion = getLayout().getConversion( getPane() ); List<MenuLineLayoutPossibility> layouts = listLayouts(); // search the layout that fits into the available space Rectangle available = conversion.viewToModel( getPane().getAvailableArea() ); int space = available.width; MenuLineLayoutPossibility best = null; int bestSize = -1; double bestScore = 0.0; MenuLineLayoutPossibility smallest = null; int smallestSize = -1; for( MenuLineLayoutPossibility layout : layouts ){ Dimension size = conversion.viewToModel( layout.getSize() ); if( size.width <= space ){ double score = layout.getScore(); if( best == null || (bestScore == score && bestSize < size.width ) || (bestScore < score)){ bestScore = score; best = layout; } } if( smallest == null || size.width < smallestSize ){ smallest = layout; smallestSize = size.width; } } if( best != null ){ best.apply(); } else if( smallest != null ){ smallest.apply(); } } /** * Creates a list of all available layouts. * @return the list of all available layouts */ private List<MenuLineLayoutPossibility> listLayouts(){ List<MenuLineLayoutPossibility> results = new ArrayList<MenuLineLayoutPossibility>(); TabPlacement orientation = getPane().getDockTabPlacement(); tabs.setOrientation( orientation ); Size[] sizesTabs = tabs.getSizes(); menu.setOrientation( orientation ); Size[] sizesMenu = menu.getSizes(); if( info != null ){ info.setOrientation( orientation ); Size[] sizesInfo = info.getSizes(); for( Size size : sizesInfo ){ listLayouts( results, size, sizesMenu, sizesTabs ); } } else{ listLayouts( results, null, sizesMenu, sizesTabs ); } return results; } private void listLayouts( List<MenuLineLayoutPossibility> list, Size infoSize, Size[] menuSizes, Size[] tabSizes ){ for( Size tab : tabSizes ){ if( tabs.isAllTabs( tab ) ){ listLayouts( list, infoSize, (Size)null, tab ); } else{ for( Size menu : menuSizes ){ listLayouts( list, infoSize, menu, tab ); } } } } private void listLayouts( List<MenuLineLayoutPossibility> list, Size infoSize, Size menuSize, Size tabSize ){ boolean tabMustBeMinimum = (infoSize != null && infoSize.isMinimum()) || (menuSize != null); boolean tabMustBeSingle = menuSize != null && menuSize.isMinimum(); boolean infoMustBeMinimum = menuSize != null && menuSize.isMinimum(); if( tabMustBeMinimum && !tabSize.isMinimum() ) return; if( tabMustBeSingle && tabs.getTabsCount( tabSize ) > 1 ) return; if( infoMustBeMinimum && (infoSize != null && !infoSize.isMinimum())) return; list.add( getLayout( tabSize, menuSize, infoSize ) ); } /** * Creates a possible layout for the given sizes. * @param tabSize the sizes of the tabs * @param menuSize the size of the menu * @param infoSize the size of the info component * @return a possible layout */ protected MenuLineLayoutPossibility getLayout( Size tabSize, Size menuSize, Size infoSize ){ return new MenuLineLayoutPossibility( this, tabSize, menuSize, infoSize ); } @Override public void infoComponentChanged( TabPane pane, LonelyTabPaneComponent oldInfo, LonelyTabPaneComponent newInfo ){ super.infoComponentChanged( pane, oldInfo, newInfo ); if( newInfo == null ) info = null; else info = newInfo.toLayoutBlock(); } }