org.pushingpixels.flamingo.internal.ui.ribbon.BasicRibbonBandUI Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of flamengo Show documentation
Show all versions of flamengo Show documentation
Flamingo Swing component suite
The newest version!
/*
* 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.internal.ui.ribbon;
import java.awt.*;
import java.awt.event.*;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.util.List;
import javax.swing.*;
import javax.swing.border.Border;
import javax.swing.border.EmptyBorder;
import javax.swing.plaf.*;
import org.pushingpixels.flamingo.api.common.*;
import org.pushingpixels.flamingo.api.common.icon.ResizableIcon;
import org.pushingpixels.flamingo.api.common.popup.*;
import org.pushingpixels.flamingo.api.ribbon.*;
import org.pushingpixels.flamingo.api.ribbon.resize.IconRibbonBandResizePolicy;
import org.pushingpixels.flamingo.api.ribbon.resize.RibbonBandResizePolicy;
import org.pushingpixels.flamingo.internal.ui.common.BasicCommandButtonUI;
import org.pushingpixels.flamingo.internal.utils.FlamingoUtilities;
import org.pushingpixels.flamingo.internal.utils.RenderingUtils;
import org.pushingpixels.trident.Timeline;
import org.pushingpixels.trident.swing.SwingRepaintCallback;
/**
* Basic UI for ribbon band {@link JRibbonBand}.
*
* @author Kirill Grouchnikov
* @author Matt Nathan
*/
public class BasicRibbonBandUI extends RibbonBandUI {
/**
* The associated ribbon band.
*/
protected AbstractRibbonBand ribbonBand;
/**
* The button for collapsed state.
*/
protected JCommandButton collapsedButton;
/**
* The band expand button. Is visible when the
* {@link JRibbonBand#getExpandActionListener()} of the associated ribbon
* band is not null
.
*/
protected AbstractCommandButton expandButton;
protected float rolloverAmount;
protected Timeline rolloverTimeline;
/**
* Mouse listener on the associated ribbon band.
*/
protected MouseListener mouseListener;
/**
* Listens to property changes on the associated ribbon band.
*/
protected PropertyChangeListener propertyChangeListener;
/**
* Action listener on the expand button.
*/
protected ActionListener expandButtonActionListener;
/**
* Popup panel that shows the contents of the ribbon band when it is in a
* collapsed state.
*
* @author Kirill Grouchnikov
*/
protected static class CollapsedButtonPopupPanel extends JPopupPanel {
/**
* The main component of this
popup panel. Can be
* null
.
*/
protected Component component;
/**
* Creates popup gallery with the specified component.
*
* @param component
* The main component of the popup gallery.
* @param originalSize
* The original dimension of the main component.
*/
public CollapsedButtonPopupPanel(Component component,
Dimension originalSize) {
this.component = component;
this.setLayout(new BorderLayout());
this.add(component, BorderLayout.CENTER);
// System.out.println("Popup dim is " + originalSize);
this.setPreferredSize(originalSize);
this.setSize(originalSize);
}
/**
* Removes the main component of this
popup gallery.
*
* @return The removed main component.
*/
public Component removeComponent() {
this.remove(this.component);
return this.component;
}
/**
* Returns the main component of this
popup gallery.
*
* @return The main component.
*/
public Component getComponent() {
return this.component;
}
}
/*
* (non-Javadoc)
*
* @see javax.swing.plaf.ComponentUI#createUI(javax.swing.JComponent)
*/
public static ComponentUI createUI(JComponent c) {
return new BasicRibbonBandUI();
}
/*
* (non-Javadoc)
*
* @see javax.swing.plaf.ComponentUI#installUI(javax.swing.JComponent)
*/
@Override
public void installUI(JComponent c) {
this.ribbonBand = (AbstractRibbonBand) c;
this.rolloverTimeline = new Timeline(this);
this.rolloverTimeline.addPropertyToInterpolate("rolloverAmount", 0.0f,
1.0f);
this.rolloverTimeline.addCallback(new SwingRepaintCallback(
this.ribbonBand));
this.rolloverTimeline.setDuration(250);
installDefaults();
installComponents();
installListeners();
c.setLayout(createLayoutManager());
AWTRibbonEventListener.install();
}
/*
* (non-Javadoc)
*
* @see javax.swing.plaf.ComponentUI#uninstallUI(javax.swing.JComponent)
*/
@Override
public void uninstallUI(JComponent c) {
c.setLayout(null);
uninstallListeners();
uninstallDefaults();
uninstallComponents();
if (!AWTRibbonEventListener.uninstall()) {
// should remove other methods of tracking
}
}
/**
* Installs default parameters on the associated ribbon band.
*/
protected void installDefaults() {
Color bg = this.ribbonBand.getBackground();
if (bg == null || bg instanceof UIResource) {
this.ribbonBand.setBackground(FlamingoUtilities.getColor(
Color.lightGray, "RibbonBand.background",
"Panel.background"));
}
Border b = this.ribbonBand.getBorder();
if (b == null || b instanceof UIResource) {
Border toSet = UIManager.getBorder("RibbonBand.border");
if (toSet == null)
toSet = new BorderUIResource(new RoundBorder(FlamingoUtilities
.getBorderColor(), new Insets(2, 2, 2, 2)));
this.ribbonBand.setBorder(toSet);
}
}
/**
* Installs subcomponents on the associated ribbon band.
*/
protected void installComponents() {
this.collapsedButton = new JCommandButton(this.ribbonBand.getTitle(),
this.ribbonBand.getIcon());
this.collapsedButton.setDisplayState(CommandButtonDisplayState.BIG);
this.collapsedButton
.setCommandButtonKind(JCommandButton.CommandButtonKind.POPUP_ONLY);
this.collapsedButton.setPopupKeyTip(this.ribbonBand
.getCollapsedStateKeyTip());
this.ribbonBand.add(this.collapsedButton);
if (this.ribbonBand.getExpandActionListener() != null) {
this.expandButton = this.createExpandButton();
this.ribbonBand.add(this.expandButton);
}
}
/**
* Creates the expand button for the associated ribbon band.
*
* @return Expand button for the associated ribbon band.
*/
protected JCommandButton createExpandButton() {
ResizableIcon icon = FlamingoUtilities
.getRibbonBandExpandIcon(this.ribbonBand);
JCommandButton result = new JCommandButton(null, icon);
result.setFlat(true);
result.putClientProperty(BasicCommandButtonUI.EMULATE_SQUARE_BUTTON,
Boolean.TRUE);
result.setBorder(new EmptyBorder(3, 2, 3, 2));
result.setActionKeyTip(this.ribbonBand.getExpandButtonKeyTip());
result.setActionRichTooltip(this.ribbonBand
.getExpandButtonRichTooltip());
return result;
}
protected void syncExpandButtonIcon() {
this.expandButton.setIcon(FlamingoUtilities
.getRibbonBandExpandIcon(this.ribbonBand));
}
/**
* Installs listeners on the associated ribbon band.
*/
protected void installListeners() {
// without this empty adapter, the global listener never
// gets mouse entered events on the ribbon band
this.mouseListener = new MouseAdapter() {
};
this.ribbonBand.addMouseListener(this.mouseListener);
configureExpandButton();
this.propertyChangeListener = new PropertyChangeListener() {
@Override
public void propertyChange(PropertyChangeEvent evt) {
if ("title".equals(evt.getPropertyName()))
ribbonBand.repaint();
if ("expandButtonKeyTip".equals(evt.getPropertyName())) {
if (expandButton != null) {
expandButton
.setActionKeyTip((String) evt.getNewValue());
}
}
if ("expandButtonRichTooltip".equals(evt.getPropertyName())) {
if (expandButton != null) {
expandButton.setActionRichTooltip((RichTooltip) evt
.getNewValue());
}
}
if ("collapsedStateKeyTip".equals(evt.getPropertyName())) {
if (collapsedButton != null) {
collapsedButton.setPopupKeyTip((String) evt
.getNewValue());
}
}
if ("expandActionListener".equals(evt.getPropertyName())) {
ActionListener oldListener = (ActionListener) evt
.getOldValue();
ActionListener newListener = (ActionListener) evt
.getNewValue();
if ((oldListener != null) && (newListener == null)) {
// need to remove
unconfigureExpandButton();
ribbonBand.remove(expandButton);
expandButton = null;
ribbonBand.revalidate();
}
if ((oldListener == null) && (newListener != null)) {
// need to add
expandButton = createExpandButton();
configureExpandButton();
ribbonBand.add(expandButton);
ribbonBand.revalidate();
}
if ((oldListener != null) && (newListener != null)) {
// need to reconfigure
expandButton.removeActionListener(oldListener);
expandButton.addActionListener(newListener);
}
}
if ("componentOrientation".equals(evt.getPropertyName())) {
if (expandButton != null) {
syncExpandButtonIcon();
}
}
}
};
this.ribbonBand.addPropertyChangeListener(this.propertyChangeListener);
}
protected void configureExpandButton() {
if (this.expandButton != null) {
this.expandButton.addActionListener(this.ribbonBand
.getExpandActionListener());
this.expandButtonActionListener = new ActionListener() {
public void actionPerformed(ActionEvent e) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
trackMouseCrossing(false);
}
});
}
};
this.expandButton
.addActionListener(this.expandButtonActionListener);
}
}
/**
* Uninstalls default parameters from the associated ribbon band.
*/
protected void uninstallDefaults() {
LookAndFeel.uninstallBorder(this.ribbonBand);
}
/**
* Uninstalls components from the associated ribbon band.
*/
protected void uninstallComponents() {
if (this.collapsedButton.isVisible()) {
// restore the control panel to the ribbon band.
CollapsedButtonPopupPanel popupPanel = (collapsedButton
.getPopupCallback() == null) ? null
: (CollapsedButtonPopupPanel) collapsedButton
.getPopupCallback().getPopupPanel(collapsedButton);
if (popupPanel != null) {
AbstractRibbonBand bandFromPopup = (AbstractRibbonBand) popupPanel
.removeComponent();
ribbonBand.setControlPanel(bandFromPopup.getControlPanel());
ribbonBand.setPopupRibbonBand(null);
collapsedButton.setPopupCallback(null);
}
}
this.ribbonBand.remove(this.collapsedButton);
this.collapsedButton = null;
if (this.expandButton != null)
this.ribbonBand.remove(this.expandButton);
this.expandButton = null;
this.ribbonBand = null;
}
/**
* Uninstalls listeners from the associated ribbon band.
*/
protected void uninstallListeners() {
this.ribbonBand
.removePropertyChangeListener(this.propertyChangeListener);
this.propertyChangeListener = null;
this.ribbonBand.removeMouseListener(this.mouseListener);
this.mouseListener = null;
unconfigureExpandButton();
}
protected void unconfigureExpandButton() {
if (this.expandButton != null) {
this.expandButton
.removeActionListener(this.expandButtonActionListener);
this.expandButtonActionListener = null;
this.expandButton.removeActionListener(this.ribbonBand
.getExpandActionListener());
}
}
/**
* Invoked by installUI
to create a layout manager object to
* manage the {@link JCommandButtonStrip}.
*
* @return a layout manager object
*/
protected LayoutManager createLayoutManager() {
return new RibbonBandLayout();
}
/**
* Layout for the ribbon band.
*
* @author Kirill Grouchnikov
*/
private class RibbonBandLayout implements LayoutManager {
/*
* (non-Javadoc)
*
* @see java.awt.LayoutManager#addLayoutComponent(java.lang.String,
* java.awt.Component)
*/
public void addLayoutComponent(String name, Component c) {
}
/*
* (non-Javadoc)
*
* @see java.awt.LayoutManager#removeLayoutComponent(java.awt.Component)
*/
public void removeLayoutComponent(Component c) {
}
/*
* (non-Javadoc)
*
* @see java.awt.LayoutManager#preferredLayoutSize(java.awt.Container)
*/
public Dimension preferredLayoutSize(Container c) {
Insets ins = c.getInsets();
AbstractBandControlPanel controlPanel = ribbonBand
.getControlPanel();
boolean useCollapsedButton = (controlPanel == null)
|| (!controlPanel.isVisible());
int width = useCollapsedButton ? collapsedButton.getPreferredSize().width
: controlPanel.getPreferredSize().width;
int height = (useCollapsedButton ? collapsedButton
.getPreferredSize().height : controlPanel
.getPreferredSize().height)
+ getBandTitleHeight();
// System.out.println(ribbonBand.getTitle() + ":" + height);
// Preferred height of the ribbon band is:
// 1. Insets on top and bottom
// 2. Preferred height of the control panel
// 3. Preferred height of the band title panel
// System.out.println("Ribbon band pref = "
// + (height + ins.top + ins.bottom));
return new Dimension(width + 2 + ins.left + ins.right, height
+ ins.top + ins.bottom);
}
/*
* (non-Javadoc)
*
* @see java.awt.LayoutManager#minimumLayoutSize(java.awt.Container)
*/
public Dimension minimumLayoutSize(Container c) {
Insets ins = c.getInsets();
AbstractBandControlPanel controlPanel = ribbonBand
.getControlPanel();
boolean useCollapsedButton = (controlPanel == null)
|| (!controlPanel.isVisible());
int width = useCollapsedButton ? collapsedButton.getMinimumSize().width
: controlPanel.getMinimumSize().width;
int height = useCollapsedButton ? collapsedButton.getMinimumSize().height
+ getBandTitleHeight()
: controlPanel.getMinimumSize().height
+ getBandTitleHeight();
// System.out.println(useCollapsedButton + ":" + height);
// Preferred height of the ribbon band is:
// 1. Insets on top and bottom
// 2. Preferred height of the control panel
// 3. Preferred height of the band title panel
return new Dimension(width + 2 + ins.left + ins.right, height
+ ins.top + ins.bottom);
}
/*
* (non-Javadoc)
*
* @see java.awt.LayoutManager#layoutContainer(java.awt.Container)
*/
public void layoutContainer(Container c) {
// System.out.println("Ribbon band real = " + c.getHeight());
if (!c.isVisible())
return;
Insets ins = c.getInsets();
int availableHeight = c.getHeight() - ins.top - ins.bottom;
RibbonBandResizePolicy resizePolicy = ((AbstractRibbonBand) c)
.getCurrentResizePolicy();
if (resizePolicy instanceof IconRibbonBandResizePolicy) {
collapsedButton.setVisible(true);
int w = collapsedButton.getPreferredSize().width;
// System.out.println("Width for collapsed of '"
// + ribbonBand.getTitle() + "' is " + w);
collapsedButton.setBounds((c.getWidth() - w) / 2, ins.top, w, c
.getHeight()
- ins.top - ins.bottom);
// System.out.println("Collapsed " + collapsedButton.getHeight()
// + ":" + c.getHeight());
if (collapsedButton.getPopupCallback() == null) {
final AbstractRibbonBand popupBand = ribbonBand.cloneBand();
popupBand.setControlPanel(ribbonBand.getControlPanel());
List resizePolicies = ribbonBand
.getResizePolicies();
popupBand.setResizePolicies(resizePolicies);
RibbonBandResizePolicy largest = resizePolicies.get(0);
popupBand.setCurrentResizePolicy(largest);
int gap = popupBand.getControlPanel().getUI()
.getLayoutGap();
final Dimension size = new Dimension(ins.left + ins.right
+ gap
+ largest.getPreferredWidth(availableHeight, gap),
ins.top
+ ins.bottom
+ Math.max(c.getHeight(), ribbonBand
.getControlPanel()
.getPreferredSize().height
+ getBandTitleHeight()));
// System.out.println(ribbonBand.getTitle() + ":"
// + size.getHeight());
collapsedButton.setPopupCallback(new PopupPanelCallback() {
@Override
public JPopupPanel getPopupPanel(
JCommandButton commandButton) {
return new CollapsedButtonPopupPanel(popupBand,
size);
}
});
// collapsedButton.setGallery(new JPopupGallery(ribbonBand
// .getControlPanel(), size));
ribbonBand.setControlPanel(null);
ribbonBand.setPopupRibbonBand(popupBand);
}
if (expandButton != null)
expandButton.setBounds(0, 0, 0, 0);
return;
}
if (collapsedButton.isVisible()) {
// was icon and now is normal band - have to restore the
// control panel
CollapsedButtonPopupPanel popupPanel = (collapsedButton
.getPopupCallback() != null) ? (CollapsedButtonPopupPanel) collapsedButton
.getPopupCallback().getPopupPanel(collapsedButton)
: null;
if (popupPanel != null) {
AbstractRibbonBand bandFromPopup = (AbstractRibbonBand) popupPanel
.removeComponent();
ribbonBand.setControlPanel(bandFromPopup.getControlPanel());
ribbonBand.setPopupRibbonBand(null);
collapsedButton.setPopupCallback(null);
}
}
collapsedButton.setVisible(false);
AbstractBandControlPanel controlPanel = ribbonBand
.getControlPanel();
controlPanel.setVisible(true);
controlPanel.setBounds(ins.left, ins.top, c.getWidth() - ins.left
- ins.right, c.getHeight() - getBandTitleHeight() - ins.top
- ins.bottom);
controlPanel.doLayout();
if (expandButton != null) {
int ebpw = expandButton.getPreferredSize().width;
int ebph = expandButton.getPreferredSize().height;
int maxHeight = getBandTitleHeight() - 4;
if (ebph > maxHeight)
ebph = maxHeight;
int expandButtonBottomY = c.getHeight()
- (getBandTitleHeight() - ebph) / 2;
boolean ltr = ribbonBand.getComponentOrientation()
.isLeftToRight();
if (ltr) {
expandButton.setBounds(c.getWidth() - ins.right - ebpw,
expandButtonBottomY - ebph, ebpw, ebph);
} else {
expandButton.setBounds(ins.left,
expandButtonBottomY - ebph, ebpw, ebph);
}
}
}
}
/**
* Event listener to handle global ribbon events. Currently handles:
*
* - Marking a ribbon band to be hovered when the mouse moves over it.
* - Mouse wheel events anywhere in the ribbon to rotate the selected
* task.
*
*/
private static class AWTRibbonEventListener implements AWTEventListener {
private static AWTRibbonEventListener instance;
private int installCount = 0;
private AbstractRibbonBand lastHovered;
public static void install() {
if (instance == null) {
instance = new AWTRibbonEventListener();
java.security.AccessController
.doPrivileged(new java.security.PrivilegedAction
© 2015 - 2025 Weber Informatics LLC | Privacy Policy