/* * Copyright (c) 2005-2010 Flamingo Kirill Grouchnikov. All Rights Reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * o Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * * o Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. * * o Neither the name of Flamingo Kirill Grouchnikov nor the names of * its contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ package org.pushingpixels.flamingo.api.ribbon.resize; import java.awt.Insets; import java.util.*; import javax.swing.JComponent; import org.pushingpixels.flamingo.api.common.AbstractCommandButton; import org.pushingpixels.flamingo.api.common.CommandButtonDisplayState; import org.pushingpixels.flamingo.api.ribbon.*; import org.pushingpixels.flamingo.internal.ui.ribbon.*; /** * The core resize policies. Provides a number of built in resize policies that * respect the application element priorities passed to * {@link JRibbonBand#addCommandButton(org.pushingpixels.flamingo.api.common.AbstractCommandButton, org.pushingpixels.flamingo.api.ribbon.RibbonElementPriority)} * and * {@link JRibbonBand#addRibbonGallery(String, java.util.List, java.util.Map, int, int, org.pushingpixels.flamingo.api.ribbon.RibbonElementPriority)} * APIs. There are three types of built in resize policies: </p> * * <ul> * <li>Resize policies for the {@link JFlowRibbonBand}s. The {@link FlowTwoRows} * and {@link FlowThreeRows} allow placing the flow ribbon band content in two * and three rows respectively.</li> * <li>Resize policies for the {@link JRibbonBand}s. The * {@link BaseCoreRibbonBandResizePolicy} is the base class for these policies. * These policies respect the {@link RibbonElementPriority} associated on * command buttons and ribbon galleries in * {@link RibbonBandResizePolicy#getPreferredWidth(int, int)} and * {@link RibbonBandResizePolicy#install(int, int)}. While * {@link RibbonBandResizePolicy#install(int, int)} call on a * {@link JFlowRibbonBand} only changes the bounds of the flow components, this * call on a {@link JRibbonBand} can also change the display state of the * command buttons (with * {@link AbstractCommandButton#setDisplayState(org.pushingpixels.flamingo.api.common.CommandButtonDisplayState)} * ) and the number of visible buttons in the ribbon galleries.</li> * <li>The collapsed policy that replaces the entire content of the ribbon band * with a single popup button. This is done when there is not enough horizontal * space to show the content of the ribbon band under the most restrictive * resize policy. Activating the popup button will show the original content * under the most permissive resize policy in a popup. This policy is * implemented in the {@link IconRibbonBandResizePolicy}.</li> * </ul> * * <p> * In addition to the specific resize policies, this class provides three core * resize policies lists for {@link JRibbonBand}s: * </p> * * <ul> * <li>{@link #getCorePoliciesPermissive(JRibbonBand)} returns a list that * starts with a resize policy that shows all command buttons in the * {@link CommandButtonDisplayState#BIG} and ribbon galleries with the largest * number of visible buttons, fully utilizing the available screen space.</li> * <li>{@link #getCorePoliciesRestrictive(JRibbonBand)} returns a list that * starts with a resize policy that respects the associated ribbon element * priority set on the specific components.</li> * <li> {@link #getCorePoliciesNone(JRibbonBand)} returns a list that only has a * <code>mirror</code> resize policy that respects the associated ribbon element * priority set on the specific components.</li> * </ul> * * <p> * Note that as mentioned above, all the three lists above have the * <code>collapsed</code> policy as their last element. * </p> * * <p> * In addition, the * {@link #getCoreFlowPoliciesRestrictive(JFlowRibbonBand, int)} returns a * restrictive resize policy for {@link JFlowRibbonBand}s. The list starts with * the two-row policy, goes to the three-row policy and then finally to the * collapsed policy. * </p> * * @author Kirill Grouchnikov */ public class CoreRibbonResizePolicies { /** * Maps the element priority associated with a ribbon band component to the * element priority assigned by the specific resize policy. * * @author Kirill Grouchnikov */ static interface Mapping { /** * Maps the element priority associated with a ribbon band component to * the element priority assigned by the specific resize policy. * * @param priority * The element priority associated with a ribbon band * component * @return The element priority assigned by the specific resize policy. */ RibbonElementPriority map(RibbonElementPriority priority); } /** * Returns a list that starts with a resize policy that shows all command * buttons in the {@link CommandButtonDisplayState#BIG} and ribbon galleries * with the largest number of visible buttons. The last entry is the * {@link IconRibbonBandResizePolicy}. * * @param ribbonBand * Ribbon band. * @return The permissive list of core ribbon band resize policies. */ public static List<RibbonBandResizePolicy> getCorePoliciesPermissive( JRibbonBand ribbonBand) { List<RibbonBandResizePolicy> result = new ArrayList<RibbonBandResizePolicy>(); result.add(new CoreRibbonResizePolicies.None(ribbonBand .getControlPanel())); result.add(new CoreRibbonResizePolicies.Low2Mid(ribbonBand .getControlPanel())); result.add(new CoreRibbonResizePolicies.Mid2Mid(ribbonBand .getControlPanel())); result.add(new CoreRibbonResizePolicies.Mirror(ribbonBand .getControlPanel())); result.add(new CoreRibbonResizePolicies.Mid2Low(ribbonBand .getControlPanel())); result.add(new CoreRibbonResizePolicies.High2Mid(ribbonBand .getControlPanel())); result.add(new CoreRibbonResizePolicies.High2Low(ribbonBand .getControlPanel())); result .add(new IconRibbonBandResizePolicy(ribbonBand .getControlPanel())); return result; } /** * Returns a list that starts with a resize policy that respects the * associated ribbon element priority set on the specific components. The * last entry is the {@link IconRibbonBandResizePolicy}. * * @param ribbonBand * Ribbon band. * @return The restrictive list of core ribbon band resize policies. */ public static List<RibbonBandResizePolicy> getCorePoliciesRestrictive( JRibbonBand ribbonBand) { List<RibbonBandResizePolicy> result = new ArrayList<RibbonBandResizePolicy>(); result.add(new CoreRibbonResizePolicies.Mirror(ribbonBand .getControlPanel())); result.add(new CoreRibbonResizePolicies.Mid2Low(ribbonBand .getControlPanel())); result.add(new CoreRibbonResizePolicies.High2Mid(ribbonBand .getControlPanel())); result.add(new CoreRibbonResizePolicies.High2Low(ribbonBand .getControlPanel())); result .add(new IconRibbonBandResizePolicy(ribbonBand .getControlPanel())); return result; } /** * Returns a list that only has a <code>mirror</code> resize policy that * respects the associated ribbon element priority set on the specific * components. The last entry is the {@link IconRibbonBandResizePolicy}. * * @param ribbonBand * Ribbon band. * @return The mirror list of core ribbon band resize policies. */ public static List<RibbonBandResizePolicy> getCorePoliciesNone( JRibbonBand ribbonBand) { List<RibbonBandResizePolicy> result = new ArrayList<RibbonBandResizePolicy>(); result.add(new CoreRibbonResizePolicies.Mirror(ribbonBand .getControlPanel())); result .add(new IconRibbonBandResizePolicy(ribbonBand .getControlPanel())); return result; } /** * The base class for mapping-based core resize policies. * * @author Kirill Grouchnikov */ protected static abstract class BaseCoreRibbonBandResizePolicy extends BaseRibbonBandResizePolicy<JBandControlPanel> { /** * The element priority mapping. */ protected Mapping mapping; /** * Creates a new resize policy. * * @param controlPanel * The control panel of the associated ribbon band. * @param mapping * The element priority mapping. */ protected BaseCoreRibbonBandResizePolicy( JBandControlPanel controlPanel, Mapping mapping) { super(controlPanel); this.mapping = mapping; } /** * Returns the total width of the specified buttons. * * @param gap * Inter component gap. * @param bigButtons * List of buttons in big display state. * @param mediumButtons * List of buttons in medium display state. * @param smallButtons * List of buttons in small display state. * @return Total width of the specified buttons. */ protected int getWidth(int gap, java.util.List<AbstractCommandButton> bigButtons, java.util.List<AbstractCommandButton> mediumButtons, java.util.List<AbstractCommandButton> smallButtons) { int result = 0; boolean hasLeadingContent = false; for (AbstractCommandButton top : bigButtons) { if (hasLeadingContent) { result += gap; } result += getPreferredWidth(top, RibbonElementPriority.TOP); hasLeadingContent = true; } int medSize = mediumButtons.size(); if (medSize > 0) { // try to move buttons from low to med to make // three-somes. while (((mediumButtons.size() % 3) != 0) && (smallButtons.size() > 0)) { AbstractCommandButton low = smallButtons.remove(0); mediumButtons.add(low); } } // at this point, mediumButtons list contains either // threesomes, or there are no buttons in lowButtons. int index3 = 0; int maxWidth3 = 0; for (AbstractCommandButton medium : mediumButtons) { int medWidth = getPreferredWidth(medium, RibbonElementPriority.MEDIUM); maxWidth3 = Math.max(maxWidth3, medWidth); index3++; if (index3 == 3) { // last button in threesome index3 = 0; if (hasLeadingContent) { result += gap; } result += maxWidth3; hasLeadingContent = true; maxWidth3 = 0; } } // at this point, maxWidth3 may be non-zero. We can safely // add it, since in this case there will be no buttons // left in mediumButtons if (maxWidth3 > 0) { if (hasLeadingContent) { result += gap; } result += maxWidth3; hasLeadingContent = true; } index3 = 0; maxWidth3 = 0; for (AbstractCommandButton low : smallButtons) { int lowWidth = getPreferredWidth(low, RibbonElementPriority.LOW); maxWidth3 = Math.max(maxWidth3, lowWidth); index3++; if (index3 == 3) { // last button in threesome index3 = 0; if (hasLeadingContent) { result += gap; } result += maxWidth3; hasLeadingContent = true; maxWidth3 = 0; } } // at this point, maxWidth3 may be non-zero. We can safely // add it, since in this case there will be no buttons left if (maxWidth3 > 0) { if (hasLeadingContent) { result += gap; } result += maxWidth3; hasLeadingContent = true; } return result; } /** * Returns the preferred width of the specified command button under the * specified display priority. * * @param button * Command button. * @param buttonDisplayPriority * Button display priority. * @return The preferred width of the specified command button under the * specified display priority. */ private int getPreferredWidth(AbstractCommandButton button, RibbonElementPriority buttonDisplayPriority) { CommandButtonDisplayState displayState = null; switch (buttonDisplayPriority) { case TOP: displayState = CommandButtonDisplayState.BIG; break; case MEDIUM: displayState = CommandButtonDisplayState.MEDIUM; break; case LOW: displayState = CommandButtonDisplayState.SMALL; break; } return displayState.createLayoutManager(button).getPreferredSize( button).width; } @Override public int getPreferredWidth(int availableHeight, int gap) { int result = 0; Insets ins = this.controlPanel.getInsets(); for (JBandControlPanel.ControlPanelGroup controlPanelGroup : this.controlPanel .getControlPanelGroups()) { boolean isCoreContent = controlPanelGroup.isCoreContent(); if (isCoreContent) { List<JRibbonComponent> ribbonComps = controlPanelGroup .getRibbonComps(); Map<JRibbonComponent, Integer> ribbonCompRowSpans = controlPanelGroup .getRibbonCompsRowSpans(); // if a group has a title, then the core components in that // group start from the second row int startRowIndex = (controlPanelGroup.getGroupTitle() == null) ? 0 : 1; int rowIndex = startRowIndex; int maxWidthInCurrColumn = 0; for (int i = 0; i < ribbonComps.size(); i++) { JRibbonComponent ribbonComp = ribbonComps.get(i); int rowSpan = ribbonCompRowSpans.get(ribbonComp); // do we need to start a new column? int nextRowIndex = rowIndex + rowSpan; if (nextRowIndex > 3) { result += maxWidthInCurrColumn; result += gap; maxWidthInCurrColumn = 0; rowIndex = startRowIndex; } RibbonElementPriority targetPriority = RibbonElementPriority.TOP; if (ribbonComp.isResizingAware()) { targetPriority = this.mapping .map(RibbonElementPriority.TOP); } int prefWidth = ribbonComp.getUI().getPreferredSize( targetPriority).width; maxWidthInCurrColumn = Math.max(maxWidthInCurrColumn, prefWidth); rowIndex += rowSpan; } if ((rowIndex > 0) && (rowIndex <= 3)) { result += maxWidthInCurrColumn; result += gap; } } else { int galleryAvailableHeight = availableHeight - ins.top - ins.bottom; // ribbon galleries result += this.getPreferredGalleryWidth(controlPanelGroup, galleryAvailableHeight, gap); // ribbon buttons result += this.getPreferredButtonWidth(controlPanelGroup, gap); } result += gap * 3 / 2; } // no gap after the last group result -= gap * 3 / 2; // control panel insets result += ins.left + ins.right; result += gap; return result; } /** * Returns the preferred width of all the buttons in the specified * control panel group. * * @param controlPanelGroup * A single control panel group in the associated ribbon * band. * @param gap * Inter component gap. * @return The preferred width of all the buttons in the specified * control panel group. */ protected int getPreferredButtonWidth( JBandControlPanel.ControlPanelGroup controlPanelGroup, int gap) { Map<RibbonElementPriority, List<AbstractCommandButton>> mapped = new HashMap<RibbonElementPriority, List<AbstractCommandButton>>(); for (RibbonElementPriority rep : RibbonElementPriority.values()) { mapped.put(rep, new ArrayList<AbstractCommandButton>()); } for (RibbonElementPriority elementPriority : RibbonElementPriority .values()) { // map the priority RibbonElementPriority mappedPriority = mapping .map(elementPriority); for (AbstractCommandButton button : controlPanelGroup .getRibbonButtons(elementPriority)) { // and add the button to a list based on the mapped priority mapped.get(mappedPriority).add(button); } } // at this point, the lists in the 'mapped' contain the buttons // grouped by the priority computed by the resize policy. return this.getWidth(gap, mapped.get(RibbonElementPriority.TOP), mapped.get(RibbonElementPriority.MEDIUM), mapped .get(RibbonElementPriority.LOW)); } /** * Returns the preferred width of all the ribbon galleries in the * specified control panel group. * * @param controlPanelGroup * A single control panel group in the associated ribbon * band. * @param galleryAvailableHeight * Available height for the ribbon galleries. * @param gap * Inter component gap. * @return The preferred width of all the ribbon galleries in the * specified control panel group. */ private int getPreferredGalleryWidth( JBandControlPanel.ControlPanelGroup controlPanelGroup, int galleryAvailableHeight, int gap) { int result = 0; for (RibbonElementPriority elementPriority : RibbonElementPriority .values()) { // map the priority RibbonElementPriority mappedPriority = mapping .map(elementPriority); // go over all galleries registered with the specific priority for (JRibbonGallery gallery : controlPanelGroup .getRibbonGalleries(elementPriority)) // and take the preferred width under the mapped priority result += (gallery.getPreferredWidth(mappedPriority, galleryAvailableHeight) + gap); } return result; } @Override public void install(int availableHeight, int gap) { for (JBandControlPanel.ControlPanelGroup controlPanelGroup : this.controlPanel .getControlPanelGroups()) { boolean isCoreContent = controlPanelGroup.isCoreContent(); if (isCoreContent) { List<JRibbonComponent> ribbonComps = controlPanelGroup .getRibbonComps(); for (int i = 0; i < ribbonComps.size(); i++) { JRibbonComponent ribbonComp = ribbonComps.get(i); RibbonElementPriority targetPriority = RibbonElementPriority.TOP; if (ribbonComp.isResizingAware()) { targetPriority = this.mapping .map(RibbonElementPriority.TOP); } ribbonComp.setDisplayPriority(targetPriority); } } else { // set the display priority for the galleries for (RibbonElementPriority elementPriority : RibbonElementPriority .values()) { // map the priority RibbonElementPriority mappedPriority = mapping .map(elementPriority); // go over all galleries registered with the specific // priority for (JRibbonGallery gallery : controlPanelGroup .getRibbonGalleries(elementPriority)) // and set the display priority based on the // specific // resize policy gallery.setDisplayPriority(mappedPriority); } // set the display priority for the buttons Map<RibbonElementPriority, List<AbstractCommandButton>> mapped = new HashMap<RibbonElementPriority, List<AbstractCommandButton>>(); for (RibbonElementPriority rep : RibbonElementPriority .values()) { mapped.put(rep, new ArrayList<AbstractCommandButton>()); } for (RibbonElementPriority elementPriority : RibbonElementPriority .values()) { // map the priority RibbonElementPriority mappedPriority = mapping .map(elementPriority); for (AbstractCommandButton button : controlPanelGroup .getRibbonButtons(elementPriority)) { // and add the button to a list based on the mapped // priority mapped.get(mappedPriority).add(button); } } // start from the top priority for (AbstractCommandButton big : mapped .get(RibbonElementPriority.TOP)) { big.setDisplayState(CommandButtonDisplayState.BIG); } // next - medium priority if (mapped.get(RibbonElementPriority.MEDIUM).size() > 0) { // try to move buttons from small to medium to make // three-somes. while (((mapped.get(RibbonElementPriority.MEDIUM) .size() % 3) != 0) && (mapped.get(RibbonElementPriority.LOW) .size() > 0)) { AbstractCommandButton low = mapped.get( RibbonElementPriority.LOW).get(0); mapped.get(RibbonElementPriority.LOW).remove(low); mapped.get(RibbonElementPriority.MEDIUM).add(low); } } for (AbstractCommandButton medium : mapped .get(RibbonElementPriority.MEDIUM)) { medium .setDisplayState(CommandButtonDisplayState.MEDIUM); } // finally - low priority for (AbstractCommandButton low : mapped .get(RibbonElementPriority.LOW)) { low.setDisplayState(CommandButtonDisplayState.SMALL); } } } } } /** * Core resize policy that maps all {@link RibbonElementPriority}s to * {@link RibbonElementPriority#TOP}. * * @author Kirill Grouchnikov */ public static final class None extends BaseCoreRibbonBandResizePolicy { /** * Creates the new resize policy of type <code>NONE</code>. * * @param controlPanel * The control panel of the associated ribbon band. */ public None(JBandControlPanel controlPanel) { super(controlPanel, new Mapping() { @Override public RibbonElementPriority map(RibbonElementPriority priority) { return RibbonElementPriority.TOP; } }); } } /** * Core resize policy that maps: * * <ul> * <li>{@link RibbonElementPriority#TOP} -> * {@link RibbonElementPriority#TOP}</li> * <li>{@link RibbonElementPriority#MEDIUM} -> * {@link RibbonElementPriority#TOP}</li> * <li>{@link RibbonElementPriority#LOW} -> * {@link RibbonElementPriority#MEDIUM}</li> * </ul> * * @author Kirill Grouchnikov */ public static final class Low2Mid extends BaseCoreRibbonBandResizePolicy { /** * Creates the new resize policy of type <code>LOW2MID</code>. * * @param controlPanel * The control panel of the associated ribbon band. */ public Low2Mid(JBandControlPanel controlPanel) { super(controlPanel, new Mapping() { @Override public RibbonElementPriority map(RibbonElementPriority priority) { switch (priority) { case TOP: return RibbonElementPriority.TOP; case MEDIUM: return RibbonElementPriority.TOP; case LOW: return RibbonElementPriority.MEDIUM; } return null; } }); } } /** * Core resize policy that maps: * * <ul> * <li>{@link RibbonElementPriority#TOP} -> * {@link RibbonElementPriority#TOP}</li> * <li>{@link RibbonElementPriority#MEDIUM} -> * {@link RibbonElementPriority#MEDIUM}</li> * <li>{@link RibbonElementPriority#LOW} -> * {@link RibbonElementPriority#MEDIUM}</li> * </ul> * * @author Kirill Grouchnikov */ public static final class Mid2Mid extends BaseCoreRibbonBandResizePolicy { /** * Creates the new resize policy of type <code>MID2MID</code>. * * @param controlPanel * The control panel of the associated ribbon band. */ public Mid2Mid(JBandControlPanel controlPanel) { super(controlPanel, new Mapping() { @Override public RibbonElementPriority map(RibbonElementPriority priority) { switch (priority) { case TOP: return RibbonElementPriority.TOP; case MEDIUM: return RibbonElementPriority.MEDIUM; case LOW: return RibbonElementPriority.MEDIUM; } return null; } }); } } /** * Mirror core resize policy that maps the values of * {@link RibbonElementPriority}s to themselves. * * @author Kirill Grouchnikov */ public static final class Mirror extends BaseCoreRibbonBandResizePolicy { /** * Creates the new resize policy of type <code>MIRROR</code>. * * @param controlPanel * The control panel of the associated ribbon band. */ public Mirror(JBandControlPanel controlPanel) { super(controlPanel, new Mapping() { @Override public RibbonElementPriority map(RibbonElementPriority priority) { return priority; } }); } } /** * Core resize policy that maps: * * <ul> * <li>{@link RibbonElementPriority#TOP} -> * {@link RibbonElementPriority#TOP}</li> * <li>{@link RibbonElementPriority#MEDIUM} -> * {@link RibbonElementPriority#LOW}</li> * <li>{@link RibbonElementPriority#LOW} -> * {@link RibbonElementPriority#LOW}</li> * </ul> * * @author Kirill Grouchnikov */ public static final class Mid2Low extends BaseCoreRibbonBandResizePolicy { /** * Creates the new resize policy of type <code>MID2LOW</code>. * * @param controlPanel * The control panel of the associated ribbon band. */ public Mid2Low(JBandControlPanel controlPanel) { super(controlPanel, new Mapping() { @Override public RibbonElementPriority map(RibbonElementPriority priority) { switch (priority) { case TOP: return RibbonElementPriority.TOP; case MEDIUM: return RibbonElementPriority.LOW; case LOW: return RibbonElementPriority.LOW; } return null; } }); } } /** * Core resize policy that maps: * * <ul> * <li>{@link RibbonElementPriority#TOP} -> * {@link RibbonElementPriority#MEDIUM}</li> * <li>{@link RibbonElementPriority#MEDIUM} -> * {@link RibbonElementPriority#LOW}</li> * <li>{@link RibbonElementPriority#LOW} -> * {@link RibbonElementPriority#LOW}</li> * </ul> * * @author Kirill Grouchnikov */ public static final class High2Mid extends BaseCoreRibbonBandResizePolicy { /** * Creates the new resize policy of type <code>HIGH2MID</code>. * * @param controlPanel * The control panel of the associated ribbon band. */ public High2Mid(JBandControlPanel controlPanel) { super(controlPanel, new Mapping() { @Override public RibbonElementPriority map(RibbonElementPriority priority) { switch (priority) { case TOP: return RibbonElementPriority.MEDIUM; case MEDIUM: return RibbonElementPriority.LOW; case LOW: return RibbonElementPriority.LOW; } return null; } }); } } /** * Core resize policy that maps all {@link RibbonElementPriority}s to * {@link RibbonElementPriority#LOW}. * * @author Kirill Grouchnikov */ public static final class High2Low extends BaseCoreRibbonBandResizePolicy { /** * Creates the new resize policy of type <code>HIGH2LOW</code>. * * @param controlPanel * The control panel of the associated ribbon band. */ public High2Low(JBandControlPanel controlPanel) { super(controlPanel, new Mapping() { @Override public RibbonElementPriority map(RibbonElementPriority priority) { return RibbonElementPriority.LOW; } }); } } /** * Core resize policy for {@link JFlowRibbonBand} that places the content in * two rows. * * @author Kirill Grouchnikov */ public static class FlowTwoRows extends BaseRibbonBandResizePolicy<JFlowBandControlPanel> { /** * Creates a new two-row resize policy for {@link JFlowRibbonBand}s. * * @param controlPanel * The control panel of the associated ribbon band. */ public FlowTwoRows(JFlowBandControlPanel controlPanel) { super(controlPanel); } @Override public int getPreferredWidth(int availableHeight, int gap) { int compCount = controlPanel.getFlowComponents().size(); int[] widths = new int[compCount]; int index = 0; int currBestResult = 0; for (JComponent flowComp : controlPanel.getFlowComponents()) { int pref = flowComp.getPreferredSize().width; widths[index++] = pref; currBestResult += (pref + gap); } // need to find the inflection point that results in // lowest value for max length of two sub-sequences for (int inflectionIndex = 0; inflectionIndex < (compCount - 1); inflectionIndex++) { int w1 = 0; for (int index1 = 0; index1 <= inflectionIndex; index1++) { w1 += widths[index1] + gap; } int w2 = 0; for (int index2 = inflectionIndex + 1; index2 < compCount; index2++) { w2 += widths[index2] + gap; } int width = Math.max(w1, w2); if (width < currBestResult) currBestResult = width; } return currBestResult; } @Override public void install(int availableHeight, int gap) { } } /** * Core resize policy for {@link JFlowRibbonBand} that places the content in * three rows. * * @author Kirill Grouchnikov */ public static class FlowThreeRows extends BaseRibbonBandResizePolicy<JFlowBandControlPanel> { /** * Creates a new three-row resize policy for {@link JFlowRibbonBand}s. * * @param controlPanel * The control panel of the associated ribbon band. */ public FlowThreeRows(JFlowBandControlPanel controlPanel) { super(controlPanel); } @Override public int getPreferredWidth(int availableHeight, int gap) { int compCount = controlPanel.getFlowComponents().size(); int[] widths = new int[compCount]; int index = 0; int currBestResult = 0; for (JComponent flowComp : controlPanel.getFlowComponents()) { int pref = flowComp.getPreferredSize().width; widths[index++] = pref; currBestResult += (pref + gap); } // need to find the inflection points that results in // lowest value for max length of three sub-sequences for (int inflectionIndex1 = 0; inflectionIndex1 < (compCount - 2); inflectionIndex1++) { for (int inflectionIndex2 = inflectionIndex1 + 1; inflectionIndex2 < (compCount - 1); inflectionIndex2++) { int w1 = 0; for (int index1 = 0; index1 <= inflectionIndex1; index1++) { w1 += widths[index1] + gap; } int w2 = 0; for (int index2 = inflectionIndex1 + 1; index2 <= inflectionIndex2; index2++) { w2 += widths[index2] + gap; } int w3 = 0; for (int index3 = inflectionIndex2 + 1; index3 < compCount; index3++) { w3 += widths[index3] + gap; } int width = Math.max(Math.max(w1, w2), w3); if (width < currBestResult) currBestResult = width; } } return currBestResult; } @Override public void install(int availableHeight, int gap) { } } /** * Returns a list that has {@link FlowTwoRows} policy followed by the * {@link FlowThreeRows} resize policy. The last entry is the * {@link IconRibbonBandResizePolicy}. * * @param ribbonBand * Ribbon band. * @param stepsToRepeat * The number of times each one of the {@link FlowTwoRows} / * {@link FlowThreeRows} should appear consecutively in the * returned list. * @return The restrictive list of core ribbon band resize policies. */ public static List<RibbonBandResizePolicy> getCoreFlowPoliciesRestrictive( JFlowRibbonBand ribbonBand, int stepsToRepeat) { List<RibbonBandResizePolicy> result = new ArrayList<RibbonBandResizePolicy>(); for (int i = 0; i < stepsToRepeat; i++) { result.add(new FlowTwoRows(ribbonBand.getControlPanel())); } for (int i = 0; i < stepsToRepeat; i++) { result.add(new FlowThreeRows(ribbonBand.getControlPanel())); } result .add(new IconRibbonBandResizePolicy(ribbonBand .getControlPanel())); return result; } }