~ubuntu-branches/debian/stretch/insubstantial/stretch

« back to all changes in this revision

Viewing changes to flamingo/src/main/java/org/pushingpixels/flamingo/internal/ui/ribbon/BasicRibbonBandUI.java

  • Committer: Package Import Robot
  • Author(s): Felix Natter
  • Date: 2016-01-18 20:58:45 UTC
  • Revision ID: package-import@ubuntu.com-20160118205845-crbmrkda61qsi5qa
Tags: upstream-7.3+dfsg2
ImportĀ upstreamĀ versionĀ 7.3+dfsg2

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
 * Copyright (c) 2005-2010 Flamingo Kirill Grouchnikov. All Rights Reserved.
 
3
 *
 
4
 * Redistribution and use in source and binary forms, with or without 
 
5
 * modification, are permitted provided that the following conditions are met:
 
6
 * 
 
7
 *  o Redistributions of source code must retain the above copyright notice, 
 
8
 *    this list of conditions and the following disclaimer. 
 
9
 *     
 
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. 
 
13
 *     
 
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. 
 
17
 *     
 
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. 
 
29
 */
 
30
package org.pushingpixels.flamingo.internal.ui.ribbon;
 
31
 
 
32
import java.awt.*;
 
33
import java.awt.event.*;
 
34
import java.beans.PropertyChangeEvent;
 
35
import java.beans.PropertyChangeListener;
 
36
import java.util.List;
 
37
 
 
38
import javax.swing.*;
 
39
import javax.swing.border.Border;
 
40
import javax.swing.border.EmptyBorder;
 
41
import javax.swing.plaf.*;
 
42
 
 
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;
 
54
 
 
55
/**
 
56
 * Basic UI for ribbon band {@link JRibbonBand}.
 
57
 * 
 
58
 * @author Kirill Grouchnikov
 
59
 * @author Matt Nathan
 
60
 */
 
61
public class BasicRibbonBandUI extends RibbonBandUI {
 
62
        /**
 
63
         * The associated ribbon band.
 
64
         */
 
65
        protected AbstractRibbonBand<AbstractBandControlPanel> ribbonBand;
 
66
 
 
67
        /**
 
68
         * The button for collapsed state.
 
69
         */
 
70
        protected JCommandButton collapsedButton;
 
71
 
 
72
        /**
 
73
         * The band expand button. Is visible when the
 
74
         * {@link JRibbonBand#getExpandActionListener()} of the associated ribbon
 
75
         * band is not <code>null</code>.
 
76
         */
 
77
        protected AbstractCommandButton expandButton;
 
78
 
 
79
        protected float rolloverAmount;
 
80
 
 
81
        protected Timeline rolloverTimeline;
 
82
 
 
83
        /**
 
84
         * Mouse listener on the associated ribbon band.
 
85
         */
 
86
        protected MouseListener mouseListener;
 
87
 
 
88
        /**
 
89
         * Listens to property changes on the associated ribbon band.
 
90
         */
 
91
        protected PropertyChangeListener propertyChangeListener;
 
92
 
 
93
        /**
 
94
         * Action listener on the expand button.
 
95
         */
 
96
        protected ActionListener expandButtonActionListener;
 
97
 
 
98
        /**
 
99
         * Popup panel that shows the contents of the ribbon band when it is in a
 
100
         * collapsed state.
 
101
         * 
 
102
         * @author Kirill Grouchnikov
 
103
         */
 
104
        protected static class CollapsedButtonPopupPanel extends JPopupPanel {
 
105
                /**
 
106
                 * The main component of <code>this</code> popup panel. Can be
 
107
                 * <code>null</code>.
 
108
                 */
 
109
                protected Component component;
 
110
 
 
111
                /**
 
112
                 * Creates popup gallery with the specified component.
 
113
                 * 
 
114
                 * @param component
 
115
                 *            The main component of the popup gallery.
 
116
                 * @param originalSize
 
117
                 *            The original dimension of the main component.
 
118
                 */
 
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);
 
127
                }
 
128
 
 
129
                /**
 
130
                 * Removes the main component of <code>this</code> popup gallery.
 
131
                 * 
 
132
                 * @return The removed main component.
 
133
                 */
 
134
                public Component removeComponent() {
 
135
                        this.remove(this.component);
 
136
                        return this.component;
 
137
                }
 
138
 
 
139
                /**
 
140
                 * Returns the main component of <code>this</code> popup gallery.
 
141
                 * 
 
142
                 * @return The main component.
 
143
                 */
 
144
                public Component getComponent() {
 
145
                        return this.component;
 
146
                }
 
147
        }
 
148
 
 
149
        /*
 
150
         * (non-Javadoc)
 
151
         * 
 
152
         * @see javax.swing.plaf.ComponentUI#createUI(javax.swing.JComponent)
 
153
         */
 
154
        public static ComponentUI createUI(JComponent c) {
 
155
                return new BasicRibbonBandUI();
 
156
        }
 
157
 
 
158
        /*
 
159
         * (non-Javadoc)
 
160
         * 
 
161
         * @see javax.swing.plaf.ComponentUI#installUI(javax.swing.JComponent)
 
162
         */
 
163
        @Override
 
164
        public void installUI(JComponent c) {
 
165
        //noinspection unchecked
 
166
        this.ribbonBand = (AbstractRibbonBand<AbstractBandControlPanel>) c;
 
167
 
 
168
                this.rolloverTimeline = new Timeline(this);
 
169
                this.rolloverTimeline.addPropertyToInterpolate("rolloverAmount", 0.0f,
 
170
                                1.0f);
 
171
                this.rolloverTimeline.addCallback(new SwingRepaintCallback(
 
172
                                this.ribbonBand));
 
173
                this.rolloverTimeline.setDuration(250);
 
174
 
 
175
                installDefaults();
 
176
                installComponents();
 
177
                installListeners();
 
178
                c.setLayout(createLayoutManager());
 
179
                AWTRibbonEventListener.install();
 
180
        }
 
181
 
 
182
        /*
 
183
         * (non-Javadoc)
 
184
         * 
 
185
         * @see javax.swing.plaf.ComponentUI#uninstallUI(javax.swing.JComponent)
 
186
         */
 
187
        @Override
 
188
        public void uninstallUI(JComponent c) {
 
189
                c.setLayout(null);
 
190
                uninstallListeners();
 
191
                uninstallDefaults();
 
192
                uninstallComponents();
 
193
                if (!AWTRibbonEventListener.uninstall()) {
 
194
                        // should remove other methods of tracking
 
195
                }
 
196
        }
 
197
 
 
198
        /**
 
199
         * Installs default parameters on the associated ribbon band.
 
200
         */
 
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"));
 
207
                }
 
208
 
 
209
                Border b = this.ribbonBand.getBorder();
 
210
                if (b == null || b instanceof UIResource) {
 
211
                        Border toSet = UIManager.getBorder("RibbonBand.border");
 
212
                        if (toSet == null)
 
213
                                toSet = new BorderUIResource(new RoundBorder(FlamingoUtilities
 
214
                                                .getBorderColor(), new Insets(2, 2, 2, 2)));
 
215
                        this.ribbonBand.setBorder(toSet);
 
216
                }
 
217
        }
 
218
 
 
219
        /**
 
220
         * Installs subcomponents on the associated ribbon band.
 
221
         */
 
222
        protected void installComponents() {
 
223
                this.collapsedButton = new JCommandButton(this.ribbonBand.getTitle(),
 
224
                                this.ribbonBand.getIcon());
 
225
                this.collapsedButton.setDisplayState(CommandButtonDisplayState.BIG);
 
226
                this.collapsedButton
 
227
                                .setCommandButtonKind(JCommandButton.CommandButtonKind.POPUP_ONLY);
 
228
                this.collapsedButton.setPopupKeyTip(this.ribbonBand
 
229
                                .getCollapsedStateKeyTip());
 
230
                this.ribbonBand.add(this.collapsedButton);
 
231
 
 
232
                if (this.ribbonBand.getExpandActionListener() != null) {
 
233
                        this.expandButton = this.createExpandButton();
 
234
                        this.ribbonBand.add(this.expandButton);
 
235
                }
 
236
        }
 
237
 
 
238
        /**
 
239
         * Creates the expand button for the associated ribbon band.
 
240
         * 
 
241
         * @return Expand button for the associated ribbon band.
 
242
         */
 
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,
 
249
                                Boolean.TRUE);
 
250
                result.setBorder(new EmptyBorder(3, 2, 3, 2));
 
251
                result.setActionKeyTip(this.ribbonBand.getExpandButtonKeyTip());
 
252
                result.setActionRichTooltip(this.ribbonBand
 
253
                                .getExpandButtonRichTooltip());
 
254
                return result;
 
255
        }
 
256
 
 
257
        protected void syncExpandButtonIcon() {
 
258
                this.expandButton.setIcon(FlamingoUtilities
 
259
                                .getRibbonBandExpandIcon(this.ribbonBand));
 
260
        }
 
261
 
 
262
        /**
 
263
         * Installs listeners on the associated ribbon band.
 
264
         */
 
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() {
 
269
                };
 
270
                this.ribbonBand.addMouseListener(this.mouseListener);
 
271
 
 
272
                configureExpandButton();
 
273
 
 
274
                this.propertyChangeListener = new PropertyChangeListener() {
 
275
                        @Override
 
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) {
 
285
                                                expandButton
 
286
                                                                .setActionKeyTip((String) evt.getNewValue());
 
287
                                        }
 
288
                                } else if ("expandButtonRichTooltip".equals(evt.getPropertyName())) {
 
289
                                        if (expandButton != null) {
 
290
                                                expandButton.setActionRichTooltip((RichTooltip) evt
 
291
                                                                .getNewValue());
 
292
                                        }
 
293
                                } else if ("collapsedStateKeyTip".equals(evt.getPropertyName())) {
 
294
                                        if (collapsedButton != null) {
 
295
                                                collapsedButton.setPopupKeyTip((String) evt
 
296
                                                                .getNewValue());
 
297
                                        }
 
298
                                } else if ("expandActionListener".equals(evt.getPropertyName())) {
 
299
                                        ActionListener oldListener = (ActionListener) evt
 
300
                                                        .getOldValue();
 
301
                                        ActionListener newListener = (ActionListener) evt
 
302
                                                        .getNewValue();
 
303
 
 
304
                                        if ((oldListener != null) && (newListener == null)) {
 
305
                                                // need to remove
 
306
                                                unconfigureExpandButton();
 
307
                                                ribbonBand.remove(expandButton);
 
308
                                                expandButton = null;
 
309
                                                ribbonBand.revalidate();
 
310
                                        } else if ((oldListener == null) && (newListener != null)) {
 
311
                                                // need to add
 
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);
 
320
                                        }
 
321
                                } else if ("componentOrientation".equals(evt.getPropertyName())) {
 
322
                                        if (expandButton != null) {
 
323
                                                syncExpandButtonIcon();
 
324
                                        }
 
325
                                }
 
326
                        }
 
327
                };
 
328
                this.ribbonBand.addPropertyChangeListener(this.propertyChangeListener);
 
329
        }
 
330
 
 
331
        protected void configureExpandButton() {
 
332
                if (this.expandButton != null) {
 
333
                        this.expandButton.addActionListener(this.ribbonBand
 
334
                                        .getExpandActionListener());
 
335
 
 
336
                        this.expandButtonActionListener = new ActionListener() {
 
337
                                @Override
 
338
                public void actionPerformed(ActionEvent e) {
 
339
                                        SwingUtilities.invokeLater(new Runnable() {
 
340
                                                @Override
 
341
                        public void run() {
 
342
                                                        trackMouseCrossing(false);
 
343
                                                }
 
344
                                        });
 
345
                                }
 
346
                        };
 
347
                        this.expandButton
 
348
                                        .addActionListener(this.expandButtonActionListener);
 
349
                }
 
350
        }
 
351
 
 
352
        /**
 
353
         * Uninstalls default parameters from the associated ribbon band.
 
354
         */
 
355
        protected void uninstallDefaults() {
 
356
                LookAndFeel.uninstallBorder(this.ribbonBand);
 
357
        }
 
358
 
 
359
        /**
 
360
         * Uninstalls components from the associated ribbon band.
 
361
         */
 
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
 
371
                                                .removeComponent();
 
372
                                ribbonBand.setControlPanel(bandFromPopup.getControlPanel());
 
373
                                ribbonBand.setPopupRibbonBand(null);
 
374
                                collapsedButton.setPopupCallback(null);
 
375
                        }
 
376
                }
 
377
 
 
378
                this.ribbonBand.remove(this.collapsedButton);
 
379
                this.collapsedButton = null;
 
380
 
 
381
                if (this.expandButton != null)
 
382
                        this.ribbonBand.remove(this.expandButton);
 
383
 
 
384
                this.expandButton = null;
 
385
                this.ribbonBand = null;
 
386
        }
 
387
 
 
388
        /**
 
389
         * Uninstalls listeners from the associated ribbon band.
 
390
         */
 
391
        protected void uninstallListeners() {
 
392
                this.ribbonBand
 
393
                                .removePropertyChangeListener(this.propertyChangeListener);
 
394
                this.propertyChangeListener = null;
 
395
 
 
396
                this.ribbonBand.removeMouseListener(this.mouseListener);
 
397
                this.mouseListener = null;
 
398
 
 
399
                unconfigureExpandButton();
 
400
        }
 
401
 
 
402
        protected void unconfigureExpandButton() {
 
403
                if (this.expandButton != null) {
 
404
                        this.expandButton
 
405
                                        .removeActionListener(this.expandButtonActionListener);
 
406
                        this.expandButtonActionListener = null;
 
407
                        this.expandButton.removeActionListener(this.ribbonBand
 
408
                                        .getExpandActionListener());
 
409
                }
 
410
        }
 
411
 
 
412
        /**
 
413
         * Invoked by <code>installUI</code> to create a layout manager object to
 
414
         * manage the {@link JCommandButtonStrip}.
 
415
         * 
 
416
         * @return a layout manager object
 
417
         */
 
418
        protected LayoutManager createLayoutManager() {
 
419
                return new RibbonBandLayout();
 
420
        }
 
421
 
 
422
        /**
 
423
         * Layout for the ribbon band.
 
424
         * 
 
425
         * @author Kirill Grouchnikov
 
426
         */
 
427
        private class RibbonBandLayout implements LayoutManager {
 
428
 
 
429
                /*
 
430
                 * (non-Javadoc)
 
431
                 * 
 
432
                 * @see java.awt.LayoutManager#addLayoutComponent(java.lang.String,
 
433
                 * java.awt.Component)
 
434
                 */
 
435
                @Override
 
436
        public void addLayoutComponent(String name, Component c) {
 
437
                }
 
438
 
 
439
                /*
 
440
                 * (non-Javadoc)
 
441
                 * 
 
442
                 * @see java.awt.LayoutManager#removeLayoutComponent(java.awt.Component)
 
443
                 */
 
444
                @Override
 
445
        public void removeLayoutComponent(Component c) {
 
446
                }
 
447
 
 
448
                /*
 
449
                 * (non-Javadoc)
 
450
                 * 
 
451
                 * @see java.awt.LayoutManager#preferredLayoutSize(java.awt.Container)
 
452
                 */
 
453
                @Override
 
454
        public Dimension preferredLayoutSize(Container c) {
 
455
                        Insets ins = c.getInsets();
 
456
                        AbstractBandControlPanel controlPanel = ribbonBand
 
457
                                        .getControlPanel();
 
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();
 
466
 
 
467
                        // System.out.println(ribbonBand.getTitle() + ":" + height);
 
468
 
 
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));
 
475
 
 
476
                        return new Dimension(width + 2 + ins.left + ins.right, height
 
477
                                        + ins.top + ins.bottom);
 
478
                }
 
479
 
 
480
                /*
 
481
                 * (non-Javadoc)
 
482
                 * 
 
483
                 * @see java.awt.LayoutManager#minimumLayoutSize(java.awt.Container)
 
484
                 */
 
485
                @Override
 
486
        public Dimension minimumLayoutSize(Container c) {
 
487
                        Insets ins = c.getInsets();
 
488
                        AbstractBandControlPanel controlPanel = ribbonBand
 
489
                                        .getControlPanel();
 
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();
 
498
 
 
499
                        // System.out.println(useCollapsedButton + ":" + height);
 
500
 
 
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);
 
507
 
 
508
                }
 
509
 
 
510
                /*
 
511
                 * (non-Javadoc)
 
512
                 * 
 
513
                 * @see java.awt.LayoutManager#layoutContainer(java.awt.Container)
 
514
                 */
 
515
                @Override
 
516
        public void layoutContainer(Container c) {
 
517
                        // System.out.println("Ribbon band real = " + c.getHeight());
 
518
                        if (!c.isVisible())
 
519
                                return;
 
520
                        Insets ins = c.getInsets();
 
521
 
 
522
                        int availableHeight = c.getHeight() - ins.top - ins.bottom;
 
523
                        RibbonBandResizePolicy resizePolicy = ((AbstractRibbonBand) c)
 
524
                                        .getCurrentResizePolicy();
 
525
 
 
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
 
532
                                                .getHeight()
 
533
                                                - ins.top - ins.bottom);
 
534
 
 
535
                                // System.out.println("Collapsed " + collapsedButton.getHeight()
 
536
                                // + ":" + c.getHeight());
 
537
 
 
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()
 
547
                                                        .getLayoutGap();
 
548
                                        final Dimension size = new Dimension(ins.left + ins.right
 
549
                                                        + gap
 
550
                                                        + largest.getPreferredWidth(availableHeight, gap),
 
551
                                                        ins.top
 
552
                                                                        + ins.bottom
 
553
                                                                        + Math.max(c.getHeight(), ribbonBand
 
554
                                                                                        .getControlPanel()
 
555
                                                                                        .getPreferredSize().height
 
556
                                                                                        + getBandTitleHeight()));
 
557
                                        // System.out.println(ribbonBand.getTitle() + ":"
 
558
                                        // + size.getHeight());
 
559
                                        collapsedButton.setPopupCallback(new PopupPanelCallback() {
 
560
                                                @Override
 
561
                                                public JPopupPanel getPopupPanel(
 
562
                                                                JCommandButton commandButton) {
 
563
                                                        return new CollapsedButtonPopupPanel(popupBand,
 
564
                                                                        size);
 
565
                                                }
 
566
                                        });
 
567
                                        // collapsedButton.setGallery(new JPopupGallery(ribbonBand
 
568
                                        // .getControlPanel(), size));
 
569
                                        ribbonBand.setControlPanel(null);
 
570
                                        ribbonBand.setPopupRibbonBand(popupBand);
 
571
                                }
 
572
 
 
573
                                if (expandButton != null)
 
574
                                        expandButton.setBounds(0, 0, 0, 0);
 
575
 
 
576
                                return;
 
577
                        }
 
578
 
 
579
                        if (collapsedButton.isVisible()) {
 
580
                                // was icon and now is normal band - have to restore the
 
581
                                // control panel
 
582
                                CollapsedButtonPopupPanel popupPanel = (collapsedButton
 
583
                                                .getPopupCallback() != null) ? (CollapsedButtonPopupPanel) collapsedButton
 
584
                                                .getPopupCallback().getPopupPanel(collapsedButton)
 
585
                                                : null;
 
586
                                if (popupPanel != null) {
 
587
                                        AbstractRibbonBand bandFromPopup = (AbstractRibbonBand) popupPanel
 
588
                                                        .removeComponent();
 
589
                                        ribbonBand.setControlPanel(bandFromPopup.getControlPanel());
 
590
                                        ribbonBand.setPopupRibbonBand(null);
 
591
                                        collapsedButton.setPopupCallback(null);
 
592
                                }
 
593
                        }
 
594
                        collapsedButton.setVisible(false);
 
595
 
 
596
                        AbstractBandControlPanel controlPanel = ribbonBand
 
597
                                        .getControlPanel();
 
598
                        controlPanel.setVisible(true);
 
599
                        controlPanel.setBounds(ins.left, ins.top, c.getWidth() - ins.left
 
600
                                        - ins.right, c.getHeight() - getBandTitleHeight() - ins.top
 
601
                                        - ins.bottom);
 
602
                        controlPanel.doLayout();
 
603
 
 
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)
 
609
                                        ebph = maxHeight;
 
610
 
 
611
                                int expandButtonBottomY = c.getHeight()
 
612
                                                - (getBandTitleHeight() - ebph) / 2;
 
613
 
 
614
                                boolean ltr = ribbonBand.getComponentOrientation()
 
615
                                                .isLeftToRight();
 
616
 
 
617
                                if (ltr) {
 
618
                                        expandButton.setBounds(c.getWidth() - ins.right - ebpw,
 
619
                                                        expandButtonBottomY - ebph, ebpw, ebph);
 
620
                                } else {
 
621
                                        expandButton.setBounds(ins.left,
 
622
                                                        expandButtonBottomY - ebph, ebpw, ebph);
 
623
                                }
 
624
                        }
 
625
                }
 
626
        }
 
627
 
 
628
        /**
 
629
         * Event listener to handle global ribbon events. Currently handles:
 
630
         * <ul>
 
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
 
633
         * task.</li>
 
634
         * </ul>
 
635
         */
 
636
        private static class AWTRibbonEventListener implements AWTEventListener {
 
637
                private static AWTRibbonEventListener instance;
 
638
                private int installCount = 0;
 
639
                private AbstractRibbonBand lastHovered;
 
640
 
 
641
                public static void install() {
 
642
                        if (instance == null) {
 
643
                                instance = new AWTRibbonEventListener();
 
644
                                java.security.AccessController
 
645
                                                .doPrivileged(new java.security.PrivilegedAction<Object>() {
 
646
                                                        @Override
 
647
                            public Object run() {
 
648
                                                                Toolkit
 
649
                                                                                .getDefaultToolkit()
 
650
                                                                                .addAWTEventListener(
 
651
                                                                                                instance,
 
652
                                                                                                AWTEvent.MOUSE_EVENT_MASK
 
653
                                                                                                                | AWTEvent.MOUSE_WHEEL_EVENT_MASK);
 
654
                                                                return null;
 
655
                                                        }
 
656
                                                });
 
657
                        }
 
658
                        instance.installCount++;
 
659
                }
 
660
 
 
661
                public static boolean uninstall() {
 
662
                        if (instance != null) {
 
663
                                instance.installCount--;
 
664
                                if (instance.installCount == 0) {
 
665
                                        // really uninstall
 
666
                                        Toolkit.getDefaultToolkit()
 
667
                                                        .removeAWTEventListener(instance);
 
668
                                        instance = null;
 
669
                                }
 
670
                                return true;
 
671
                        }
 
672
                        return false;
 
673
                }
 
674
 
 
675
                @Override
 
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)) {
 
681
                                        return;
 
682
                                }
 
683
                                Component component = (Component) object;
 
684
                                AbstractRibbonBand band = (component instanceof AbstractRibbonBand) ? ((AbstractRibbonBand) component)
 
685
                                                : (AbstractRibbonBand) SwingUtilities
 
686
                                                                .getAncestorOfClass(AbstractRibbonBand.class,
 
687
                                                                                component);
 
688
                                setHoveredBand(band);
 
689
                        }
 
690
 
 
691
                        if (mouseEvent.getID() == MouseEvent.MOUSE_WHEEL) {
 
692
                                if (PopupPanelManager.defaultManager().getShownPath().size() > 0)
 
693
                                        return;
 
694
 
 
695
                                Object object = event.getSource();
 
696
                                if (!(object instanceof Component)) {
 
697
                                        return;
 
698
                                }
 
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
 
704
                                                                .getY());
 
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);
 
712
                                }
 
713
                        }
 
714
                }
 
715
 
 
716
                private void setHoveredBand(AbstractRibbonBand band) {
 
717
                        if (lastHovered == band) {
 
718
                                return; // nothing to do as we are already over
 
719
                        }
 
720
                        if (lastHovered != null) {
 
721
                                // RibbonBandUI ui = lastHovered.getUI();
 
722
                                lastHovered.getUI().trackMouseCrossing(false);
 
723
                        }
 
724
                        lastHovered = band;
 
725
                        if (band != null) {
 
726
                                band.getUI().trackMouseCrossing(true);
 
727
                        }
 
728
                }
 
729
        }
 
730
 
 
731
        /*
 
732
         * (non-Javadoc)
 
733
         * 
 
734
         * @see javax.swing.plaf.ComponentUI#update(java.awt.Graphics,
 
735
         * javax.swing.JComponent)
 
736
         */
 
737
        @Override
 
738
        public void update(Graphics g, JComponent c) {
 
739
                Graphics2D g2d = (Graphics2D) g.create();
 
740
                RenderingUtils.installDesktopHints(g2d);
 
741
                super.update(g2d, c);
 
742
                g2d.dispose();
 
743
        }
 
744
 
 
745
        /*
 
746
         * (non-Javadoc)
 
747
         * 
 
748
         * @see javax.swing.plaf.ComponentUI#paint(java.awt.Graphics,
 
749
         * javax.swing.JComponent)
 
750
         */
 
751
        @Override
 
752
        public void paint(Graphics g, JComponent c) {
 
753
                Graphics2D graphics = (Graphics2D) g.create();
 
754
 
 
755
                Insets ins = ribbonBand.getInsets();
 
756
 
 
757
                this.paintBandBackground(graphics, new Rectangle(0, 0, c.getWidth(), c
 
758
                                .getHeight()));
 
759
 
 
760
                if (!(ribbonBand.getCurrentResizePolicy() instanceof IconRibbonBandResizePolicy)) {
 
761
                        String title = ribbonBand.getTitle();
 
762
                        int titleHeight = getBandTitleHeight();
 
763
 
 
764
                        int bandTitleTopY = c.getHeight() - titleHeight;
 
765
 
 
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) {
 
772
                                if (ltr) {
 
773
                                        titleWidth = expandButton.getX() - 2 * ins.right - 2
 
774
                                                        * ins.left;
 
775
                                } else {
 
776
                                        titleWidth = ribbonBand.getWidth() - expandButton.getX()
 
777
                                                        - expandButton.getWidth() - 2 * ins.right - 2
 
778
                                                        * ins.left;
 
779
                                        titleX = expandButton.getX() + expandButton.getWidth() + 2
 
780
                                                        * ins.left;
 
781
                                }
 
782
                        }
 
783
                        this.paintBandTitle(graphics, new Rectangle(titleX, bandTitleTopY,
 
784
                                        titleWidth, titleHeight), title);
 
785
                }
 
786
 
 
787
                graphics.dispose();
 
788
        }
 
789
 
 
790
        /**
 
791
         * Paints band title pane.
 
792
         * 
 
793
         * @param g
 
794
         *            Graphics context.
 
795
         * @param titleRectangle
 
796
         *            Rectangle for the title pane.
 
797
         * @param title
 
798
         *            Title string.
 
799
         */
 
800
        protected void paintBandTitle(Graphics g, Rectangle titleRectangle,
 
801
                        String title) {
 
802
                // fix for issue 10 - empty ribbon band
 
803
                if (titleRectangle.width <= 0)
 
804
                        return;
 
805
 
 
806
                Graphics2D graphics = (Graphics2D) g.create();
 
807
                graphics.setFont(FlamingoUtilities.getFont(this.ribbonBand,
 
808
                                "Ribbon.font", "Button.font", "Panel.font"));
 
809
 
 
810
                FontMetrics fm = graphics.getFontMetrics();
 
811
                int y = titleRectangle.y - 2 + (titleRectangle.height + fm.getAscent())
 
812
                                / 2;
 
813
 
 
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();
 
820
                }
 
821
 
 
822
                int x = titleRectangle.x + (titleRectangle.width - currLength) / 2;
 
823
                graphics.setColor(this.ribbonBand.getForeground());
 
824
                graphics.drawString(titleToPaint, x, y);
 
825
                graphics.dispose();
 
826
        }
 
827
 
 
828
        /**
 
829
         * Paints band title pane.
 
830
         * 
 
831
         * @param g
 
832
         *            Graphics context.
 
833
         * @param titleRectangle
 
834
         *            Rectangle for the title pane.
 
835
         * @param title
 
836
         *            Title string.
 
837
         */
 
838
        protected void paintBandTitleBackground(Graphics g,
 
839
                        Rectangle titleRectangle, String title) {
 
840
 
 
841
                Graphics2D g2d = (Graphics2D) g.create();
 
842
                g2d.setComposite(AlphaComposite.SrcOver
 
843
                                .derive(0.7f + 0.3f * this.rolloverAmount));
 
844
 
 
845
                FlamingoUtilities.renderSurface(g2d, this.ribbonBand, titleRectangle,
 
846
                                this.rolloverAmount > 0.0f, true, false);
 
847
 
 
848
                g2d.dispose();
 
849
        }
 
850
 
 
851
        public void setRolloverAmount(float rolloverAmount) {
 
852
                this.rolloverAmount = rolloverAmount;
 
853
        }
 
854
 
 
855
        /**
 
856
         * Paints band background.
 
857
         * 
 
858
         * @param graphics
 
859
         *            Graphics context.
 
860
         * @param toFill
 
861
         *            Rectangle for the background.
 
862
         */
 
863
        protected void paintBandBackground(Graphics graphics, Rectangle toFill) {
 
864
                graphics.setColor(ribbonBand.getBackground());
 
865
                graphics.fillRect(toFill.x, toFill.y, toFill.width, toFill.height);
 
866
        }
 
867
 
 
868
        @Override
 
869
        public float getRolloverAmount() {
 
870
                return this.rolloverAmount;
 
871
        }
 
872
 
 
873
        /**
 
874
         * Returns the height of the ribbon band title area.
 
875
         * 
 
876
         * @return The height of the ribbon band title area.
 
877
         */
 
878
        @Override
 
879
        public int getBandTitleHeight() {
 
880
                Font font = FlamingoUtilities.getFont(this.ribbonBand, "Ribbon.font",
 
881
                                "Button.font", "Panel.font");
 
882
                if (font == null) {
 
883
                        // Nimbus - is that you?
 
884
                        font = new JLabel().getFont();
 
885
                }
 
886
                int result = font.getSize() + 5;
 
887
                if (result % 2 == 0)
 
888
                        result++;
 
889
                return result;
 
890
        }
 
891
 
 
892
        /**
 
893
         * Round border for the ribbon bands.
 
894
         * 
 
895
         * @author Kirill Grouchnikov
 
896
         */
 
897
        protected static class RoundBorder implements Border {
 
898
                /**
 
899
                 * Border color.
 
900
                 */
 
901
                protected Color color;
 
902
 
 
903
                /**
 
904
                 * Border insets.
 
905
                 */
 
906
                protected Insets insets;
 
907
 
 
908
                /**
 
909
                 * Creates the new border.
 
910
                 * 
 
911
                 * @param color
 
912
                 *            Border color.
 
913
                 * @param insets
 
914
                 *            Border insets.
 
915
                 */
 
916
                public RoundBorder(Color color, Insets insets) {
 
917
                        this.color = color;
 
918
                        this.insets = insets;
 
919
                }
 
920
 
 
921
                @Override
 
922
                public Insets getBorderInsets(Component c) {
 
923
                        return this.insets;
 
924
                }
 
925
 
 
926
                @Override
 
927
                public boolean isBorderOpaque() {
 
928
                        return false;
 
929
                }
 
930
 
 
931
                @Override
 
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);
 
937
                        g2d.dispose();
 
938
                }
 
939
 
 
940
        }
 
941
 
 
942
        @Override
 
943
        public int getPreferredCollapsedWidth() {
 
944
                return this.collapsedButton.getPreferredSize().width + 2;
 
945
        }
 
946
 
 
947
        @Override
 
948
        public void trackMouseCrossing(boolean isMouseIn) {
 
949
                if (isMouseIn) {
 
950
                        this.rolloverTimeline.play();
 
951
                } else {
 
952
                        this.rolloverTimeline.playReverse();
 
953
                }
 
954
                this.ribbonBand.repaint();
 
955
        }
 
956
 
 
957
        /**
 
958
         * This method is for unit tests only and should not be called by the
 
959
         * application code.
 
960
         * 
 
961
         * @return The expand button of the matching ribbon band.
 
962
         */
 
963
    @Deprecated
 
964
        public AbstractCommandButton getExpandButton() {
 
965
                return this.expandButton;
 
966
        }
 
967
 
 
968
        /**
 
969
         * This method is for unit tests only and should not be called by the
 
970
         * application code.
 
971
         *
 
972
         * @return The expand button of the matching ribbon band.
 
973
         */
 
974
    @Deprecated
 
975
        public AbstractCommandButton getCollapsedButton() {
 
976
                return this.collapsedButton;
 
977
        }
 
978
}