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

« back to all changes in this revision

Viewing changes to flamingo/src/main/java/org/pushingpixels/flamingo/api/ribbon/JRibbon.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.api.ribbon;
 
31
 
 
32
import java.awt.Component;
 
33
import java.awt.event.ActionListener;
 
34
import java.util.*;
 
35
 
 
36
import javax.swing.*;
 
37
import javax.swing.event.ChangeEvent;
 
38
import javax.swing.event.ChangeListener;
 
39
 
 
40
import org.pushingpixels.flamingo.api.common.*;
 
41
import org.pushingpixels.flamingo.api.common.icon.ResizableIcon;
 
42
import org.pushingpixels.flamingo.internal.ui.ribbon.BasicRibbonUI;
 
43
import org.pushingpixels.flamingo.internal.ui.ribbon.RibbonUI;
 
44
 
 
45
/**
 
46
 * The ribbon component.
 
47
 * 
 
48
 * <p>
 
49
 * The ribbon has the following major parts:
 
50
 * </p>
 
51
 * <ul>
 
52
 * <li>Ribbon tasks added with {@link #addTask(RibbonTask)}</li>
 
53
 * <li>Contextual ribbon task groups added with
 
54
 * {@link #addContextualTaskGroup(RibbonContextualTaskGroup)}</li>
 
55
 * <li>Application menu button set by
 
56
 * {@link #setApplicationMenu(RibbonApplicationMenu)}</li>
 
57
 * <li>Taskbar panel populated by {@link #addTaskbarComponent(Component)}</li>
 
58
 * <li>Help button set by {@link #configureHelp(ResizableIcon, ActionListener)}</li>
 
59
 * </ul>
 
60
 * 
 
61
 * <p>
 
62
 * While multiple ribbon tasks can be added to the ribbon, only one is visible
 
63
 * at any given time. This task is called the <strong>selected</strong> task.
 
64
 * Tasks can be switched with the task buttons placed along the top part of the
 
65
 * ribbon. Once a task has been added to the ribbon, it cannot be removed.
 
66
 * </p>
 
67
 * 
 
68
 * <p>
 
69
 * The contextual ribbon task groups allow showing and hiding ribbon tasks based
 
70
 * on the current selection in the application. For example, Word only shows the
 
71
 * table tasks when a table is selected in the document. By default, tasks
 
72
 * belonging to the groups adde by
 
73
 * {@link #addContextualTaskGroup(RibbonContextualTaskGroup)} are not visible.
 
74
 * To show the tasks belonging to the specific group, call
 
75
 * {@link #setVisible(RibbonContextualTaskGroup, boolean)} API. Note that you
 
76
 * can have multiple task groups visible at the same time.
 
77
 * </p>
 
78
 * 
 
79
 * <p>
 
80
 * The application menu button is a big round button shown in the top left
 
81
 * corner of the ribbon. If the
 
82
 * {@link #setApplicationMenu(RibbonApplicationMenu)} is not called, or called
 
83
 * with the <code>null</code> value, the application menu button is not shown,
 
84
 * and ribbon task buttons are shifted to the left.
 
85
 * </p>
 
86
 * 
 
87
 * <p>
 
88
 * The taskbar panel allows showing controls that are visible no matter what
 
89
 * ribbon task is selected. To add a taskbar component use the
 
90
 * {@link #addTaskbarComponent(Component)} API. The taskbar panel lives to the
 
91
 * right of the application menu button. Taskbar components can be removed with
 
92
 * the {@link #removeTaskbarComponent(Component)} API.
 
93
 * </p>
 
94
 * 
 
95
 * <p>
 
96
 * The ribbon can be minimized in one of the following ways:
 
97
 * </p>
 
98
 * <ul>
 
99
 * <li>Calling {@link #setMinimized(boolean)} with <code>true</code>.</li>
 
100
 * <li>User double-clicking on a task button.</li>
 
101
 * <li>User pressing <code>Ctrl+F1</code> key combination.</li>
 
102
 * </ul>
 
103
 * 
 
104
 * <p>
 
105
 * A minimized ribbon shows the application menu button, taskbar panel, task
 
106
 * buttons and help button, but not the ribbon bands of the selected task.
 
107
 * Clicking a task button shows the ribbon bands of that task in a popup
 
108
 * <strong>without</strong> shifting the application content down.
 
109
 * </p>
 
110
 * 
 
111
 * @author Kirill Grouchnikov
 
112
 */
 
113
@SuppressWarnings("serial")
 
114
public class JRibbon extends JComponent {
 
115
 
 
116
        /**
 
117
         * The property string used when the {@link #applicationIcon} changes. The
 
118
         * value is {@value #PROPERTY_APPLICATION_ICON}.
 
119
         */
 
120
        public static final String PROPERTY_APPLICATION_ICON = "ribbon.icon";
 
121
 
 
122
        /**
 
123
         * The property string used when the {@link #applicationMenuRichTooltip}
 
124
         * changes. The value is {@value #PROPERTY_APPLICATION_MENU_RICH_TOOLTIP}.
 
125
         */
 
126
        public static final String PROPERTY_APPLICATION_MENU_RICH_TOOLTIP = "applicationMenuRichTooltip";
 
127
 
 
128
        /**
 
129
         * The property string used when the {@link #applicationMenu} changes. The
 
130
         * value is {@value #PROPERTY_APPLICATION_MENU}.
 
131
         */
 
132
        public static final String PROPERTY_APPLICATION_MENU = "applicationMenu";
 
133
 
 
134
        /**
 
135
         * The property string used when the {@link #applicationMenuKeyTip} changes.
 
136
         * The value is {@value #PROPERTY_APPLICATION_MENU_KEY_TIP}.
 
137
         */
 
138
        public static final String PROPERTY_APPLICATION_MENU_KEY_TIP = "applicationMenuKeyTip";
 
139
 
 
140
        /**
 
141
         * The property string used when the {@link #currentlySelectedTask} changes.
 
142
         * The value is {@value #PROPERTY_SELECTED_TASK}.
 
143
         */
 
144
        public static final String PROPERTY_SELECTED_TASK = "selectedTask";
 
145
 
 
146
        /**
 
147
         * The property string used when the {@link #isMinimized} changes. The value
 
148
         * is {@value #PROPERTY_MINIMIZED}.
 
149
         */
 
150
        public static final String PROPERTY_MINIMIZED = "minimized";
 
151
 
 
152
        /**
 
153
         * The general tasks for this ribbon.
 
154
         * <p>
 
155
         * Tasks that get displayed based on a specific context are contextual
 
156
         * tasks. See {@link #contextualTaskGroups} for more information about
 
157
         * contextual tasks.
 
158
         * 
 
159
         * @see #addTask(RibbonTask)
 
160
         * @see #getTaskCount()
 
161
         * @see #getTask(int)
 
162
         */
 
163
        private List<RibbonTask> tasks;
 
164
 
 
165
        /**
 
166
         * The contextual task groups.
 
167
         * 
 
168
         * @see #addContextualTaskGroup(RibbonContextualTaskGroup)
 
169
         * @see #setVisible(RibbonContextualTaskGroup, boolean)
 
170
         * @see #isVisible(RibbonContextualTaskGroup)
 
171
         * @see #getContextualTaskGroupCount()
 
172
         * @see #getContextualTaskGroup(int)
 
173
         */
 
174
        private List<RibbonContextualTaskGroup> contextualTaskGroups;
 
175
 
 
176
    /**
 
177
         * The taskbar components (to the right of the application menu button).
 
178
         * 
 
179
         * @see #addTaskbarComponent(Component)
 
180
         * @see #getTaskbarComponents()
 
181
         * @see #removeTaskbarComponent(Component)
 
182
         */
 
183
        private List<Component> taskbarComponents;
 
184
 
 
185
        /**
 
186
     *  Currently selected (shown) task.
 
187
     */
 
188
        private RibbonTask currentlySelectedTask;
 
189
 
 
190
    /**
 
191
         * Help icon. When not <code>null</code>, the ribbon will display a help
 
192
         * button at the far right of the tab area.
 
193
         * 
 
194
         * @see #helpActionListener
 
195
         * @see #configureHelp(ResizableIcon, ActionListener)
 
196
         * @see #getHelpIcon()
 
197
         */
 
198
        private ResizableIcon helpIcon;
 
199
 
 
200
    /**
 
201
         * When the {@link #helpIcon} is not <code>null</code>, this listener will
 
202
         * be invoked when the user activates the help button.
 
203
         * 
 
204
         * @see #configureHelp(ResizableIcon, ActionListener)
 
205
         * @see #getHelpActionListener()
 
206
         */
 
207
        private ActionListener helpActionListener;
 
208
 
 
209
    /**
 
210
     * When the {@link #helpIcon} is not <code>null</code>, this rich tooltip
 
211
     * will be shown when the user mouses over the icon.
 
212
     *
 
213
     * @see #setHelpRichTooltip(org.pushingpixels.flamingo.api.common.RichTooltip)
 
214
     * @see #getHelpRichTooltip()
 
215
     */
 
216
    private RichTooltip helpRichTooltip;
 
217
 
 
218
        /**
 
219
         * Visibility status of the contextual task group. Must contain a value for
 
220
         * each group in {@link #contextualTaskGroups}.
 
221
         * 
 
222
         * @see #setVisible(RibbonContextualTaskGroup, boolean)
 
223
         * @see #isVisible(RibbonContextualTaskGroup)
 
224
         */
 
225
        private Map<RibbonContextualTaskGroup, Boolean> groupVisibilityMap;
 
226
 
 
227
        /**
 
228
         * The application menu.
 
229
         * 
 
230
         * @see #setApplicationMenu(RibbonApplicationMenu)
 
231
         * @see #getApplicationMenu()
 
232
         */
 
233
        private RibbonApplicationMenu applicationMenu;
 
234
 
 
235
        /**
 
236
         * The rich tooltip of {@link #applicationMenu} button.
 
237
         * 
 
238
         * @see #applicationMenu
 
239
         * @see #setApplicationMenuRichTooltip(RichTooltip)
 
240
         * @see #getApplicationMenuRichTooltip()
 
241
         */
 
242
        private RichTooltip applicationMenuRichTooltip;
 
243
 
 
244
        /**
 
245
         * The key tip of {@link #applicationMenu} button.
 
246
         * 
 
247
         * @see #applicationMenu
 
248
         * @see #setApplicationMenuKeyTip(String)
 
249
         * @see #getApplicationMenuKeyTip()
 
250
         */
 
251
        private String applicationMenuKeyTip;
 
252
 
 
253
        /**
 
254
         * Indicates whether the ribbon is currently minimized.
 
255
         * 
 
256
         * @see #setMinimized(boolean)
 
257
         * @see #isMinimized()
 
258
         */
 
259
        private boolean isMinimized;
 
260
 
 
261
        /**
 
262
         * The host ribbon frame. Is <code>null</code> when the ribbon is not hosted
 
263
         * in a {@link JRibbonFrame}.
 
264
         * 
 
265
         * @deprecated Dropped support in order to decouple the <code>JRibbon</code>
 
266
         *             from the <code>JRibbonFrame</code>
 
267
         */
 
268
        @Deprecated
 
269
        private JRibbonFrame ribbonFrame;
 
270
 
 
271
    /**
 
272
     *  The UI class ID string.
 
273
     */
 
274
        public static final String uiClassID = "RibbonUI";
 
275
 
 
276
    /**
 
277
     *  The application icon. This is displayed in the application menu button.
 
278
     */
 
279
        public ResizableIcon applicationIcon;
 
280
 
 
281
        /**
 
282
         * Constructs an empty default <code>JRibbon</code>. Applications are highly
 
283
         * encouraged to use {@link JRibbonFrame} and access the ribbon with
 
284
         * {@link JRibbonFrame#getRibbon()} API.
 
285
         */
 
286
        public JRibbon() {
 
287
                this((ResizableIcon) null);
 
288
        }
 
289
 
 
290
        /**
 
291
         * Constructs a <code>JRibbon</code> specifying the application icon. The
 
292
         * application icon is displayed in the application menu button.
 
293
         * Applications are highly encouraged to use {@link JRibbonFrame} and access
 
294
         * the ribbon with {@link JRibbonFrame#getRibbon()} API.
 
295
         * 
 
296
         * @param appIcon
 
297
         *            the application icon
 
298
         */
 
299
        public JRibbon(ResizableIcon appIcon) {
 
300
                this.tasks = new LinkedList<RibbonTask>();
 
301
                this.contextualTaskGroups = new ArrayList<RibbonContextualTaskGroup>();
 
302
                this.taskbarComponents = new ArrayList<Component>();
 
303
                this.currentlySelectedTask = null;
 
304
                this.groupVisibilityMap = new HashMap<RibbonContextualTaskGroup, Boolean>();
 
305
 
 
306
                updateUI();
 
307
                getUI().setApplicationIcon(appIcon);
 
308
        }
 
309
 
 
310
        /**
 
311
         * Creates an empty ribbon for the specified ribbon frame.
 
312
         * 
 
313
         * @param ribbonFrame
 
314
         *            Host ribbon frame.
 
315
         * @deprecated Dropped support in order to decouple the <code>JRibbon</code>
 
316
         *             from the <code>JRibbonFrame</code>
 
317
         */
 
318
        @Deprecated
 
319
        JRibbon(JRibbonFrame ribbonFrame) {
 
320
                this();
 
321
                this.ribbonFrame = ribbonFrame;
 
322
        }
 
323
 
 
324
        /**
 
325
         * Adds the specified taskbar component to this ribbon.
 
326
         * <p>
 
327
         * Taskbar components are small components placed to the right of the
 
328
         * application menu. These components usually perform an action common among
 
329
         * the entire application.
 
330
         * 
 
331
         * @param comp
 
332
         *            the taskbar component to add
 
333
         * @see #removeTaskbarComponent(Component)
 
334
         * @see #removeAllTaskbarComponents()
 
335
         * @see #getTaskbarComponents()
 
336
         */
 
337
        public synchronized void addTaskbarComponent(Component comp) {
 
338
                if (comp instanceof AbstractCommandButton) {
 
339
                        AbstractCommandButton button = (AbstractCommandButton) comp;
 
340
                        button.setDisplayState(CommandButtonDisplayState.SMALL);
 
341
                        button.setGapScaleFactor(0.5);
 
342
                        button.setFocusable(false);
 
343
                }
 
344
                taskbarComponents.add(comp);
 
345
                fireStateChanged();
 
346
        }
 
347
 
 
348
        /*
 
349
         * Added Remove Tasks from patch provided by Jonathan Giles Jan 2009
 
350
         * http://markmail.org/message/vzw3hrntr6qsdlu3
 
351
         */
 
352
 
 
353
        /**
 
354
         * Removes the specified taskbar component from this ribbon.
 
355
         * 
 
356
         * @param comp
 
357
         *            The taskbar component to remove.
 
358
         * @see #addTaskbarComponent(Component)
 
359
         * @see #getTaskbarComponents()
 
360
         * @see #removeAllTaskbarComponents()
 
361
         */
 
362
        public synchronized void removeTaskbarComponent(Component comp) {
 
363
                taskbarComponents.remove(comp);
 
364
                fireStateChanged();
 
365
        }
 
366
 
 
367
        /**
 
368
         * Removes all components added to the taskbar of the ribbon.
 
369
         * 
 
370
         * @see #addTaskbarComponent(Component)
 
371
         * @see #getTaskbarComponents()
 
372
         * @see #removeTaskbarComponent(Component)
 
373
         */
 
374
        public void removeAllTaskbarComponents() {
 
375
                taskbarComponents.clear();
 
376
                fireStateChanged();
 
377
        }
 
378
 
 
379
        /**
 
380
         * Adds the specified task to this ribbon.
 
381
         * 
 
382
         * @param task
 
383
         *            The ribbon task to add.
 
384
         * @see #addContextualTaskGroup(RibbonContextualTaskGroup)
 
385
         * @see #getTaskCount()
 
386
         * @see #getTask(int)
 
387
         */
 
388
        public synchronized void addTask(RibbonTask task) {
 
389
                task.setRibbon(this);
 
390
 
 
391
                tasks.add(task);
 
392
 
 
393
                if (tasks.size() == 1) {
 
394
                        setSelectedTask(task);
 
395
                }
 
396
 
 
397
                fireStateChanged();
 
398
        }
 
399
 
 
400
        /**
 
401
         * Removes the task at the specified position, if it represents a valid
 
402
         * task. Throws an {@link IndexOutOfBoundsException} if not.
 
403
         * 
 
404
         * @param pos
 
405
         *            The position of the task to remove.
 
406
         */
 
407
        public void removeTask(int pos) {
 
408
                if (pos >= getTaskCount()) {
 
409
                        throw new IndexOutOfBoundsException("task position  '" + pos
 
410
                                        + "' exceeds number of tasks in ribbon ('" + getTaskCount()
 
411
                                        + "')");
 
412
                }
 
413
 
 
414
                removeTask(getTask(pos));
 
415
        }
 
416
 
 
417
        /**
 
418
         * Removes the given task from the ribbon. If this is the currently visible
 
419
         * task, the ribbon will move to the task to its left, unless the removed
 
420
         * task is the left-most, in which case it will move to the next task to the
 
421
         * right.
 
422
         * 
 
423
         * @param task
 
424
         *            The ribbon task to be removed from the panel.
 
425
         * @exception IllegalArgumentException
 
426
         *                if <code>task</code> is <code>null</code>
 
427
         */
 
428
        public void removeTask(RibbonTask task) {
 
429
                if (task == null) {
 
430
                        throw new IllegalArgumentException("RibbonTask can not be null");
 
431
                }
 
432
 
 
433
                int posOfTask = this.tasks.indexOf(task);
 
434
                this.tasks.remove(task);
 
435
 
 
436
                if (getSelectedTask().equals(task) && tasks.size() > 0) {
 
437
                        RibbonTask newTask = getTask(posOfTask == 0 ? 1 : posOfTask - 1);
 
438
                        setSelectedTask(newTask);
 
439
                }
 
440
 
 
441
                this.fireStateChanged();
 
442
        }
 
443
 
 
444
        /**
 
445
         * Removes all tasks from the ribbon.
 
446
         */
 
447
        public void removeAllTasks() {
 
448
                this.tasks.clear();
 
449
                this.contextualTaskGroups.clear();
 
450
                this.fireStateChanged();
 
451
        }
 
452
 
 
453
        /**
 
454
         * Configures the help button of this ribbon.
 
455
         * 
 
456
         * @param helpIcon
 
457
         *            The icon for the help button.
 
458
         * @param helpActionListener
 
459
         *            The action listener for the help button.
 
460
         * @see #getHelpIcon()
 
461
         * @see #getHelpActionListener()
 
462
         */
 
463
        public synchronized void configureHelp(ResizableIcon helpIcon,
 
464
                        ActionListener helpActionListener) {
 
465
                this.helpIcon = helpIcon;
 
466
                this.helpActionListener = helpActionListener;
 
467
                this.fireStateChanged();
 
468
        }
 
469
 
 
470
        /**
 
471
         * Returns the icon for the help button. Will return <code>null</code> if
 
472
         * the help button has not been configured with the
 
473
         * {@link #configureHelp(ResizableIcon, ActionListener)} API.
 
474
         * 
 
475
         * @return The icon for the help button.
 
476
         * @see #configureHelp(ResizableIcon, ActionListener)
 
477
         * @see #getHelpActionListener()
 
478
         */
 
479
        public ResizableIcon getHelpIcon() {
 
480
                return this.helpIcon;
 
481
        }
 
482
 
 
483
        /**
 
484
         * Returns the action listener for the help button. Will return
 
485
         * <code>null</code> if the help button has not been configured with the
 
486
         * {@link #configureHelp(ResizableIcon, ActionListener)} API.
 
487
         * 
 
488
         * @return The action listener for the help button.
 
489
         * @see #configureHelp(ResizableIcon, ActionListener)
 
490
         * @see #getHelpIcon()
 
491
         */
 
492
        public ActionListener getHelpActionListener() {
 
493
                return this.helpActionListener;
 
494
        }
 
495
 
 
496
    /**
 
497
     * Sets the rich tooltip of the help button. Fires an
 
498
     * stateChanged event.
 
499
     *
 
500
     * @param tooltip
 
501
     *            The rich tooltip of the help button.
 
502
     * @see #getHelpRichTooltip()
 
503
     * @see #configureHelp(org.pushingpixels.flamingo.api.common.icon.ResizableIcon, java.awt.event.ActionListener)
 
504
     */
 
505
    public synchronized void setHelpRichTooltip(RichTooltip tooltip) {
 
506
        RichTooltip old = this.helpRichTooltip;
 
507
        this.helpRichTooltip = tooltip;
 
508
        this.fireStateChanged();
 
509
    }
 
510
 
 
511
    /**
 
512
     * Returns the rich tooltip of the help button.
 
513
     *
 
514
     * @return The rich tooltip of the help button.
 
515
     * @see #setHelpRichTooltip(org.pushingpixels.flamingo.api.common.RichTooltip)
 
516
     * @see #configureHelp(org.pushingpixels.flamingo.api.common.icon.ResizableIcon, java.awt.event.ActionListener)
 
517
     */
 
518
    public synchronized RichTooltip getHelpRichTooltip() {
 
519
        return this.helpRichTooltip;
 
520
    }
 
521
    /**
 
522
     * Adds a component to the 'Help Panel.'  This is the area where the
 
523
     * help button lives. and is the far right area of the main tab area.
 
524
     *
 
525
     * Components will be added in left to right fashion,  Also, if a
 
526
     * help listener is specified then the help button will be the rightmost
 
527
     * component on the list.
 
528
     *
 
529
     * Generally speaking this area should not be abused, as any large amount
 
530
     * of components will cause the space available for the task tabs to shrink.
 
531
     *
 
532
     * This is the area where you would add a "collapse" button like found in
 
533
     * Office 2010, or the min/max/close buttons of an integrated desktop area.
 
534
     *
 
535
     * @param comp the component to be added
 
536
     */
 
537
    public void addHelpPanelComponent(Component comp) {
 
538
        if (comp == null) return;
 
539
 
 
540
        try {
 
541
            List<Component> existingHelpPanelComponents = (List<Component>) getClientProperty(BasicRibbonUI.HELP_PANEL_COMPONENTS);
 
542
            if (existingHelpPanelComponents != null) {
 
543
                if (!existingHelpPanelComponents.contains(comp)) {
 
544
                    existingHelpPanelComponents.add(comp);
 
545
                }
 
546
            } else {
 
547
                List<Component> helpComps = new ArrayList<Component>();
 
548
                helpComps.add(comp);
 
549
                putClientProperty(BasicRibbonUI.HELP_PANEL_COMPONENTS, helpComps);
 
550
            }
 
551
        } catch (RuntimeException re) {
 
552
            //re-write on any error
 
553
            List<Component> helpComps = new ArrayList<Component>();
 
554
            helpComps.add(comp);
 
555
            putClientProperty(BasicRibbonUI.HELP_PANEL_COMPONENTS, helpComps);
 
556
        }
 
557
        fireStateChanged();
 
558
    }
 
559
 
 
560
    /**
 
561
     * Removes a component from the 'Help Panel'.
 
562
     *
 
563
     * @param comp The component to remove.  If the component is not currently
 
564
     *  on the help panel this call will be a no-op.
 
565
     */
 
566
    public void removeHelpPanelComponent(Component comp) {
 
567
        try {
 
568
            List<Component> existingHelpPanelComponents = (List<Component>) getClientProperty(BasicRibbonUI.HELP_PANEL_COMPONENTS);
 
569
            if (existingHelpPanelComponents != null) {
 
570
                if (existingHelpPanelComponents.remove(comp)) {
 
571
                    fireStateChanged();
 
572
                }
 
573
            }
 
574
        } catch (RuntimeException ignore) {
 
575
        }
 
576
    }
 
577
 
 
578
    /**
 
579
     * Removes al the  components from the 'Help Panel'.
 
580
     */
 
581
    public void removeAllHelpPanelComponents() {
 
582
        try {
 
583
            List<Component> existingHelpPanelComponents = (List<Component>) getClientProperty(BasicRibbonUI.HELP_PANEL_COMPONENTS);
 
584
            if (existingHelpPanelComponents != null) {
 
585
                existingHelpPanelComponents.clear();
 
586
                fireStateChanged();
 
587
            }
 
588
        } catch (RuntimeException ignore) {
 
589
        }
 
590
    }
 
591
 
 
592
        /**
 
593
         * Adds the specified contextual task group to this ribbon.
 
594
         * 
 
595
         * @param group
 
596
         *            Task group to add.
 
597
         * @see #addTask(RibbonTask)
 
598
         * @see #setVisible(RibbonContextualTaskGroup, boolean)
 
599
         * @see #isVisible(RibbonContextualTaskGroup)
 
600
         */
 
601
        public synchronized void addContextualTaskGroup(
 
602
                        RibbonContextualTaskGroup group) {
 
603
                group.setRibbon(this);
 
604
 
 
605
                this.contextualTaskGroups.add(group);
 
606
                this.groupVisibilityMap.put(group, false);
 
607
 
 
608
                this.fireStateChanged();
 
609
        }
 
610
 
 
611
        /**
 
612
         * Returns the number of regular tasks in <code>this</code> ribbon. This
 
613
         * does not include the contextual ribbon tasks.
 
614
         * <p>
 
615
         * To find the total number of ribbon tasks (including contextual ribbon
 
616
         * tasks) you will have to iterate through the contextual task groups.
 
617
         * 
 
618
         * @return Number of regular tasks in <code>this</code> ribbon.
 
619
         * @see #getTask(int)
 
620
         * @see #addTask(RibbonTask)
 
621
         */
 
622
        public synchronized int getTaskCount() {
 
623
                return this.tasks.size();
 
624
        }
 
625
 
 
626
        /**
 
627
         * Retrieves the regular task at specified index.
 
628
         * 
 
629
         * @param index
 
630
         *            task index
 
631
         * @return the task that matches the specified index
 
632
         * @see #getTaskCount()
 
633
         * @see #addTask(RibbonTask)
 
634
         */
 
635
        public synchronized RibbonTask getTask(int index) {
 
636
                return this.tasks.get(index);
 
637
        }
 
638
 
 
639
        /**
 
640
         * Returns the number of contextual task groups in <code>this</code> ribbon.
 
641
         * 
 
642
         * @return number of contextual task groups in <code>this</code> ribbon
 
643
         * @see #addContextualTaskGroup(RibbonContextualTaskGroup)
 
644
         * @see #getContextualTaskGroup(int)
 
645
         */
 
646
        public synchronized int getContextualTaskGroupCount() {
 
647
                return this.contextualTaskGroups.size();
 
648
        }
 
649
 
 
650
        /**
 
651
         * Retrieves contextual task group at specified index.
 
652
         * 
 
653
         * @param index
 
654
         *            group index
 
655
         * @return group that matches the specified index
 
656
         * @see #addContextualTaskGroup(RibbonContextualTaskGroup)
 
657
         * @see #getContextualTaskGroupCount()
 
658
         */
 
659
        public synchronized RibbonContextualTaskGroup getContextualTaskGroup(
 
660
                        int index) {
 
661
                return this.contextualTaskGroups.get(index);
 
662
        }
 
663
 
 
664
        /**
 
665
         * Selects the specified task. The task can be either regular (added with
 
666
         * {@link #addTask(RibbonTask)}) or a task in a visible contextual task
 
667
         * group (added with
 
668
         * {@link #addContextualTaskGroup(RibbonContextualTaskGroup)}. Fires a
 
669
         * <code>selectedTask</code> property change event.
 
670
         * 
 
671
         * @param task
 
672
         *            task to select
 
673
         * @throws IllegalArgumentException
 
674
         *             if <code>task</code> is not in the ribbon, is
 
675
         *             <code>null</code>, or not visible.
 
676
         * @see #getSelectedTask()
 
677
         */
 
678
        public synchronized void setSelectedTask(RibbonTask task) {
 
679
                // check for task in general tasks
 
680
                boolean valid = tasks.contains(task);
 
681
                // if not a general task, then check contextual tasks
 
682
                if (!valid) {
 
683
                        for (int i = 0; i < getContextualTaskGroupCount(); i++) {
 
684
                                RibbonContextualTaskGroup group = getContextualTaskGroup(i);
 
685
                                if (!this.isVisible(group))
 
686
                                        continue;
 
687
                                for (int j = 0; j < group.getTaskCount(); j++) {
 
688
                                        if (group.getTask(j) == task) {
 
689
                                                valid = true;
 
690
                                                break;
 
691
                                        }
 
692
                                }
 
693
                                if (valid)
 
694
                                        break;
 
695
                        }
 
696
                }
 
697
                if (!valid) {
 
698
                        throw new IllegalArgumentException(
 
699
                                        "The specified task to be selected is either not "
 
700
                                                        + "part of this ribbon or not marked as visible");
 
701
                }
 
702
 
 
703
                if (currentlySelectedTask != null) {
 
704
                        for (AbstractRibbonBand<?> ribbonBand : currentlySelectedTask
 
705
                                        .getBands()) {
 
706
                                ribbonBand.setVisible(false);
 
707
                        }
 
708
                }
 
709
 
 
710
                for (int i = 0; i < task.getBandCount(); i++) {
 
711
                        AbstractRibbonBand<?> ribbonBand = task.getBand(i);
 
712
                        ribbonBand.setVisible(true);
 
713
                }
 
714
 
 
715
                RibbonTask old = currentlySelectedTask;
 
716
                currentlySelectedTask = task;
 
717
 
 
718
                revalidate();
 
719
                repaint();
 
720
 
 
721
                firePropertyChange(PROPERTY_SELECTED_TASK, old,
 
722
                                this.currentlySelectedTask);
 
723
        }
 
724
 
 
725
        /**
 
726
         * Returns the currently selected task.
 
727
         * 
 
728
         * @return The currently selected task.
 
729
         * @see #setSelectedTask(RibbonTask)
 
730
         */
 
731
        public synchronized RibbonTask getSelectedTask() {
 
732
                return this.currentlySelectedTask;
 
733
        }
 
734
 
 
735
        /*
 
736
         * (non-Javadoc)
 
737
         * 
 
738
         * @see javax.swing.JComponent#updateUI()
 
739
         */
 
740
        @Override
 
741
        public void updateUI() {
 
742
                if (UIManager.get(getUIClassID()) != null) {
 
743
                        setUI(UIManager.getUI(this));
 
744
                } else {
 
745
                        setUI(new BasicRibbonUI());
 
746
                }
 
747
                for (Component comp : this.taskbarComponents) {
 
748
                        SwingUtilities.updateComponentTreeUI(comp);
 
749
                }
 
750
        }
 
751
 
 
752
        /**
 
753
         * Returns the UI object which implements the L&F for this component.
 
754
         * 
 
755
         * @return a <code>RibbonUI</code> object
 
756
         * @see #setUI(javax.swing.plaf.ComponentUI)
 
757
         */
 
758
        public RibbonUI getUI() {
 
759
                return (RibbonUI) ui;
 
760
        }
 
761
 
 
762
        /*
 
763
         * (non-Javadoc)
 
764
         * 
 
765
         * @see javax.swing.JComponent#getUIClassID()
 
766
         */
 
767
        @Override
 
768
        public String getUIClassID() {
 
769
                return uiClassID;
 
770
        }
 
771
 
 
772
        /**
 
773
         * Gets an unmodifiable list of all taskbar components of <code>this</code>
 
774
         * ribbon.
 
775
         * 
 
776
         * @return All taskbar components of <code>this</code> ribbon.
 
777
         * @see #addTaskbarComponent(Component)
 
778
         * @see #removeTaskbarComponent(Component)
 
779
         */
 
780
        public synchronized List<Component> getTaskbarComponents() {
 
781
                return Collections.unmodifiableList(this.taskbarComponents);
 
782
        }
 
783
 
 
784
        /**
 
785
         * Adds the specified change listener to track changes to this ribbon.
 
786
         * 
 
787
         * @param l
 
788
         *            Change listener to add.
 
789
         * @see #removeChangeListener(ChangeListener)
 
790
         */
 
791
        public void addChangeListener(ChangeListener l) {
 
792
                this.listenerList.add(ChangeListener.class, l);
 
793
        }
 
794
 
 
795
        /**
 
796
         * Removes the specified change listener from tracking changes to this
 
797
         * ribbon.
 
798
         * 
 
799
         * @param l
 
800
         *            Change listener to remove.
 
801
         * @see #addChangeListener(ChangeListener)
 
802
         */
 
803
        public void removeChangeListener(ChangeListener l) {
 
804
                this.listenerList.remove(ChangeListener.class, l);
 
805
        }
 
806
 
 
807
        /**
 
808
         * Notifies all registered listeners that the state of this ribbon has
 
809
         * changed.
 
810
         */
 
811
        protected void fireStateChanged() {
 
812
                // Guaranteed to return a non-null array
 
813
                Object[] listeners = this.listenerList.getListenerList();
 
814
                // Process the listeners last to first, notifying
 
815
                // those that are interested in this event
 
816
                ChangeEvent event = new ChangeEvent(this);
 
817
                for (int i = listeners.length - 2; i >= 0; i -= 2) {
 
818
                        if (listeners[i] == ChangeListener.class) {
 
819
                                ((ChangeListener) listeners[i + 1]).stateChanged(event);
 
820
                        }
 
821
                }
 
822
        }
 
823
 
 
824
        /**
 
825
         * Sets the visibility of ribbon tasks in the specified contextual task
 
826
         * group. Visibility of all ribbon tasks in the specified group is affected.
 
827
         * Note that the ribbon can show ribbon tasks of multiple groups at the same
 
828
         * time.
 
829
         * 
 
830
         * @param group
 
831
         *            Contextual task group.
 
832
         * @param isVisible
 
833
         *            If <code>true</code>, all ribbon tasks in the specified group
 
834
         *            will be visible. If <code>false</code>, all ribbon tasks in
 
835
         *            the specified group will be hidden.
 
836
         * @see #isVisible(RibbonContextualTaskGroup)
 
837
         */
 
838
        public synchronized void setVisible(RibbonContextualTaskGroup group,
 
839
                        boolean isVisible) {
 
840
                this.groupVisibilityMap.put(group, isVisible);
 
841
 
 
842
                // special handling of selected tab
 
843
                if (!isVisible) {
 
844
                        boolean isSelectedBeingHidden = false;
 
845
                        for (int i = 0; i < group.getTaskCount(); i++) {
 
846
                                if (this.getSelectedTask() == group.getTask(i)) {
 
847
                                        isSelectedBeingHidden = true;
 
848
                                        break;
 
849
                                }
 
850
                        }
 
851
                        if (isSelectedBeingHidden) {
 
852
                                this.setSelectedTask(this.getTask(0));
 
853
                        }
 
854
                }
 
855
 
 
856
                this.fireStateChanged();
 
857
                this.revalidate();
 
858
                SwingUtilities.getWindowAncestor(this).repaint();
 
859
        }
 
860
 
 
861
        /**
 
862
         * Returns the visibility of ribbon tasks in the specified contextual task
 
863
         * group.
 
864
         * 
 
865
         * @param group
 
866
         *            Contextual task group.
 
867
         * @return <code>true</code> if the ribbon tasks in the specified group are
 
868
         *         visible, <code>false</code> otherwise.
 
869
         */
 
870
        public synchronized boolean isVisible(RibbonContextualTaskGroup group) {
 
871
                return this.groupVisibilityMap.get(group);
 
872
        }
 
873
 
 
874
        /**
 
875
         * Sets the application menu for this ribbon. If <code>null</code> is
 
876
         * passed, the application menu button is hidden. Fires an
 
877
         * <code>applicationMenu</code> property change event.
 
878
         * 
 
879
         * @param applicationMenu
 
880
         *            The new application menu. Can be <code>null</code>.
 
881
         * @see #getApplicationMenu()
 
882
         */
 
883
        public synchronized void setApplicationMenu(
 
884
                        RibbonApplicationMenu applicationMenu) {
 
885
                RibbonApplicationMenu old = this.applicationMenu;
 
886
                if (old != applicationMenu) {
 
887
                        this.applicationMenu = applicationMenu;
 
888
                        if (this.applicationMenu != null) {
 
889
                                this.applicationMenu.setFrozen();
 
890
                        }
 
891
                        this.firePropertyChange(PROPERTY_APPLICATION_MENU, old,
 
892
                                        this.applicationMenu);
 
893
                }
 
894
        }
 
895
 
 
896
        /**
 
897
         * Returns the application menu of this ribbon.
 
898
         * 
 
899
         * @return The application menu of this ribbon.
 
900
         * @see #setApplicationMenu(RibbonApplicationMenu)
 
901
         */
 
902
        public synchronized RibbonApplicationMenu getApplicationMenu() {
 
903
                return this.applicationMenu;
 
904
        }
 
905
 
 
906
        /**
 
907
         * Sets the rich tooltip of the application menu button. Fires an
 
908
         * <code>applicationMenuRichTooltip</code> property change event.
 
909
         * 
 
910
         * @param tooltip
 
911
         *            The rich tooltip of the application menu button.
 
912
         * @see #getApplicationMenuRichTooltip()
 
913
         * @see #setApplicationMenu(RibbonApplicationMenu)
 
914
         */
 
915
        public synchronized void setApplicationMenuRichTooltip(RichTooltip tooltip) {
 
916
                RichTooltip old = this.applicationMenuRichTooltip;
 
917
                this.applicationMenuRichTooltip = tooltip;
 
918
                this.firePropertyChange(PROPERTY_APPLICATION_MENU_RICH_TOOLTIP, old,
 
919
                                this.applicationMenuRichTooltip);
 
920
        }
 
921
 
 
922
        /**
 
923
         * Returns the rich tooltip of the application menu button.
 
924
         * 
 
925
         * @return The rich tooltip of the application menu button.
 
926
         * @see #setApplicationMenuRichTooltip(RichTooltip)
 
927
         * @see #setApplicationMenu(RibbonApplicationMenu)
 
928
         */
 
929
        public synchronized RichTooltip getApplicationMenuRichTooltip() {
 
930
                return this.applicationMenuRichTooltip;
 
931
        }
 
932
 
 
933
        /**
 
934
         * Sets the key tip of the application menu button. Fires an
 
935
         * <code>applicationMenuKeyTip</code> property change event.
 
936
         * 
 
937
         * @param keyTip
 
938
         *            The new key tip for the application menu button.
 
939
         * @see #setApplicationMenu(RibbonApplicationMenu)
 
940
         * @see #getApplicationMenuKeyTip()
 
941
         */
 
942
        public synchronized void setApplicationMenuKeyTip(String keyTip) {
 
943
                String old = this.applicationMenuKeyTip;
 
944
                this.applicationMenuKeyTip = keyTip;
 
945
                this.firePropertyChange(PROPERTY_APPLICATION_MENU_KEY_TIP, old,
 
946
                                this.applicationMenuKeyTip);
 
947
        }
 
948
 
 
949
        /**
 
950
         * Returns the key tip of the application menu button.
 
951
         * 
 
952
         * @return The key tip of the application menu button.
 
953
         * @see #setApplicationMenuKeyTip(String)
 
954
         * @see #setApplicationMenu(RibbonApplicationMenu)
 
955
         */
 
956
        public synchronized String getApplicationMenuKeyTip() {
 
957
                return this.applicationMenuKeyTip;
 
958
        }
 
959
 
 
960
        /**
 
961
         * Returns the indication whether this ribbon is minimized.
 
962
         * 
 
963
         * @return <code>true</code> if this ribbon is minimized, <code>false</code>
 
964
         *         otherwise.
 
965
         * @see #setMinimized(boolean)
 
966
         */
 
967
        public synchronized boolean isMinimized() {
 
968
                return this.isMinimized;
 
969
        }
 
970
 
 
971
        /**
 
972
         * Changes the minimized state of this ribbon. Fires a
 
973
         * <code>minimized</code> property change event.
 
974
         * 
 
975
         * @param isMinimized
 
976
         *            if <code>true</code>, this ribbon becomes minimized, otherwise
 
977
         *            it is unminimized.
 
978
         */
 
979
        public synchronized void setMinimized(boolean isMinimized) {
 
980
                // System.out.println("Ribbon minimized -> " + isMinimized);
 
981
                boolean old = this.isMinimized;
 
982
                if (old != isMinimized) {
 
983
                        this.isMinimized = isMinimized;
 
984
                        this.firePropertyChange(PROPERTY_MINIMIZED, old, this.isMinimized);
 
985
                }
 
986
        }
 
987
 
 
988
        /**
 
989
         * Returns the ribbon frame that hosts this ribbon. The result can be
 
990
         * <code>null</code>.
 
991
         * 
 
992
         * @return The ribbon frame that hosts this ribbon.
 
993
         * @deprecated Dropped support in order to decouple the <code>JRibbon</code>
 
994
         *             from the <code>JRibbonFrame</code>
 
995
         */
 
996
        @Deprecated
 
997
        public JRibbonFrame getRibbonFrame() {
 
998
                return this.ribbonFrame;
 
999
        }
 
1000
 
 
1001
        /*
 
1002
         * (non-Javadoc)
 
1003
         * 
 
1004
         * @see javax.swing.JComponent#setVisible(boolean)
 
1005
         */
 
1006
        @Override
 
1007
        public void setVisible(boolean flag) {
 
1008
                if (!flag && (getRibbonFrame() != null))
 
1009
                        throw new IllegalArgumentException(
 
1010
                                        "Can't hide ribbon on JRibbonFrame");
 
1011
                super.setVisible(flag);
 
1012
        }
 
1013
 
 
1014
        /**
 
1015
         * Returns the application icon. The application icon is displayed on the
 
1016
         * application menu button.
 
1017
         * <p>
 
1018
         * This is a convenience method and is equivalent to
 
1019
         * <code>getUI().getApplicationIcon()</code>.
 
1020
         * 
 
1021
         * @see #getUI()
 
1022
         * @see RibbonUI#getApplicationIcon()
 
1023
         * @see #setApplicationIcon(ResizableIcon)
 
1024
         * @return the application icon
 
1025
         */
 
1026
        public synchronized ResizableIcon getApplicationIcon() {
 
1027
                return getUI().getApplicationIcon();
 
1028
        }
 
1029
 
 
1030
        /**
 
1031
         * Sets the application icon. This is displayed on the application menu
 
1032
         * button.
 
1033
         * <p>
 
1034
         * There is no check performed to see if <code>applicationIcon</code> is
 
1035
         * <code>null</code>.
 
1036
         * <p>
 
1037
         * A <code>PropertyChangeEvent</code> is fired for the
 
1038
         * {@link #PROPERTY_APPLICATION_ICON} property.
 
1039
         * 
 
1040
         * @see #getUI()
 
1041
         * @see RibbonUI#setApplicationIcon(ResizableIcon)
 
1042
         * @see #getApplicationIcon()
 
1043
         * @param applicationIcon
 
1044
         *            the application icon to set
 
1045
         */
 
1046
        public synchronized void setApplicationIcon(ResizableIcon applicationIcon) {
 
1047
                ResizableIcon old = getUI().getApplicationIcon();
 
1048
                getUI().setApplicationIcon(applicationIcon);
 
1049
                firePropertyChange(PROPERTY_APPLICATION_ICON, old, this.applicationIcon);
 
1050
                // TODO set the application menu button icon
 
1051
                // JRibbonApplicationMenuButton button = getApplicationMenuButton();
 
1052
                // if (button != null) {
 
1053
                // button.setIcon(this.applicationIcon);
 
1054
                // }
 
1055
        }
 
1056
 
 
1057
}