All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.pushingpixels.flamingo.api.ribbon.JRibbon Maven / Gradle / Ivy

/*
 * Copyright (c) 2005-2010 Flamingo Kirill Grouchnikov. All Rights Reserved.
 *
 * Redistribution and use in source and binary forms, with or without 
 * modification, are permitted provided that the following conditions are met:
 * 
 *  o Redistributions of source code must retain the above copyright notice, 
 *    this list of conditions and the following disclaimer. 
 *     
 *  o Redistributions in binary form must reproduce the above copyright notice, 
 *    this list of conditions and the following disclaimer in the documentation 
 *    and/or other materials provided with the distribution. 
 *     
 *  o Neither the name of Flamingo Kirill Grouchnikov nor the names of 
 *    its contributors may be used to endorse or promote products derived 
 *    from this software without specific prior written permission. 
 *     
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 
 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, 
 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 
 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR 
 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 
 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 
 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; 
 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 
 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE 
 * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, 
 * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 
 */
package org.pushingpixels.flamingo.api.ribbon;

import java.awt.Component;
import java.awt.event.ActionListener;
import java.util.*;

import javax.swing.*;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;

import org.pushingpixels.flamingo.api.common.*;
import org.pushingpixels.flamingo.api.common.icon.ResizableIcon;
import org.pushingpixels.flamingo.internal.ui.ribbon.BasicRibbonUI;
import org.pushingpixels.flamingo.internal.ui.ribbon.RibbonUI;

/**
 * The ribbon component.
 * 
 * 

* The ribbon has the following major parts: *

*
    *
  • Ribbon tasks added with {@link #addTask(RibbonTask)}
  • *
  • Contextual ribbon task groups added with * {@link #addContextualTaskGroup(RibbonContextualTaskGroup)}
  • *
  • Application menu button set by * {@link #setApplicationMenu(RibbonApplicationMenu)}
  • *
  • Taskbar panel populated by {@link #addTaskbarComponent(Component)}
  • *
  • Help button set by {@link #configureHelp(ResizableIcon, ActionListener)}
  • *
* *

* While multiple ribbon tasks can be added to the ribbon, only one is visible * at any given time. This task is called the selected task. * Tasks can be switched with the task buttons placed along the top part of the * ribbon. Once a task has been added to the ribbon, it cannot be removed. *

* *

* The contextual ribbon task groups allow showing and hiding ribbon tasks based * on the current selection in the application. For example, Word only shows the * table tasks when a table is selected in the document. By default, tasks * belonging to the groups adde by * {@link #addContextualTaskGroup(RibbonContextualTaskGroup)} are not visible. * To show the tasks belonging to the specific group, call * {@link #setVisible(RibbonContextualTaskGroup, boolean)} API. Note that you * can have multiple task groups visible at the same time. *

* *

* The application menu button is a big round button shown in the top left * corner of the ribbon. If the * {@link #setApplicationMenu(RibbonApplicationMenu)} is not called, or called * with the null value, the application menu button is not shown, * and ribbon task buttons are shifted to the left. *

* *

* The taskbar panel allows showing controls that are visible no matter what * ribbon task is selected. To add a taskbar component use the * {@link #addTaskbarComponent(Component)} API. The taskbar panel lives to the * right of the application menu button. Taskbar components can be removed with * the {@link #removeTaskbarComponent(Component)} API. *

* *

* The ribbon can be minimized in one of the following ways: *

*
    *
  • Calling {@link #setMinimized(boolean)} with true.
  • *
  • User double-clicking on a task button.
  • *
  • User pressing Ctrl+F1 key combination.
  • *
* *

* A minimized ribbon shows the application menu button, taskbar panel, task * buttons and help button, but not the ribbon bands of the selected task. * Clicking a task button shows the ribbon bands of that task in a popup * without shifting the application content down. *

* * @author Kirill Grouchnikov */ public class JRibbon extends JComponent { /** * The general tasks. * * @see #addTask(RibbonTask) * @see #getTaskCount() * @see #getTask(int) */ private ArrayList tasks; /** * The contextual task groups. * * @see #addContextualTaskGroup(RibbonContextualTaskGroup) * @see #setVisible(RibbonContextualTaskGroup, boolean) * @see #isVisible(RibbonContextualTaskGroup) * @see #getContextualTaskGroupCount() * @see #getContextualTaskGroup(int) */ private ArrayList contextualTaskGroups; /** * The taskbar components (to the right of the application menu button). * * @see #addTaskbarComponent(Component) * @see #getTaskbarComponents() * @see #removeTaskbarComponent(Component) */ private ArrayList taskbarComponents; /** * Bands of the currently shown task. */ private ArrayList bands; /** * Currently selected (shown) task. */ private RibbonTask currentlySelectedTask; /** * Help icon. When not null, the ribbon will display a help * button at the far right of the tab area. * * @see #helpActionListener * @see #configureHelp(ResizableIcon, ActionListener) * @see #getHelpIcon() */ private ResizableIcon helpIcon; /** * When the {@link #helpIcon} is not null, this listener will * be invoked when the user activates the help button. * * @see #configureHelp(ResizableIcon, ActionListener) * @see #getHelpActionListener() */ private ActionListener helpActionListener; /** * Visibility status of the contextual task group. Must contain a value for * each group in {@link #contextualTaskGroups}. * * @see #setVisible(RibbonContextualTaskGroup, boolean) * @see #isVisible(RibbonContextualTaskGroup) */ private Map groupVisibilityMap; /** * The application menu. * * @see #setApplicationMenu(RibbonApplicationMenu) * @see #getApplicationMenu() */ private RibbonApplicationMenu applicationMenu; /** * The rich tooltip of {@link #applicationMenu} button. * * @see #applicationMenu * @see #setApplicationMenuRichTooltip(RichTooltip) * @see #getApplicationMenuRichTooltip() */ private RichTooltip applicationMenuRichTooltip; /** * The key tip of {@link #applicationMenu} button. * * @see #applicationMenu * @see #setApplicationMenuKeyTip(String) * @see #getApplicationMenuKeyTip() */ private String applicationMenuKeyTip; /** * Indicates whether the ribbon is currently minimized. * * @see #setMinimized(boolean) * @see #isMinimized() */ private boolean isMinimized; /** * The host ribbon frame. Is null when the ribbon is not hosted * in a {@link JRibbonFrame}. */ private JRibbonFrame ribbonFrame; /** * The UI class ID string. */ public static final String uiClassID = "RibbonUI"; /** * Creates a new empty ribbon. Applications are highly encouraged to use * {@link JRibbonFrame} and access the ribbon with * {@link JRibbonFrame#getRibbon()} API. */ public JRibbon() { this.tasks = new ArrayList(); this.contextualTaskGroups = new ArrayList(); this.taskbarComponents = new ArrayList(); this.bands = new ArrayList(); this.currentlySelectedTask = null; this.groupVisibilityMap = new HashMap(); updateUI(); } /** * Creates an empty ribbon for the specified ribbon frame. * * @param ribbonFrame * Host ribbon frame. */ JRibbon(JRibbonFrame ribbonFrame) { this(); this.ribbonFrame = ribbonFrame; } /** * Adds the specified taskbar component to this ribbon. * * @param comp * The taskbar component to add. * @see #removeTaskbarComponent(Component) * @see #getTaskbarComponents() */ public synchronized void addTaskbarComponent(Component comp) { if (comp instanceof AbstractCommandButton) { AbstractCommandButton button = (AbstractCommandButton) comp; button.setDisplayState(CommandButtonDisplayState.SMALL); button.setGapScaleFactor(0.5); button.setFocusable(false); } this.taskbarComponents.add(comp); this.fireStateChanged(); } /** * Removes the specified taskbar component from this ribbon. * * @param comp * The taskbar component to remove. * @see #addTaskbarComponent(Component) * @see #getTaskbarComponents() */ public synchronized void removeTaskbarComponent(Component comp) { this.taskbarComponents.remove(comp); this.fireStateChanged(); } /** * Adds the specified task to this ribbon. * * @param task * The ribbon task to add. * @see #addContextualTaskGroup(RibbonContextualTaskGroup) * @see #getTaskCount() * @see #getTask(int) */ public synchronized void addTask(RibbonTask task) { task.setRibbon(this); this.tasks.add(task); if (this.tasks.size() == 1) { this.setSelectedTask(task); } this.fireStateChanged(); } /** * Configures the help button of this ribbon. * * @param helpIcon * The icon for the help button. * @param helpActionListener * The action listener for the help button. * @see #getHelpIcon() * @see #getHelpActionListener() */ public synchronized void configureHelp(ResizableIcon helpIcon, ActionListener helpActionListener) { this.helpIcon = helpIcon; this.helpActionListener = helpActionListener; this.fireStateChanged(); } /** * Returns the icon for the help button. Will return null if * the help button has not been configured with the * {@link #configureHelp(ResizableIcon, ActionListener)} API. * * @return The icon for the help button. * @see #configureHelp(ResizableIcon, ActionListener) * @see #getHelpActionListener() */ public ResizableIcon getHelpIcon() { return this.helpIcon; } /** * Returns the action listener for the help button. Will return * null if the help button has not been configured with the * {@link #configureHelp(ResizableIcon, ActionListener)} API. * * @return The action listener for the help button. * @see #configureHelp(ResizableIcon, ActionListener) * @see #getHelpIcon() */ public ActionListener getHelpActionListener() { return this.helpActionListener; } /** * Adds the specified contextual task group to this ribbon. * * @param group * Task group to add. * @see #addTask(RibbonTask) * @see #setVisible(RibbonContextualTaskGroup, boolean) * @see #isVisible(RibbonContextualTaskGroup) */ public synchronized void addContextualTaskGroup( RibbonContextualTaskGroup group) { group.setRibbon(this); this.contextualTaskGroups.add(group); this.groupVisibilityMap.put(group, Boolean.valueOf(false)); this.fireStateChanged(); } /** * Returns the number of regular tasks in this ribbon. * * @return Number of regular tasks in this ribbon. * @see #getTask(int) * @see #addTask(RibbonTask) */ public synchronized int getTaskCount() { return this.tasks.size(); } /** * Retrieves the regular task at specified index. * * @param index * Task index. * @return Task that matches the specified index. * @see #getTaskCount() * @see #addTask(RibbonTask) */ public synchronized RibbonTask getTask(int index) { return this.tasks.get(index); } /** * Returns the number of contextual task groups in this ribbon. * * @return Number of contextual task groups in this ribbon. * @see #addContextualTaskGroup(RibbonContextualTaskGroup) * @see #getContextualTaskGroup(int) */ public synchronized int getContextualTaskGroupCount() { return this.contextualTaskGroups.size(); } /** * Retrieves contextual task group at specified index. * * @param index * Group index. * @return Group that matches the specified index. * @see #addContextualTaskGroup(RibbonContextualTaskGroup) * @see #getContextualTaskGroupCount() */ public synchronized RibbonContextualTaskGroup getContextualTaskGroup( int index) { return this.contextualTaskGroups.get(index); } /** * Selects the specified task. The task can be either regular (added with * {@link #addTask(RibbonTask)}) or a task in a visible contextual task * group (added with * {@link #addContextualTaskGroup(RibbonContextualTaskGroup)}. Fires a * selectedTask property change event. * * @param task * Task to select. * @throws IllegalArgumentException * If the specified task is not in the ribbon or not visible. * @see #getSelectedTask() */ public synchronized void setSelectedTask(RibbonTask task) { boolean valid = this.tasks.contains(task); if (!valid) { for (int i = 0; i < this.getContextualTaskGroupCount(); i++) { RibbonContextualTaskGroup group = this .getContextualTaskGroup(i); if (!this.isVisible(group)) continue; for (int j = 0; j < group.getTaskCount(); j++) { if (group.getTask(j) == task) { valid = true; break; } } if (valid) break; } } if (!valid) { throw new IllegalArgumentException( "The specified task to be selected is either not " + "part of this ribbon or not marked as visible"); } for (AbstractRibbonBand ribbonBand : this.bands) { ribbonBand.setVisible(false); } this.bands.clear(); for (int i = 0; i < task.getBandCount(); i++) { AbstractRibbonBand ribbonBand = task.getBand(i); ribbonBand.setVisible(true); this.bands.add(ribbonBand); } RibbonTask old = this.currentlySelectedTask; this.currentlySelectedTask = task; this.revalidate(); this.repaint(); this .firePropertyChange("selectedTask", old, this.currentlySelectedTask); } /** * Returns the currently selected task. * * @return The currently selected task. * @see #setSelectedTask(RibbonTask) */ public synchronized RibbonTask getSelectedTask() { return this.currentlySelectedTask; } /* * (non-Javadoc) * * @see javax.swing.JComponent#updateUI() */ @Override public void updateUI() { if (UIManager.get(getUIClassID()) != null) { setUI(UIManager.getUI(this)); } else { setUI(new BasicRibbonUI()); } for (Component comp : this.taskbarComponents) { SwingUtilities.updateComponentTreeUI(comp); } } /** * Returns the UI object which implements the L&F for this component. * * @return a RibbonUI object * @see #setUI */ public RibbonUI getUI() { return (RibbonUI) ui; } /* * (non-Javadoc) * * @see javax.swing.JComponent#getUIClassID() */ @Override public String getUIClassID() { return uiClassID; } /** * Gets an unmodifiable list of all taskbar components of this * ribbon. * * @return All taskbar components of this ribbon. * @see #addTaskbarComponent(Component) * @see #removeTaskbarComponent(Component) */ public synchronized List getTaskbarComponents() { return Collections.unmodifiableList(this.taskbarComponents); } /** * Adds the specified change listener to track changes to this ribbon. * * @param l * Change listener to add. * @see #removeChangeListener(ChangeListener) */ public void addChangeListener(ChangeListener l) { this.listenerList.add(ChangeListener.class, l); } /** * Removes the specified change listener from tracking changes to this * ribbon. * * @param l * Change listener to remove. * @see #addChangeListener(ChangeListener) */ public void removeChangeListener(ChangeListener l) { this.listenerList.remove(ChangeListener.class, l); } /** * Notifies all registered listeners that the state of this ribbon has * changed. */ protected void fireStateChanged() { // Guaranteed to return a non-null array Object[] listeners = this.listenerList.getListenerList(); // Process the listeners last to first, notifying // those that are interested in this event ChangeEvent event = new ChangeEvent(this); for (int i = listeners.length - 2; i >= 0; i -= 2) { if (listeners[i] == ChangeListener.class) { ((ChangeListener) listeners[i + 1]).stateChanged(event); } } } /** * Sets the visibility of ribbon tasks in the specified contextual task * group. Visibility of all ribbon tasks in the specified group is affected. * Note that the ribbon can show ribbon tasks of multiple groups at the same * time. * * @param group * Contextual task group. * @param isVisible * If true, all ribbon tasks in the specified group * will be visible. If false, all ribbon tasks in * the specified group will be hidden. * @see #isVisible(RibbonContextualTaskGroup) */ public synchronized void setVisible(RibbonContextualTaskGroup group, boolean isVisible) { this.groupVisibilityMap.put(group, Boolean.valueOf(isVisible)); // special handling of selected tab if (!isVisible) { boolean isSelectedBeingHidden = false; for (int i = 0; i < group.getTaskCount(); i++) { if (this.getSelectedTask() == group.getTask(i)) { isSelectedBeingHidden = true; break; } } if (isSelectedBeingHidden) { this.setSelectedTask(this.getTask(0)); } } this.fireStateChanged(); this.revalidate(); SwingUtilities.getWindowAncestor(this).repaint(); } /** * Returns the visibility of ribbon tasks in the specified contextual task * group. * * @param group * Contextual task group. * @return true if the ribbon tasks in the specified group are * visible, false otherwise. */ public synchronized boolean isVisible(RibbonContextualTaskGroup group) { return this.groupVisibilityMap.get(group); } /** * Sets the application menu for this ribbon. If null is * passed, the application menu button is hidden. Fires an * applicationMenu property change event. * * @param applicationMenu * The new application menu. Can be null. * @see #getApplicationMenu() */ public synchronized void setApplicationMenu( RibbonApplicationMenu applicationMenu) { RibbonApplicationMenu old = this.applicationMenu; if (old != applicationMenu) { this.applicationMenu = applicationMenu; if (this.applicationMenu != null) { this.applicationMenu.setFrozen(); } this.firePropertyChange("applicationMenu", old, this.applicationMenu); } } /** * Returns the application menu of this ribbon. * * @return The application menu of this ribbon. * @see #setApplicationMenu(RibbonApplicationMenu) */ public synchronized RibbonApplicationMenu getApplicationMenu() { return this.applicationMenu; } /** * Sets the rich tooltip of the application menu button. Fires an * applicationMenuRichTooltip property change event. * * @param tooltip * The rich tooltip of the application menu button. * @see #getApplicationMenuRichTooltip() * @see #setApplicationMenu(RibbonApplicationMenu) */ public synchronized void setApplicationMenuRichTooltip(RichTooltip tooltip) { RichTooltip old = this.applicationMenuRichTooltip; this.applicationMenuRichTooltip = tooltip; this.firePropertyChange("applicationMenuRichTooltip", old, this.applicationMenuRichTooltip); } /** * Returns the rich tooltip of the application menu button. * * @return The rich tooltip of the application menu button. * @see #setApplicationMenuRichTooltip(RichTooltip) * @see #setApplicationMenu(RibbonApplicationMenu) */ public synchronized RichTooltip getApplicationMenuRichTooltip() { return this.applicationMenuRichTooltip; } /** * Sets the key tip of the application menu button. Fires an * applicationMenuKeyTip property change event. * * @param keyTip * The new key tip for the application menu button. * @see #setApplicationMenu(RibbonApplicationMenu) * @see #getApplicationMenuKeyTip() */ public synchronized void setApplicationMenuKeyTip(String keyTip) { String old = this.applicationMenuKeyTip; this.applicationMenuKeyTip = keyTip; this.firePropertyChange("applicationMenuKeyTip", old, this.applicationMenuKeyTip); } /** * Returns the key tip of the application menu button. * * @return The key tip of the application menu button. * @see #setApplicationMenuKeyTip(String) * @see #setApplicationMenu(RibbonApplicationMenu) */ public synchronized String getApplicationMenuKeyTip() { return this.applicationMenuKeyTip; } /** * Returns the indication whether this ribbon is minimized. * * @return true if this ribbon is minimized, false * otherwise. * @see #setMinimized(boolean) */ public synchronized boolean isMinimized() { return this.isMinimized; } /** * Changes the minimized state of this ribbon. Fires a * minimized property change event. * * @param isMinimized * if true, this ribbon becomes minimized, otherwise * it is unminimized. */ public synchronized void setMinimized(boolean isMinimized) { // System.out.println("Ribbon minimized -> " + isMinimized); boolean old = this.isMinimized; if (old != isMinimized) { this.isMinimized = isMinimized; this.firePropertyChange("minimized", old, this.isMinimized); } } /** * Returns the ribbon frame that hosts this ribbon. The result can be * null. * * @return The ribbon frame that hosts this ribbon. */ public JRibbonFrame getRibbonFrame() { return this.ribbonFrame; } /* * (non-Javadoc) * * @see javax.swing.JComponent#setVisible(boolean) */ @Override public void setVisible(boolean flag) { if (!flag && (getRibbonFrame() != null)) throw new IllegalArgumentException( "Can't hide ribbon on JRibbonFrame"); super.setVisible(flag); } }




© 2015 - 2025 Weber Informatics LLC | Privacy Policy