/*
* 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.color.ColorSpace;
import java.awt.image.ColorConvertOp;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import javax.swing.*;
import javax.swing.plaf.ComponentUI;
import org.pushingpixels.flamingo.api.common.HorizontalAlignment;
import org.pushingpixels.flamingo.api.common.icon.FilteredResizableIcon;
import org.pushingpixels.flamingo.api.common.icon.ResizableIcon;
import org.pushingpixels.flamingo.api.ribbon.JRibbonComponent;
import org.pushingpixels.flamingo.api.ribbon.RibbonElementPriority;
public class BasicRibbonComponentUI extends RibbonComponentUI {
/**
* The associated ribbon component.
*/
protected JRibbonComponent ribbonComponent;
protected JLabel captionLabel;
protected PropertyChangeListener propertyChangeListener;
protected ResizableIcon disabledIcon;
/*
* (non-Javadoc)
*
* @see javax.swing.plaf.ComponentUI#createUI(javax.swing.JComponent)
*/
public static ComponentUI createUI(JComponent c) {
return new BasicRibbonComponentUI();
}
/*
* (non-Javadoc)
*
* @see javax.swing.plaf.ComponentUI#installUI(javax.swing.JComponent)
*/
@Override
public void installUI(JComponent c) {
this.ribbonComponent = (JRibbonComponent) c;
installDefaults();
installComponents();
installListeners();
c.setLayout(createLayoutManager());
}
/*
* (non-Javadoc)
*
* @see javax.swing.plaf.ComponentUI#uninstallUI(javax.swing.JComponent)
*/
@Override
public void uninstallUI(JComponent c) {
c.setLayout(null);
uninstallListeners();
uninstallDefaults();
uninstallComponents();
}
/**
* Installs default parameters on the associated ribbon component.
*/
protected void installDefaults() {
if (!this.ribbonComponent.isSimpleWrapper()) {
ResizableIcon icon = this.ribbonComponent.getIcon();
if (icon != null) {
icon.setDimension(new Dimension(16, 16));
this.disabledIcon = createDisabledIcon();
}
}
this.ribbonComponent.getMainComponent().setOpaque(false);
this.ribbonComponent.setOpaque(false);
}
/**
* Installs subcomponents on the associated ribbon component.
*/
protected void installComponents() {
this.captionLabel = new JLabel(this.ribbonComponent.getCaption());
this.captionLabel.setEnabled(this.ribbonComponent.isEnabled());
this.ribbonComponent.add(this.captionLabel);
JComponent mainComponent = this.ribbonComponent.getMainComponent();
this.ribbonComponent.add(mainComponent);
}
/**
* Installs listeners on the associated ribbon component.
*/
protected void installListeners() {
this.propertyChangeListener = new PropertyChangeListener() {
@Override
public void propertyChange(PropertyChangeEvent evt) {
if ("enabled".equals(evt.getPropertyName())) {
boolean isEnabled = (Boolean) evt.getNewValue();
ribbonComponent.getMainComponent().setEnabled(isEnabled);
if (!ribbonComponent.isSimpleWrapper()) {
captionLabel.setEnabled(isEnabled);
}
ribbonComponent.repaint();
}
if ("caption".equals(evt.getPropertyName())) {
captionLabel.setText((String) evt.getNewValue());
}
if ("displayPriority".equals(evt.getPropertyName())) {
ribbonComponent.revalidate();
ribbonComponent.doLayout();
}
}
};
this.ribbonComponent
.addPropertyChangeListener(this.propertyChangeListener);
}
/**
* Uninstalls default parameters from the associated ribbon component.
*/
protected void uninstallDefaults() {
}
/**
* Uninstalls components from the associated ribbon component.
*/
protected void uninstallComponents() {
JComponent mainComponent = this.ribbonComponent.getMainComponent();
this.ribbonComponent.remove(mainComponent);
this.ribbonComponent.remove(this.captionLabel);
this.captionLabel = null;
}
/**
* Uninstalls listeners from the associated ribbon component.
*/
protected void uninstallListeners() {
this.ribbonComponent
.removePropertyChangeListener(this.propertyChangeListener);
this.propertyChangeListener = null;
}
@Override
public Point getKeyTipAnchorCenterPoint() {
if (this.ribbonComponent.isSimpleWrapper()) {
return new Point(
this.ribbonComponent.getMainComponent().getX() + 10,
this.ribbonComponent.getHeight());
} else {
return new Point(this.captionLabel.getX(), this.ribbonComponent
.getHeight());
}
}
protected LayoutManager createLayoutManager() {
return new ExtComponentLayout();
}
protected class ExtComponentLayout implements LayoutManager {
@Override
public void addLayoutComponent(String name, Component comp) {
}
@Override
public void removeLayoutComponent(Component comp) {
}
@Override
public Dimension minimumLayoutSize(Container parent) {
Insets ins = ribbonComponent.getInsets();
JComponent mainComponent = ribbonComponent.getMainComponent();
Dimension minMain = mainComponent.getMinimumSize();
int width = ins.left;
int height = minMain.height;
if (isIconVisible(ribbonComponent.getDisplayPriority())) {
ResizableIcon icon = ribbonComponent.getIcon();
if (icon != null) {
width += (icon.getIconWidth() + getLayoutGap());
height = Math.max(height, icon.getIconHeight());
}
}
if (isCaptionVisible(ribbonComponent.getDisplayPriority())) {
Dimension minCaption = captionLabel.getMinimumSize();
width += (minCaption.width + getLayoutGap());
height = Math.max(height, minCaption.height);
}
width += minMain.width;
width += ins.right;
height += (ins.top + ins.bottom);
return new Dimension(width, height);
}
@Override
public Dimension preferredLayoutSize(Container parent) {
return getPreferredSize(ribbonComponent.getDisplayPriority());
}
@Override
public void layoutContainer(Container parent) {
JRibbonComponent ribbonComp = (JRibbonComponent) parent;
Insets ins = ribbonComp.getInsets();
int gap = getLayoutGap();
int availableHeight = ribbonComp.getHeight() - ins.top - ins.bottom;
int availableWidth = ribbonComp.getWidth() - ins.left - ins.right;
HorizontalAlignment horizAlignment = ribbonComp
.getHorizontalAlignment();
JComponent mainComp = ribbonComp.getMainComponent();
Dimension prefMainDim = mainComp.getPreferredSize();
int prefMainWidth = prefMainDim.width;
int finalHeight = Math.min(prefMainDim.height, availableHeight);
boolean ltr = ribbonComp.getComponentOrientation().isLeftToRight();
if (ribbonComp.isSimpleWrapper()) {
int finalMainWidth = Math.min(availableWidth, prefMainWidth);
int offset = availableWidth - prefMainWidth;
int topMain = ins.top + (availableHeight - finalHeight) / 2;
int x = ltr ? ins.left : ribbonComp.getWidth() - ins.right;
switch (horizAlignment) {
case LEADING:
if (ltr) {
mainComp.setBounds(x, topMain, finalMainWidth,
finalHeight);
} else {
mainComp.setBounds(x - finalMainWidth, topMain,
finalMainWidth, finalHeight);
}
break;
case TRAILING:
if (ltr) {
mainComp.setBounds(x + offset, topMain, finalMainWidth,
finalHeight);
} else {
mainComp.setBounds(x - finalMainWidth - offset,
topMain, finalMainWidth, finalHeight);
}
break;
case CENTER:
if (ltr) {
mainComp.setBounds(x + offset / 2, topMain,
finalMainWidth, finalHeight);
} else {
mainComp.setBounds(x - finalMainWidth - offset / 2,
topMain, finalMainWidth, finalHeight);
}
break;
case FILL:
if (ltr) {
mainComp.setBounds(x, topMain, availableWidth,
finalHeight);
} else {
mainComp.setBounds(x - availableWidth, topMain,
availableWidth, finalHeight);
}
break;
}
mainComp.doLayout();
} else {
int x = ltr ? ins.left : ribbonComp.getWidth() - ins.right;
if (isIconVisible(ribbonComponent.getDisplayPriority())) {
if (ribbonComp.getIcon() != null) {
// icon is painted separately
int iconW = ribbonComp.getIcon().getIconWidth();
x = ltr ? x + iconW + gap : x - iconW - gap;
}
}
if (isCaptionVisible(ribbonComponent.getDisplayPriority())) {
captionLabel.setVisible(true);
Dimension prefCaptionDim = captionLabel.getPreferredSize();
if (ltr) {
captionLabel
.setBounds(
x,
ins.top
+ (availableHeight - prefCaptionDim.height)
/ 2, prefCaptionDim.width,
prefCaptionDim.height);
x += (prefCaptionDim.width + gap);
} else {
captionLabel
.setBounds(
x - prefCaptionDim.width,
ins.top
+ (availableHeight - prefCaptionDim.height)
/ 2, prefCaptionDim.width,
prefCaptionDim.height);
x -= (prefCaptionDim.width + gap);
}
} else {
captionLabel.setVisible(false);
}
int topMain = ins.top + (availableHeight - finalHeight) / 2;
int finalMainWidth = ltr ? Math.min(ribbonComp.getWidth()
- ins.right - x, prefMainWidth) : Math.min(
x - ins.left, prefMainWidth);
int offset = ltr ? ribbonComp.getWidth() - ins.right - x
- prefMainWidth : x - prefMainWidth - ins.left;
switch (horizAlignment) {
case LEADING:
if (ltr) {
mainComp.setBounds(x, topMain, finalMainWidth,
finalHeight);
} else {
mainComp.setBounds(x - finalMainWidth, topMain,
finalMainWidth, finalHeight);
}
break;
case TRAILING:
if (ltr) {
mainComp.setBounds(x + offset, topMain, finalMainWidth,
finalHeight);
} else {
mainComp.setBounds(x - finalMainWidth - offset,
topMain, finalMainWidth, finalHeight);
}
break;
case CENTER:
if (ltr) {
mainComp.setBounds(x + offset / 2, topMain,
finalMainWidth, finalHeight);
} else {
mainComp.setBounds(x - finalMainWidth - offset / 2,
topMain, finalMainWidth, finalHeight);
}
break;
case FILL:
if (ltr) {
mainComp.setBounds(x, topMain, ribbonComp.getWidth()
- ins.right - x, finalHeight);
} else {
mainComp.setBounds(ins.left, topMain, x - ins.left,
finalHeight);
}
break;
}
mainComp.doLayout();
}
}
}
@Override
public void paint(Graphics g, JComponent c) {
JRibbonComponent ribbonComp = (JRibbonComponent) c;
if (isIconVisible(this.ribbonComponent.getDisplayPriority())) {
Insets ins = ribbonComp.getInsets();
ResizableIcon icon = ribbonComp.isEnabled() ? ribbonComp.getIcon()
: this.disabledIcon;
if (icon != null) {
int availableHeight = ribbonComp.getHeight() - ins.top
- ins.bottom;
int iconY = Math.max(0, ins.top
+ (availableHeight - icon.getIconHeight()) / 2);
if (ribbonComp.getComponentOrientation().isLeftToRight()) {
paintIcon(g, ribbonComp, icon, ins.left, iconY);
} else {
paintIcon(g, ribbonComp, icon, ribbonComp.getWidth()
- ins.right - icon.getIconWidth(), iconY);
}
}
}
}
protected void paintIcon(Graphics g, JRibbonComponent ribbonComp,
Icon icon, int x, int y) {
icon.paintIcon(ribbonComp, g, x, y);
}
protected int getLayoutGap() {
return 4;
}
protected ResizableIcon createDisabledIcon() {
return new FilteredResizableIcon(this.ribbonComponent.getIcon(),
new ColorConvertOp(ColorSpace.getInstance(ColorSpace.CS_GRAY),
null));
}
protected boolean isIconVisible(RibbonElementPriority displayPriority) {
if (this.ribbonComponent.isSimpleWrapper())
return false;
return (displayPriority == RibbonElementPriority.TOP)
|| (displayPriority == RibbonElementPriority.MEDIUM);
}
protected boolean isCaptionVisible(RibbonElementPriority displayPriority) {
if (this.ribbonComponent.isSimpleWrapper())
return false;
return (displayPriority == RibbonElementPriority.TOP);
}
@Override
public Dimension getPreferredSize(RibbonElementPriority priority) {
Insets ins = ribbonComponent.getInsets();
JComponent mainComponent = ribbonComponent.getMainComponent();
Dimension prefMain = mainComponent.getPreferredSize();
int width = ins.left;
int height = prefMain.height;
if (isIconVisible(priority)) {
ResizableIcon icon = ribbonComponent.getIcon();
if (icon != null) {
width += (icon.getIconWidth() + getLayoutGap());
height = Math.max(height, icon.getIconHeight());
}
}
if (isCaptionVisible(priority)) {
Dimension prefCaption = captionLabel.getPreferredSize();
width += (prefCaption.width + getLayoutGap());
height = Math.max(height, prefCaption.height);
}
width += prefMain.width;
width += ins.right;
height += (ins.top + ins.bottom);
return new Dimension(width, height);
}
}