2
* Copyright (c) 2005-2010 Flamingo Kirill Grouchnikov. All Rights Reserved.
4
* Redistribution and use in source and binary forms, with or without
5
* modification, are permitted provided that the following conditions are met:
7
* o Redistributions of source code must retain the above copyright notice,
8
* this list of conditions and the following disclaimer.
10
* o Redistributions in binary form must reproduce the above copyright notice,
11
* this list of conditions and the following disclaimer in the documentation
12
* and/or other materials provided with the distribution.
14
* o Neither the name of Flamingo Kirill Grouchnikov nor the names of
15
* its contributors may be used to endorse or promote products derived
16
* from this software without specific prior written permission.
18
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
19
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
20
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
21
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
22
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
23
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
24
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
25
* OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
26
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
27
* OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
28
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30
package org.pushingpixels.flamingo.internal.ui.ribbon;
33
import java.awt.event.*;
34
import java.beans.PropertyChangeEvent;
35
import java.beans.PropertyChangeListener;
36
import java.util.List;
39
import javax.swing.border.Border;
40
import javax.swing.border.EmptyBorder;
41
import javax.swing.plaf.*;
43
import org.pushingpixels.flamingo.api.common.*;
44
import org.pushingpixels.flamingo.api.common.icon.ResizableIcon;
45
import org.pushingpixels.flamingo.api.common.popup.*;
46
import org.pushingpixels.flamingo.api.ribbon.*;
47
import org.pushingpixels.flamingo.api.ribbon.resize.IconRibbonBandResizePolicy;
48
import org.pushingpixels.flamingo.api.ribbon.resize.RibbonBandResizePolicy;
49
import org.pushingpixels.flamingo.internal.ui.common.BasicCommandButtonUI;
50
import org.pushingpixels.flamingo.internal.utils.FlamingoUtilities;
51
import org.pushingpixels.flamingo.internal.utils.RenderingUtils;
52
import org.pushingpixels.trident.Timeline;
53
import org.pushingpixels.trident.swing.SwingRepaintCallback;
56
* Basic UI for ribbon band {@link JRibbonBand}.
58
* @author Kirill Grouchnikov
61
public class BasicRibbonBandUI extends RibbonBandUI {
63
* The associated ribbon band.
65
protected AbstractRibbonBand<AbstractBandControlPanel> ribbonBand;
68
* The button for collapsed state.
70
protected JCommandButton collapsedButton;
73
* The band expand button. Is visible when the
74
* {@link JRibbonBand#getExpandActionListener()} of the associated ribbon
75
* band is not <code>null</code>.
77
protected AbstractCommandButton expandButton;
79
protected float rolloverAmount;
81
protected Timeline rolloverTimeline;
84
* Mouse listener on the associated ribbon band.
86
protected MouseListener mouseListener;
89
* Listens to property changes on the associated ribbon band.
91
protected PropertyChangeListener propertyChangeListener;
94
* Action listener on the expand button.
96
protected ActionListener expandButtonActionListener;
99
* Popup panel that shows the contents of the ribbon band when it is in a
102
* @author Kirill Grouchnikov
104
protected static class CollapsedButtonPopupPanel extends JPopupPanel {
106
* The main component of <code>this</code> popup panel. Can be
109
protected Component component;
112
* Creates popup gallery with the specified component.
115
* The main component of the popup gallery.
116
* @param originalSize
117
* The original dimension of the main component.
119
public CollapsedButtonPopupPanel(Component component,
120
Dimension originalSize) {
121
this.component = component;
122
this.setLayout(new BorderLayout());
123
this.add(component, BorderLayout.CENTER);
124
// System.out.println("Popup dim is " + originalSize);
125
this.setPreferredSize(originalSize);
126
this.setSize(originalSize);
130
* Removes the main component of <code>this</code> popup gallery.
132
* @return The removed main component.
134
public Component removeComponent() {
135
this.remove(this.component);
136
return this.component;
140
* Returns the main component of <code>this</code> popup gallery.
142
* @return The main component.
144
public Component getComponent() {
145
return this.component;
152
* @see javax.swing.plaf.ComponentUI#createUI(javax.swing.JComponent)
154
public static ComponentUI createUI(JComponent c) {
155
return new BasicRibbonBandUI();
161
* @see javax.swing.plaf.ComponentUI#installUI(javax.swing.JComponent)
164
public void installUI(JComponent c) {
165
//noinspection unchecked
166
this.ribbonBand = (AbstractRibbonBand<AbstractBandControlPanel>) c;
168
this.rolloverTimeline = new Timeline(this);
169
this.rolloverTimeline.addPropertyToInterpolate("rolloverAmount", 0.0f,
171
this.rolloverTimeline.addCallback(new SwingRepaintCallback(
173
this.rolloverTimeline.setDuration(250);
178
c.setLayout(createLayoutManager());
179
AWTRibbonEventListener.install();
185
* @see javax.swing.plaf.ComponentUI#uninstallUI(javax.swing.JComponent)
188
public void uninstallUI(JComponent c) {
190
uninstallListeners();
192
uninstallComponents();
193
if (!AWTRibbonEventListener.uninstall()) {
194
// should remove other methods of tracking
199
* Installs default parameters on the associated ribbon band.
201
protected void installDefaults() {
202
Color bg = this.ribbonBand.getBackground();
203
if (bg == null || bg instanceof UIResource) {
204
this.ribbonBand.setBackground(FlamingoUtilities.getColor(
205
Color.lightGray, "RibbonBand.background",
206
"Panel.background"));
209
Border b = this.ribbonBand.getBorder();
210
if (b == null || b instanceof UIResource) {
211
Border toSet = UIManager.getBorder("RibbonBand.border");
213
toSet = new BorderUIResource(new RoundBorder(FlamingoUtilities
214
.getBorderColor(), new Insets(2, 2, 2, 2)));
215
this.ribbonBand.setBorder(toSet);
220
* Installs subcomponents on the associated ribbon band.
222
protected void installComponents() {
223
this.collapsedButton = new JCommandButton(this.ribbonBand.getTitle(),
224
this.ribbonBand.getIcon());
225
this.collapsedButton.setDisplayState(CommandButtonDisplayState.BIG);
227
.setCommandButtonKind(JCommandButton.CommandButtonKind.POPUP_ONLY);
228
this.collapsedButton.setPopupKeyTip(this.ribbonBand
229
.getCollapsedStateKeyTip());
230
this.ribbonBand.add(this.collapsedButton);
232
if (this.ribbonBand.getExpandActionListener() != null) {
233
this.expandButton = this.createExpandButton();
234
this.ribbonBand.add(this.expandButton);
239
* Creates the expand button for the associated ribbon band.
241
* @return Expand button for the associated ribbon band.
243
protected JCommandButton createExpandButton() {
244
ResizableIcon icon = FlamingoUtilities
245
.getRibbonBandExpandIcon(this.ribbonBand);
246
JCommandButton result = new JCommandButton(null, icon);
247
result.setFlat(true);
248
result.putClientProperty(BasicCommandButtonUI.EMULATE_SQUARE_BUTTON,
250
result.setBorder(new EmptyBorder(3, 2, 3, 2));
251
result.setActionKeyTip(this.ribbonBand.getExpandButtonKeyTip());
252
result.setActionRichTooltip(this.ribbonBand
253
.getExpandButtonRichTooltip());
257
protected void syncExpandButtonIcon() {
258
this.expandButton.setIcon(FlamingoUtilities
259
.getRibbonBandExpandIcon(this.ribbonBand));
263
* Installs listeners on the associated ribbon band.
265
protected void installListeners() {
266
// without this empty adapter, the global listener never
267
// gets mouse entered events on the ribbon band
268
this.mouseListener = new MouseAdapter() {
270
this.ribbonBand.addMouseListener(this.mouseListener);
272
configureExpandButton();
274
this.propertyChangeListener = new PropertyChangeListener() {
276
public void propertyChange(PropertyChangeEvent evt) {
277
if ("title".equals(evt.getPropertyName())) {
278
collapsedButton.setText((String) evt.getNewValue());
279
ribbonBand.repaint();
280
} else if ("icon".equals(evt.getPropertyName())) {
281
collapsedButton.setIcon((ResizableIcon) evt.getNewValue());
282
ribbonBand.repaint();
283
} else if ("expandButtonKeyTip".equals(evt.getPropertyName())) {
284
if (expandButton != null) {
286
.setActionKeyTip((String) evt.getNewValue());
288
} else if ("expandButtonRichTooltip".equals(evt.getPropertyName())) {
289
if (expandButton != null) {
290
expandButton.setActionRichTooltip((RichTooltip) evt
293
} else if ("collapsedStateKeyTip".equals(evt.getPropertyName())) {
294
if (collapsedButton != null) {
295
collapsedButton.setPopupKeyTip((String) evt
298
} else if ("expandActionListener".equals(evt.getPropertyName())) {
299
ActionListener oldListener = (ActionListener) evt
301
ActionListener newListener = (ActionListener) evt
304
if ((oldListener != null) && (newListener == null)) {
306
unconfigureExpandButton();
307
ribbonBand.remove(expandButton);
309
ribbonBand.revalidate();
310
} else if ((oldListener == null) && (newListener != null)) {
312
expandButton = createExpandButton();
313
configureExpandButton();
314
ribbonBand.add(expandButton);
315
ribbonBand.revalidate();
316
} else if ((oldListener != null) && (newListener != null)) {
317
// need to reconfigure
318
expandButton.removeActionListener(oldListener);
319
expandButton.addActionListener(newListener);
321
} else if ("componentOrientation".equals(evt.getPropertyName())) {
322
if (expandButton != null) {
323
syncExpandButtonIcon();
328
this.ribbonBand.addPropertyChangeListener(this.propertyChangeListener);
331
protected void configureExpandButton() {
332
if (this.expandButton != null) {
333
this.expandButton.addActionListener(this.ribbonBand
334
.getExpandActionListener());
336
this.expandButtonActionListener = new ActionListener() {
338
public void actionPerformed(ActionEvent e) {
339
SwingUtilities.invokeLater(new Runnable() {
342
trackMouseCrossing(false);
348
.addActionListener(this.expandButtonActionListener);
353
* Uninstalls default parameters from the associated ribbon band.
355
protected void uninstallDefaults() {
356
LookAndFeel.uninstallBorder(this.ribbonBand);
360
* Uninstalls components from the associated ribbon band.
362
protected void uninstallComponents() {
363
if (this.collapsedButton.isVisible()) {
364
// restore the control panel to the ribbon band.
365
CollapsedButtonPopupPanel popupPanel = (collapsedButton
366
.getPopupCallback() == null) ? null
367
: (CollapsedButtonPopupPanel) collapsedButton
368
.getPopupCallback().getPopupPanel(collapsedButton);
369
if (popupPanel != null) {
370
AbstractRibbonBand bandFromPopup = (AbstractRibbonBand) popupPanel
372
ribbonBand.setControlPanel(bandFromPopup.getControlPanel());
373
ribbonBand.setPopupRibbonBand(null);
374
collapsedButton.setPopupCallback(null);
378
this.ribbonBand.remove(this.collapsedButton);
379
this.collapsedButton = null;
381
if (this.expandButton != null)
382
this.ribbonBand.remove(this.expandButton);
384
this.expandButton = null;
385
this.ribbonBand = null;
389
* Uninstalls listeners from the associated ribbon band.
391
protected void uninstallListeners() {
393
.removePropertyChangeListener(this.propertyChangeListener);
394
this.propertyChangeListener = null;
396
this.ribbonBand.removeMouseListener(this.mouseListener);
397
this.mouseListener = null;
399
unconfigureExpandButton();
402
protected void unconfigureExpandButton() {
403
if (this.expandButton != null) {
405
.removeActionListener(this.expandButtonActionListener);
406
this.expandButtonActionListener = null;
407
this.expandButton.removeActionListener(this.ribbonBand
408
.getExpandActionListener());
413
* Invoked by <code>installUI</code> to create a layout manager object to
414
* manage the {@link JCommandButtonStrip}.
416
* @return a layout manager object
418
protected LayoutManager createLayoutManager() {
419
return new RibbonBandLayout();
423
* Layout for the ribbon band.
425
* @author Kirill Grouchnikov
427
private class RibbonBandLayout implements LayoutManager {
432
* @see java.awt.LayoutManager#addLayoutComponent(java.lang.String,
433
* java.awt.Component)
436
public void addLayoutComponent(String name, Component c) {
442
* @see java.awt.LayoutManager#removeLayoutComponent(java.awt.Component)
445
public void removeLayoutComponent(Component c) {
451
* @see java.awt.LayoutManager#preferredLayoutSize(java.awt.Container)
454
public Dimension preferredLayoutSize(Container c) {
455
Insets ins = c.getInsets();
456
AbstractBandControlPanel controlPanel = ribbonBand
458
boolean useCollapsedButton = (controlPanel == null)
459
|| (!controlPanel.isVisible());
460
int width = useCollapsedButton ? collapsedButton.getPreferredSize().width
461
: controlPanel.getPreferredSize().width;
462
int height = (useCollapsedButton ? collapsedButton
463
.getPreferredSize().height : controlPanel
464
.getPreferredSize().height)
465
+ getBandTitleHeight();
467
// System.out.println(ribbonBand.getTitle() + ":" + height);
469
// Preferred height of the ribbon band is:
470
// 1. Insets on top and bottom
471
// 2. Preferred height of the control panel
472
// 3. Preferred height of the band title panel
473
// System.out.println("Ribbon band pref = "
474
// + (height + ins.top + ins.bottom));
476
return new Dimension(width + 2 + ins.left + ins.right, height
477
+ ins.top + ins.bottom);
483
* @see java.awt.LayoutManager#minimumLayoutSize(java.awt.Container)
486
public Dimension minimumLayoutSize(Container c) {
487
Insets ins = c.getInsets();
488
AbstractBandControlPanel controlPanel = ribbonBand
490
boolean useCollapsedButton = (controlPanel == null)
491
|| (!controlPanel.isVisible());
492
int width = useCollapsedButton ? collapsedButton.getMinimumSize().width
493
: controlPanel.getMinimumSize().width;
494
int height = useCollapsedButton ? collapsedButton.getMinimumSize().height
495
+ getBandTitleHeight()
496
: controlPanel.getMinimumSize().height
497
+ getBandTitleHeight();
499
// System.out.println(useCollapsedButton + ":" + height);
501
// Preferred height of the ribbon band is:
502
// 1. Insets on top and bottom
503
// 2. Preferred height of the control panel
504
// 3. Preferred height of the band title panel
505
return new Dimension(width + 2 + ins.left + ins.right, height
506
+ ins.top + ins.bottom);
513
* @see java.awt.LayoutManager#layoutContainer(java.awt.Container)
516
public void layoutContainer(Container c) {
517
// System.out.println("Ribbon band real = " + c.getHeight());
520
Insets ins = c.getInsets();
522
int availableHeight = c.getHeight() - ins.top - ins.bottom;
523
RibbonBandResizePolicy resizePolicy = ((AbstractRibbonBand) c)
524
.getCurrentResizePolicy();
526
if (resizePolicy instanceof IconRibbonBandResizePolicy) {
527
collapsedButton.setVisible(true);
528
int w = collapsedButton.getPreferredSize().width;
529
// System.out.println("Width for collapsed of '"
530
// + ribbonBand.getTitle() + "' is " + w);
531
collapsedButton.setBounds((c.getWidth() - w) / 2, ins.top, w, c
533
- ins.top - ins.bottom);
535
// System.out.println("Collapsed " + collapsedButton.getHeight()
536
// + ":" + c.getHeight());
538
if (collapsedButton.getPopupCallback() == null) {
539
final AbstractRibbonBand<AbstractBandControlPanel> popupBand = ribbonBand.cloneBand();
540
popupBand.setControlPanel(ribbonBand.getControlPanel());
541
List<RibbonBandResizePolicy> resizePolicies = ribbonBand
542
.getResizePolicies();
543
popupBand.setResizePolicies(resizePolicies);
544
RibbonBandResizePolicy largest = resizePolicies.get(0);
545
popupBand.setCurrentResizePolicy(largest);
546
int gap = popupBand.getControlPanel().getUI()
548
final Dimension size = new Dimension(ins.left + ins.right
550
+ largest.getPreferredWidth(availableHeight, gap),
553
+ Math.max(c.getHeight(), ribbonBand
555
.getPreferredSize().height
556
+ getBandTitleHeight()));
557
// System.out.println(ribbonBand.getTitle() + ":"
558
// + size.getHeight());
559
collapsedButton.setPopupCallback(new PopupPanelCallback() {
561
public JPopupPanel getPopupPanel(
562
JCommandButton commandButton) {
563
return new CollapsedButtonPopupPanel(popupBand,
567
// collapsedButton.setGallery(new JPopupGallery(ribbonBand
568
// .getControlPanel(), size));
569
ribbonBand.setControlPanel(null);
570
ribbonBand.setPopupRibbonBand(popupBand);
573
if (expandButton != null)
574
expandButton.setBounds(0, 0, 0, 0);
579
if (collapsedButton.isVisible()) {
580
// was icon and now is normal band - have to restore the
582
CollapsedButtonPopupPanel popupPanel = (collapsedButton
583
.getPopupCallback() != null) ? (CollapsedButtonPopupPanel) collapsedButton
584
.getPopupCallback().getPopupPanel(collapsedButton)
586
if (popupPanel != null) {
587
AbstractRibbonBand bandFromPopup = (AbstractRibbonBand) popupPanel
589
ribbonBand.setControlPanel(bandFromPopup.getControlPanel());
590
ribbonBand.setPopupRibbonBand(null);
591
collapsedButton.setPopupCallback(null);
594
collapsedButton.setVisible(false);
596
AbstractBandControlPanel controlPanel = ribbonBand
598
controlPanel.setVisible(true);
599
controlPanel.setBounds(ins.left, ins.top, c.getWidth() - ins.left
600
- ins.right, c.getHeight() - getBandTitleHeight() - ins.top
602
controlPanel.doLayout();
604
if (expandButton != null) {
605
int ebpw = expandButton.getPreferredSize().width;
606
int ebph = expandButton.getPreferredSize().height;
607
int maxHeight = getBandTitleHeight() - 4;
608
if (ebph > maxHeight)
611
int expandButtonBottomY = c.getHeight()
612
- (getBandTitleHeight() - ebph) / 2;
614
boolean ltr = ribbonBand.getComponentOrientation()
618
expandButton.setBounds(c.getWidth() - ins.right - ebpw,
619
expandButtonBottomY - ebph, ebpw, ebph);
621
expandButton.setBounds(ins.left,
622
expandButtonBottomY - ebph, ebpw, ebph);
629
* Event listener to handle global ribbon events. Currently handles:
631
* <li>Marking a ribbon band to be hovered when the mouse moves over it.</li>
632
* <li>Mouse wheel events anywhere in the ribbon to rotate the selected
636
private static class AWTRibbonEventListener implements AWTEventListener {
637
private static AWTRibbonEventListener instance;
638
private int installCount = 0;
639
private AbstractRibbonBand lastHovered;
641
public static void install() {
642
if (instance == null) {
643
instance = new AWTRibbonEventListener();
644
java.security.AccessController
645
.doPrivileged(new java.security.PrivilegedAction<Object>() {
647
public Object run() {
650
.addAWTEventListener(
652
AWTEvent.MOUSE_EVENT_MASK
653
| AWTEvent.MOUSE_WHEEL_EVENT_MASK);
658
instance.installCount++;
661
public static boolean uninstall() {
662
if (instance != null) {
663
instance.installCount--;
664
if (instance.installCount == 0) {
666
Toolkit.getDefaultToolkit()
667
.removeAWTEventListener(instance);
676
public void eventDispatched(AWTEvent event) {
677
MouseEvent mouseEvent = (MouseEvent) event;
678
if (mouseEvent.getID() == MouseEvent.MOUSE_ENTERED) {
679
Object object = event.getSource();
680
if (!(object instanceof Component)) {
683
Component component = (Component) object;
684
AbstractRibbonBand band = (component instanceof AbstractRibbonBand) ? ((AbstractRibbonBand) component)
685
: (AbstractRibbonBand) SwingUtilities
686
.getAncestorOfClass(AbstractRibbonBand.class,
688
setHoveredBand(band);
691
if (mouseEvent.getID() == MouseEvent.MOUSE_WHEEL) {
692
if (PopupPanelManager.defaultManager().getShownPath().size() > 0)
695
Object object = event.getSource();
696
if (!(object instanceof Component)) {
699
Component component = (Component) object;
700
// get the deepest subcomponent at the event point
701
MouseWheelEvent mouseWheelEvent = (MouseWheelEvent) mouseEvent;
702
Component deepest = SwingUtilities.getDeepestComponentAt(
703
component, mouseWheelEvent.getX(), mouseWheelEvent
705
JRibbon ribbon = (JRibbon) SwingUtilities.getAncestorOfClass(
706
JRibbon.class, deepest);
707
if (ribbon != null) {
708
// if the mouse wheel scroll has happened inside a ribbon,
709
// ask the UI delegate to handle it
710
ribbon.getUI().handleMouseWheelEvent(
711
(MouseWheelEvent) mouseEvent);
716
private void setHoveredBand(AbstractRibbonBand band) {
717
if (lastHovered == band) {
718
return; // nothing to do as we are already over
720
if (lastHovered != null) {
721
// RibbonBandUI ui = lastHovered.getUI();
722
lastHovered.getUI().trackMouseCrossing(false);
726
band.getUI().trackMouseCrossing(true);
734
* @see javax.swing.plaf.ComponentUI#update(java.awt.Graphics,
735
* javax.swing.JComponent)
738
public void update(Graphics g, JComponent c) {
739
Graphics2D g2d = (Graphics2D) g.create();
740
RenderingUtils.installDesktopHints(g2d);
741
super.update(g2d, c);
748
* @see javax.swing.plaf.ComponentUI#paint(java.awt.Graphics,
749
* javax.swing.JComponent)
752
public void paint(Graphics g, JComponent c) {
753
Graphics2D graphics = (Graphics2D) g.create();
755
Insets ins = ribbonBand.getInsets();
757
this.paintBandBackground(graphics, new Rectangle(0, 0, c.getWidth(), c
760
if (!(ribbonBand.getCurrentResizePolicy() instanceof IconRibbonBandResizePolicy)) {
761
String title = ribbonBand.getTitle();
762
int titleHeight = getBandTitleHeight();
764
int bandTitleTopY = c.getHeight() - titleHeight;
766
this.paintBandTitleBackground(graphics, new Rectangle(0,
767
bandTitleTopY, c.getWidth(), titleHeight), title);
768
boolean ltr = ribbonBand.getComponentOrientation().isLeftToRight();
769
int titleWidth = c.getWidth() - 2 * ins.left - 2 * ins.right;
770
int titleX = 2 * ins.left;
771
if (expandButton != null) {
773
titleWidth = expandButton.getX() - 2 * ins.right - 2
776
titleWidth = ribbonBand.getWidth() - expandButton.getX()
777
- expandButton.getWidth() - 2 * ins.right - 2
779
titleX = expandButton.getX() + expandButton.getWidth() + 2
783
this.paintBandTitle(graphics, new Rectangle(titleX, bandTitleTopY,
784
titleWidth, titleHeight), title);
791
* Paints band title pane.
795
* @param titleRectangle
796
* Rectangle for the title pane.
800
protected void paintBandTitle(Graphics g, Rectangle titleRectangle,
802
// fix for issue 10 - empty ribbon band
803
if (titleRectangle.width <= 0)
806
Graphics2D graphics = (Graphics2D) g.create();
807
graphics.setFont(FlamingoUtilities.getFont(this.ribbonBand,
808
"Ribbon.font", "Button.font", "Panel.font"));
810
FontMetrics fm = graphics.getFontMetrics();
811
int y = titleRectangle.y - 2 + (titleRectangle.height + fm.getAscent())
814
int currLength = (int) fm.getStringBounds(title, g).getWidth();
815
String titleToPaint = title;
816
while (currLength > titleRectangle.width) {
817
title = title.substring(0, title.length() - 1);
818
titleToPaint = title + "...";
819
currLength = (int) fm.getStringBounds(titleToPaint, g).getWidth();
822
int x = titleRectangle.x + (titleRectangle.width - currLength) / 2;
823
graphics.setColor(this.ribbonBand.getForeground());
824
graphics.drawString(titleToPaint, x, y);
829
* Paints band title pane.
833
* @param titleRectangle
834
* Rectangle for the title pane.
838
protected void paintBandTitleBackground(Graphics g,
839
Rectangle titleRectangle, String title) {
841
Graphics2D g2d = (Graphics2D) g.create();
842
g2d.setComposite(AlphaComposite.SrcOver
843
.derive(0.7f + 0.3f * this.rolloverAmount));
845
FlamingoUtilities.renderSurface(g2d, this.ribbonBand, titleRectangle,
846
this.rolloverAmount > 0.0f, true, false);
851
public void setRolloverAmount(float rolloverAmount) {
852
this.rolloverAmount = rolloverAmount;
856
* Paints band background.
861
* Rectangle for the background.
863
protected void paintBandBackground(Graphics graphics, Rectangle toFill) {
864
graphics.setColor(ribbonBand.getBackground());
865
graphics.fillRect(toFill.x, toFill.y, toFill.width, toFill.height);
869
public float getRolloverAmount() {
870
return this.rolloverAmount;
874
* Returns the height of the ribbon band title area.
876
* @return The height of the ribbon band title area.
879
public int getBandTitleHeight() {
880
Font font = FlamingoUtilities.getFont(this.ribbonBand, "Ribbon.font",
881
"Button.font", "Panel.font");
883
// Nimbus - is that you?
884
font = new JLabel().getFont();
886
int result = font.getSize() + 5;
893
* Round border for the ribbon bands.
895
* @author Kirill Grouchnikov
897
protected static class RoundBorder implements Border {
901
protected Color color;
906
protected Insets insets;
909
* Creates the new border.
916
public RoundBorder(Color color, Insets insets) {
918
this.insets = insets;
922
public Insets getBorderInsets(Component c) {
927
public boolean isBorderOpaque() {
932
public void paintBorder(Component c, Graphics g, int x, int y,
933
int width, int height) {
934
Graphics2D g2d = (Graphics2D) g.create();
935
g2d.setColor(this.color);
936
g2d.drawRoundRect(x, y, width - 1, height - 1, 3, 3);
943
public int getPreferredCollapsedWidth() {
944
return this.collapsedButton.getPreferredSize().width + 2;
948
public void trackMouseCrossing(boolean isMouseIn) {
950
this.rolloverTimeline.play();
952
this.rolloverTimeline.playReverse();
954
this.ribbonBand.repaint();
958
* This method is for unit tests only and should not be called by the
961
* @return The expand button of the matching ribbon band.
964
public AbstractCommandButton getExpandButton() {
965
return this.expandButton;
969
* This method is for unit tests only and should not be called by the
972
* @return The expand button of the matching ribbon band.
975
public AbstractCommandButton getCollapsedButton() {
976
return this.collapsedButton;