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

org.pushingpixels.radiance.component.api.ribbon.JRibbonFrame Maven / Gradle / Ivy

Go to download

Demonstrating the abilities of the Swing UI Toolkit swingset2 and swingx aka swingset3

The newest version!
/*
 * Copyright (c) 2005-2021 Radiance 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 the copyright holder 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.radiance.component.api.ribbon;

import org.pushingpixels.radiance.component.api.common.CommandButtonPresentationState;
import org.pushingpixels.radiance.component.api.common.JCommandButton;
import org.pushingpixels.radiance.component.api.common.model.Command;
import org.pushingpixels.radiance.component.api.common.model.CommandMenuContentModel;
import org.pushingpixels.radiance.component.api.common.popup.JCommandPopupMenu;
import org.pushingpixels.radiance.component.api.common.popup.JPopupPanel;
import org.pushingpixels.radiance.component.api.common.popup.PopupPanelManager;
import org.pushingpixels.radiance.component.api.common.popup.model.CommandPopupMenuPresentationModel;
import org.pushingpixels.radiance.component.api.common.projection.CommandButtonProjection;
import org.pushingpixels.radiance.component.api.common.projection.CommandPopupMenuProjection;
import org.pushingpixels.radiance.component.api.common.projection.Projection;
import org.pushingpixels.radiance.component.api.ribbon.projection.RibbonGalleryProjection;
import org.pushingpixels.radiance.component.api.ribbon.synapse.model.ComponentContentModel;
import org.pushingpixels.radiance.component.api.ribbon.synapse.projection.ComponentProjection;
import org.pushingpixels.radiance.component.internal.theming.ribbon.ui.RadianceRibbonFrameTitlePane;
import org.pushingpixels.radiance.component.internal.ui.common.RadianceInternalButton;
import org.pushingpixels.radiance.component.internal.utils.ComponentUtilities;
import org.pushingpixels.radiance.component.internal.utils.KeyTipManager;
import org.pushingpixels.radiance.component.internal.utils.KeyTipManager.KeyTipEvent;
import org.pushingpixels.radiance.component.internal.utils.KeyTipRenderingUtilities;
import org.pushingpixels.radiance.common.api.AsynchronousLoadListener;
import org.pushingpixels.radiance.common.api.AsynchronousLoading;
import org.pushingpixels.radiance.common.api.RadianceCommonCortex;
import org.jdesktop.swingx.icon.RadianceIcon;
import org.pushingpixels.radiance.component.internal.ui.ribbon.*;
import org.pushingpixels.radiance.theming.internal.utils.RadianceCoreUtilities;
import org.pushingpixels.radiance.theming.internal.utils.RadiancePopupContainer;

import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
import java.util.List;
import java.util.*;
import java.util.concurrent.CountDownLatch;

/**
 * 

* Ribbon frame. Provides the same functionality as a regular {@link JFrame}, but with a * {@link JRibbon} component in the top location. *

* *

* This is the only officially supported way to use the {@link JRibbon} container. While * {@link JRibbon#JRibbon()} constructor is public, it is provided only for the applications that * are absolutely prevented from using {@link JRibbonFrame} class. *

* *

* The implementation enforces that a {@link JRibbon} component is always at the * {@link BorderLayout#NORTH} location, throwing {@link IllegalArgumentException} on attempts to set * a custom layout manager, add another component at {@link BorderLayout#NORTH}, remove the * {@link JRibbon} component, set a custom menu bar, content pane or any other operation that * interferes with the intended hierarchy of this frame. *

* * @author Kirill Grouchnikov */ public class JRibbonFrame extends JFrame { /** * The ribbon component. */ private JRibbon ribbon; private boolean wasSetIconImagesCalled; private AWTEventListener awtEventListener; private KeyTipManager.KeyTipListener keyTipListener; /** * Custom layout manager that enforces the {@link JRibbon} location at * {@link BorderLayout#NORTH}. * * @author Kirill Grouchnikov */ private static class RibbonFrameLayout extends BorderLayout { @Override public void addLayoutComponent(Component comp, Object constraints) { if ((constraints != null) && constraints.equals(BorderLayout.NORTH)) { if (getLayoutComponent(BorderLayout.NORTH) != null) { throw new IllegalArgumentException("Already has a NORTH JRibbon component"); } if (!(comp instanceof JRibbon)) { throw new IllegalArgumentException( "Can't add non-JRibbon component to NORTH location"); } } super.addLayoutComponent(comp, constraints); } @Override public void removeLayoutComponent(Component comp) { if (comp instanceof JRibbon) { throw new IllegalArgumentException("Can't remove JRibbon component"); } super.removeLayoutComponent(comp); } } /** * A custom layer that shows the currently visible key tip chain. * * @author Kirill Grouchnikov */ private static class KeyTipLayer extends JComponent { /** * Creates a new key tip layer. */ public KeyTipLayer() { this.setOpaque(false); // Support placing heavyweight components in the ribbon frame. See // https://community.oracle.com/docs/DOC-982814. this.setMixingCutoutShape(new Rectangle()); } @Override public synchronized void addMouseListener(MouseListener l) { } @Override public synchronized void addMouseMotionListener(MouseMotionListener l) { } @Override public synchronized void addMouseWheelListener(MouseWheelListener l) { } @Override public synchronized void addKeyListener(KeyListener l) { } @Override protected void paintComponent(Graphics g) { JRibbonFrame ribbonFrame = (JRibbonFrame) SwingUtilities.getWindowAncestor(this); if (!ribbonFrame.isShowingKeyTips()) { return; } // don't show keytips on inactive windows if (!ribbonFrame.isActive()) { return; } Collection keyTips = KeyTipManager.defaultManager() .getCurrentlyShownKeyTips(); if (keyTips != null) { Graphics2D g2d = (Graphics2D) g.create(); RadianceCommonCortex.installDesktopHints(g2d, getFont()); for (KeyTipManager.KeyTipLink keyTip : keyTips) { // Components in generic popup panels do not display keytips as that interferes // with the popup layer in the root pane. However, there is a special treatment // for the taskbar overflow popup where the height is limited and we push the // key tips to be displayed below the popup. boolean isInPopup = (SwingUtilities.getAncestorOfClass( JPopupPanel.class, keyTip.comp) != null); if (isInPopup && (SwingUtilities.getAncestorOfClass( RadianceRibbonFrameTitlePane.TaskbarOverflowPopupPanel.class, keyTip.comp) == null)) { continue; } // don't display key tips on hidden components Rectangle compBounds = keyTip.comp.getBounds(); if (!keyTip.comp.isShowing() || (compBounds.getWidth() == 0) || (compBounds.getHeight() == 0)) { continue; } Dimension pref = KeyTipRenderingUtilities.getPrefSize(g2d.getFontMetrics(), keyTip.keyTipString); Point prefCenter = keyTip.prefAnchorPoint; Point loc = SwingUtilities.convertPoint(keyTip.comp, prefCenter, this); Container bandControlPanel = SwingUtilities .getAncestorOfClass(AbstractBandControlPanel.class, keyTip.comp); if (bandControlPanel != null) { // special case for controls in threesome ribbon band rows if (hasClientPropertySetToTrue(keyTip.comp, BasicBandControlPanelUI.TOP_ROW)) { loc = SwingUtilities.convertPoint(keyTip.comp, prefCenter, bandControlPanel); loc.y = 0; loc = SwingUtilities.convertPoint(bandControlPanel, loc, this); // prefCenter.y = 0; } if (hasClientPropertySetToTrue(keyTip.comp, BasicBandControlPanelUI.MID_ROW)) { loc = SwingUtilities.convertPoint(keyTip.comp, prefCenter, bandControlPanel); loc.y = bandControlPanel.getHeight() / 2; loc = SwingUtilities.convertPoint(bandControlPanel, loc, this); // prefCenter.y = keyTip.comp.getHeight() / 2; } if (hasClientPropertySetToTrue(keyTip.comp, BasicBandControlPanelUI.BOTTOM_ROW)) { loc = SwingUtilities.convertPoint(keyTip.comp, prefCenter, bandControlPanel); loc.y = bandControlPanel.getHeight(); loc = SwingUtilities.convertPoint(bandControlPanel, loc, this); // prefCenter.y = keyTip.comp.getHeight(); } } Container taskbarOverflowPanel = SwingUtilities .getAncestorOfClass( RadianceRibbonFrameTitlePane.TaskbarOverflowPopupPanel.class, keyTip.comp); if (taskbarOverflowPanel != null) { // special case for controls in taskbar overflow - push them down loc = SwingUtilities.convertPoint(keyTip.comp, prefCenter, taskbarOverflowPanel); loc.y = pref.height / 2 + taskbarOverflowPanel.getHeight(); loc = SwingUtilities.convertPoint(taskbarOverflowPanel, loc, this); } Container titlePane = SwingUtilities .getAncestorOfClass(RadianceRibbonFrameTitlePane.class, keyTip.comp); if (titlePane != null) { // special case for controls in title pane (taskbar) loc = SwingUtilities.convertPoint(keyTip.comp, prefCenter, titlePane); loc.y = pref.height / 2 + titlePane.getHeight() / 2; loc = SwingUtilities.convertPoint(titlePane, loc, this); } KeyTipRenderingUtilities.renderKeyTip( g2d, this, new Rectangle(loc.x - pref.width / 2, loc.y - pref.height / 2, pref.width, pref.height), keyTip.keyTipString, keyTip.enabled); } g2d.dispose(); } } /** * Checks whether the specified component or one of its ancestors has the specified client * property set to {@link Boolean#TRUE}. * * @param c Component. * @param clientPropName Client property name. * @return true if the specified component or one of its ancestors has the * specified client property set to {@link Boolean#TRUE}, false * otherwise. */ private boolean hasClientPropertySetToTrue(Component c, String clientPropName) { while (c != null) { if (c instanceof JComponent) { JComponent jc = (JComponent) c; if (Boolean.TRUE.equals(jc.getClientProperty(clientPropName))) return true; } c = c.getParent(); } return false; } @Override public boolean contains(int x, int y) { // pass the mouse events to the underlying layers for // showing the correct cursor. See // https://community.oracle.com/blogs/alexfromsun/2006/09/20/well-behaved-glasspane return false; } } public static class RibbonKeyboardAction { private String actionName; private KeyStroke actionKeyStroke; private Command command; public RibbonKeyboardAction(String actionName, KeyStroke actionKeyStroke, Command command) { this.actionName = actionName; this.actionKeyStroke = actionKeyStroke; this.command = command; } public String getActionName() { return actionName; } public KeyStroke getActionKeyStroke() { return actionKeyStroke; } public Command getCommand() { return command; } } /** * Creates a new ribbon frame with no title. * * @throws HeadlessException If GraphicsEnvironment.isHeadless() returns true. */ public JRibbonFrame() throws HeadlessException { super(); this.initRibbon(); } /** * Creates a new ribbon frame with no title. * * @param gc Graphics configuration to use. */ public JRibbonFrame(GraphicsConfiguration gc) { super(gc); this.initRibbon(); } /** * Creates a new ribbon frame with the specified title. * * @param title Ribbon frame title. * @throws HeadlessException If GraphicsEnvironment.isHeadless() returns true. */ public JRibbonFrame(String title) throws HeadlessException { super(title); this.initRibbon(); } /** * Creates a new ribbon frame with the specified title. * * @param title Ribbon frame title. * @param gc Graphics configuration to use. * @throws HeadlessException If GraphicsEnvironment.isHeadless() returns true. */ public JRibbonFrame(String title, GraphicsConfiguration gc) { super(title, gc); this.initRibbon(); } @Override public void setLayout(LayoutManager manager) { if (manager.getClass() != RibbonFrameLayout.class) { LayoutManager currManager = getLayout(); if (currManager != null) { throw new IllegalArgumentException( "Can't set a custom layout manager on JRibbonFrame"); } } super.setLayout(manager); } @Override public void setJMenuBar(JMenuBar menubar) { throw new IllegalArgumentException("Can't set a menu bar on JRibbonFrame"); } @Override public void setContentPane(Container contentPane) { throw new IllegalArgumentException("Can't set the content pane on JRibbonFrame"); } /** * Initializes the layout and the ribbon. */ private void initRibbon() { this.setLayout(new RibbonFrameLayout()); this.ribbon = new JRibbon(this); this.add(this.ribbon, BorderLayout.NORTH); final KeyTipManager keyTipManager = KeyTipManager.defaultManager(); this.awtEventListener = new AWTEventListener() { private boolean prevAltModif = false; @Override public void eventDispatched(AWTEvent event) { Object src = event.getSource(); if (src instanceof Component) { Component c = (Component) src; if ((c == JRibbonFrame.this) || (SwingUtilities.getWindowAncestor(c) == JRibbonFrame.this)) { if (event instanceof KeyEvent) { KeyEvent keyEvent = (KeyEvent) event; // System.out.println(keyEvent.getID() + ":" // + keyEvent.getKeyCode()); switch (keyEvent.getID()) { case KeyEvent.KEY_RELEASED: boolean wasAltModif = prevAltModif; prevAltModif = (keyEvent.getModifiersEx() == InputEvent.ALT_DOWN_MASK); if (wasAltModif && keyEvent.getKeyCode() == KeyEvent.VK_ALT) { break; } char keyChar = keyEvent.getKeyChar(); if (Character.isLetter(keyChar) || Character.isDigit(keyChar)) { // System.out.println("Will handle key press " // + keyChar); keyTipManager.handleKeyPress(keyChar); } if ((keyEvent.getKeyCode() == KeyEvent.VK_ALT) || (keyEvent.getKeyCode() == KeyEvent.VK_F10)) { if (keyEvent.getModifiersEx() != 0) { break; } boolean hadPopups = !PopupPanelManager.defaultManager() .getShownPath().isEmpty(); PopupPanelManager.defaultManager().hidePopups(null); if (hadPopups || keyTipManager.isShowingKeyTips()) { keyTipManager.hideAllKeyTips(); } else { keyTipManager.showRootKeyTipChain(JRibbonFrame.this); } } if (keyEvent.getKeyCode() == KeyEvent.VK_ESCAPE) { // Dismiss keytips if showing if (keyTipManager.isShowingKeyTips()) { keyTipManager.showPreviousChain(); } } if (keyTipManager.isShowingKeyTips()) { // Traversal of ribbon tasks while keytips are showing switch (keyEvent.getKeyCode()) { case KeyEvent.VK_LEFT: RibbonTask previous = getPreviousRibbonTask(); if (previous != null) { ribbon.setSelectedTask(previous); } break; case KeyEvent.VK_RIGHT: RibbonTask next = getNextRibbonTask(); if (next != null) { ribbon.setSelectedTask(next); } break; } } break; } } if (event instanceof MouseEvent) { MouseEvent mouseEvent = (MouseEvent) event; switch (mouseEvent.getID()) { case MouseEvent.MOUSE_CLICKED: case MouseEvent.MOUSE_DRAGGED: { keyTipManager.hideAllKeyTips(); break; } case MouseEvent.MOUSE_PRESSED: case MouseEvent.MOUSE_RELEASED: { keyTipManager.hideAllKeyTips(); if (mouseEvent.isPopupTrigger()) { // Note that we need to find the deepest component // under the mouse event so that it is then routed // properly to the ribbon contextual click listener handlePopupTrigger(mouseEvent, SwingUtilities.getDeepestComponentAt(c, mouseEvent.getX(), mouseEvent.getY())); } else if (mouseEvent.getID() == MouseEvent.MOUSE_PRESSED) { if (SwingUtilities.getAncestorOfClass(JPopupPanel.class, c) == null) { PopupPanelManager.defaultManager().hidePopups(null); } } } } } } } } }; final KeyTipLayer keyTipLayer = new KeyTipLayer(); JRootPane rootPane = this.getRootPane(); JLayeredPane layeredPane = rootPane.getLayeredPane(); final LayoutManager currLM = rootPane.getLayout(); rootPane.setLayout(new LayoutManager() { public void addLayoutComponent(String name, Component comp) { currLM.addLayoutComponent(name, comp); } public void layoutContainer(Container parent) { currLM.layoutContainer(parent); JRibbonFrame ribbonFrame = JRibbonFrame.this; if (ribbonFrame.getRootPane().getWindowDecorationStyle() != JRootPane.NONE) { keyTipLayer.setBounds(ribbonFrame.getRootPane().getBounds()); } else { keyTipLayer.setBounds(ribbonFrame.getRootPane().getContentPane().getBounds()); } } public Dimension minimumLayoutSize(Container parent) { return currLM.minimumLayoutSize(parent); } public Dimension preferredLayoutSize(Container parent) { return currLM.preferredLayoutSize(parent); } public void removeLayoutComponent(Component comp) { currLM.removeLayoutComponent(comp); } }); layeredPane.add(keyTipLayer, (Integer) (JLayeredPane.DEFAULT_LAYER + 60)); this.addWindowListener(new WindowAdapter() { @Override public void windowDeactivated(WindowEvent e) { // hide all key tips on window deactivation KeyTipManager keyTipManager = KeyTipManager.defaultManager(); if (keyTipManager.isShowingKeyTips()) { keyTipManager.hideAllKeyTips(); } } }); this.keyTipListener = new KeyTipManager.KeyTipListener() { @Override public void keyTipsHidden(KeyTipEvent event) { if (event.getSource() == JRibbonFrame.this) { keyTipLayer.setVisible(false); } } @Override public void keyTipsShown(KeyTipEvent event) { if (event.getSource() == JRibbonFrame.this) { keyTipLayer.setVisible(true); } } }; ToolTipManager.sharedInstance().setLightWeightPopupEnabled(false); JPopupMenu.setDefaultLightWeightPopupEnabled(false); super.setIconImages(Collections.singletonList(RadianceCoreUtilities.getBlankImage( RadianceCommonCortex.getScaleFactor(null), 16, 16))); } @Override public void dispose() { RadianceCoreUtilities.unregisterAWTEventListener(this.awtEventListener); KeyTipManager.defaultManager().removeKeyTipListener(this.keyTipListener); super.dispose(); } @SuppressWarnings("deprecation") @Override public void show() { super.show(); RadianceCoreUtilities.registerAWTEventListener(this.awtEventListener); KeyTipManager.defaultManager().addKeyTipListener(this.keyTipListener); } @SuppressWarnings("deprecation") @Override public void hide() { RadianceCoreUtilities.unregisterAWTEventListener(this.awtEventListener); KeyTipManager.defaultManager().removeKeyTipListener(this.keyTipListener); super.hide(); } private boolean isValidPopupTriggerSource(Component c) { if (SwingUtilities.getAncestorOfClass(GlobalPopupMenu.class, c) != null) { // Don't display context menu on context menu entries return false; } if ((SwingUtilities.getAncestorOfClass(JRibbon.class, c) != null) || (SwingUtilities.getAncestorOfClass(RadianceRibbonFrameTitlePane.class, c) != null)) { // If the component is in the ribbon or in the ribbon frame title pane, it's valid return true; } // Is it in a popup panel? JPopupPanel popupPanel = (JPopupPanel) SwingUtilities.getAncestorOfClass( JPopupPanel.class, c); if (popupPanel == null) { return false; } while (true) { JComponent popupInvoker = popupPanel.getInvoker(); if (popupInvoker == null) { return false; } // Are we in a multi-cascade popup chain? popupPanel = (JPopupPanel) SwingUtilities.getAncestorOfClass( JPopupPanel.class, popupInvoker); if (popupPanel != null) { continue; } // At the "top" level of the popup chain // If the component is in the ribbon or in the ribbon frame title pane, it's valid boolean isValidChainRoot = (SwingUtilities.getAncestorOfClass(JRibbon.class, popupInvoker) != null) || (SwingUtilities.getAncestorOfClass(RadianceRibbonFrameTitlePane.class, popupInvoker) != null); return isValidChainRoot; } } private boolean isInTaskbar(Component c) { if (SwingUtilities.getAncestorOfClass(RadianceRibbonFrameTitlePane.class, c) != null) { return true; } // Is it in a popup panel? JPopupPanel popupPanel = (JPopupPanel) SwingUtilities.getAncestorOfClass( JPopupPanel.class, c); if (popupPanel == null) { return false; } while (true) { JComponent popupInvoker = popupPanel.getInvoker(); if (popupInvoker == null) { return false; } // Are we in a multi-cascade popup chain? popupPanel = (JPopupPanel) SwingUtilities.getAncestorOfClass( JPopupPanel.class, popupInvoker); if (popupPanel != null) { continue; } // At the "top" level of the popup chain return (SwingUtilities.getAncestorOfClass(RadianceRibbonFrameTitlePane.class, popupInvoker) != null); } } @RadiancePopupContainer public static class GlobalPopupMenu extends JCommandPopupMenu { public GlobalPopupMenu(Projection projection) { super(projection); } } @SuppressWarnings("unchecked") private void handlePopupTrigger(MouseEvent event, Component c) { if (!isValidPopupTriggerSource(c)) { // Component not in the ribbon. Do nothing. return; } JRibbon.OnShowContextualMenuListener onShowContextualMenuListener = this.ribbon.getOnShowContextualMenuListener(); if (onShowContextualMenuListener == null) { return; } CommandMenuContentModel menuContentModel = null; // Special case - the component is in the taskbar. if (isInTaskbar(c)) { Object projection = null; // Is it a wrapped component JRibbonComponent taskbarWrapped = (JRibbonComponent) SwingUtilities.getAncestorOfClass( JRibbonComponent.class, c); if (taskbarWrapped != null) { projection = taskbarWrapped.getClientProperty(ComponentUtilities.TASKBAR_PROJECTION); } else { projection = ((JComponent) c).getClientProperty( ComponentUtilities.TASKBAR_PROJECTION); } if (projection instanceof RibbonGalleryProjection) { menuContentModel = onShowContextualMenuListener.getContextualMenuContentModel( ribbon, (RibbonGalleryProjection) projection); } else if (projection instanceof ComponentProjection) { menuContentModel = onShowContextualMenuListener.getContextualMenuContentModel( ribbon, (ComponentProjection) projection); } else if (projection instanceof CommandButtonProjection) { CommandButtonProjection commandButtonProjection = (CommandButtonProjection) projection; menuContentModel = onShowContextualMenuListener.getContextualMenuContentModel( ribbon, commandButtonProjection); } else { menuContentModel = onShowContextualMenuListener.getContextualMenuContentModel(ribbon); } } else { // Special case - popup trigger in a ribbon gallery JRibbonGallery gallery = (JRibbonGallery) SwingUtilities.getAncestorOfClass( JRibbonGallery.class, c); if (gallery != null) { menuContentModel = onShowContextualMenuListener.getContextualMenuContentModel( ribbon, gallery.getProjection()); } else { // Another special case - wrapped component JRibbonComponent component = (JRibbonComponent) SwingUtilities.getAncestorOfClass( JRibbonComponent.class, c); if (component != null) { menuContentModel = onShowContextualMenuListener.getContextualMenuContentModel( ribbon, component.getProjection()); } else { if ((c instanceof JCommandButton) && (!(c instanceof RadianceInternalButton))) { menuContentModel = onShowContextualMenuListener.getContextualMenuContentModel( ribbon, ((JCommandButton) c).getProjection()); } } } } if (menuContentModel == null) { // If the popup trigger is not on any of the "supported" ribbon content, ask the // application to provide the general contextual menu items menuContentModel = onShowContextualMenuListener.getContextualMenuContentModel(ribbon); } CommandPopupMenuProjection globalContextMenuProjection = new CommandPopupMenuProjection( menuContentModel, CommandPopupMenuPresentationModel.builder() .setMenuPresentationState(CommandButtonPresentationState.MEDIUM) .build()); globalContextMenuProjection.setComponentSupplier(projection -> GlobalPopupMenu::new); final JCommandPopupMenu menu = globalContextMenuProjection.buildComponent(); int x = event.getXOnScreen(); int y = event.getYOnScreen(); Rectangle scrBounds = this.ribbon.getGraphicsConfiguration().getBounds(); int pw = menu.getPreferredSize().width; if ((x + pw) > (scrBounds.x + scrBounds.width)) { x = scrBounds.x + scrBounds.width - pw; } int ph = menu.getPreferredSize().height; if ((y + ph) > (scrBounds.y + scrBounds.height)) { y = scrBounds.y + scrBounds.height - ph; } PopupPanelManager.defaultManager().hidePopups(c); Popup popup = PopupFactory.getSharedInstance().getPopup(ribbon, menu, x, y); PopupPanelManager.defaultManager().addPopup((JComponent) c, popup, menu); } /** * Returns the ribbon component. * * @return Ribbon component. */ public JRibbon getRibbon() { return this.ribbon; } @Override protected JRootPane createRootPane() { JRootPane rp = new JRibbonRootPane(); rp.setOpaque(true); return rp; } public void setKeyboardActions(Set actions) { JRibbonRootPane rootPane = (JRibbonRootPane) this.getRootPane(); rootPane.setKeyboardActions(actions); } @Override public synchronized void setIconImages(List icons) { super.setIconImages(icons); this.wasSetIconImagesCalled = true; } public synchronized void setApplicationIcon(final RadianceIcon.Factory iconFactory) { if (iconFactory == null) { return; } // Important - the work to convert the resizable icon content to images suited // to be passed to the underlying Swing / platform APIs needs to happen off the // UI thread. new Thread(() -> setApplicationAndMenuButtonIcon(iconFactory)).start(); } private void setApplicationAndMenuButtonIcon(final RadianceIcon.Factory iconFactory) { final Image icon16 = getImage(iconFactory, 16); if (RadianceCommonCortex.getPlatform() == RadianceCommonCortex.Platform.MACOS) { SwingUtilities.invokeLater(() -> setLegacyIconImages( Collections.singletonList(icon16))); } else { SwingUtilities.invokeLater(() -> setLegacyIconImages(Arrays.asList(icon16, getImage(iconFactory, 32), getImage(iconFactory, 64)))); } // Set the taskbar / dock icon SwingUtilities.invokeLater(() -> { Taskbar taskbar = Taskbar.getTaskbar(); if (taskbar.isSupported(Taskbar.Feature.ICON_IMAGE)) { taskbar.setIconImage(getImage(iconFactory, 256)); } }); } private void setLegacyIconImages(List images) { if (this.wasSetIconImagesCalled) { return; } super.setIconImages(images); } private static Image getImage(RadianceIcon.Factory iconFactory, int size) { RadianceIcon icon = iconFactory.createNewIcon(); icon.setDimension(new Dimension(size, size)); if (icon instanceof AsynchronousLoading) { AsynchronousLoading async = (AsynchronousLoading) icon; if (async.isLoading()) { final CountDownLatch latch = new CountDownLatch(1); final boolean[] status = new boolean[1]; AsynchronousLoadListener all = (boolean success) -> { status[0] = success; latch.countDown(); }; async.addAsynchronousLoadListener(all); try { latch.await(); } catch (InterruptedException ie) { } async.removeAsynchronousLoadListener(all); if (!status[0]) { return null; } if (async.isLoading()) { return null; } } } Image result = RadianceCoreUtilities.getBlankImage( RadianceCommonCortex.getScaleFactor(null), size, size); Graphics2D g2d = (Graphics2D) result.getGraphics().create(); icon.paintIcon(null, g2d, 0, 0); g2d.dispose(); return result; } /** * Returns indication whether this ribbon frame is showing the key tips. * * @return true if this ribbon frame is showing the key tips, false * otherwise. */ public boolean isShowingKeyTips() { return KeyTipManager.defaultManager().isShowingKeyTips(); } private List getAllShownRibbonTasks() { List result = new ArrayList<>(); for (int i = 0; i < this.ribbon.getTaskCount(); i++) { result.add(this.ribbon.getTask(i)); } for (int i = 0; i < this.ribbon.getContextualTaskGroupCount(); i++) { RibbonContextualTaskGroup curr = this.ribbon.getContextualTaskGroup(i); if (this.ribbon.isVisible(curr)) { for (int j = 0; j < curr.getTaskCount(); j++) { result.add(curr.getTask(j)); } } } return Collections.unmodifiableList(result); } private RibbonTask getNextRibbonTask() { List all = getAllShownRibbonTasks(); int indexOfCurrent = all.indexOf(this.ribbon.getSelectedTask()); if (indexOfCurrent < 0) { return null; } if (indexOfCurrent == (all.size() - 1)) { return null; } return all.get(indexOfCurrent + 1); } private RibbonTask getPreviousRibbonTask() { List all = getAllShownRibbonTasks(); int indexOfCurrent = all.indexOf(this.ribbon.getSelectedTask()); if (indexOfCurrent < 0) { return null; } if (indexOfCurrent == 0) { return null; } return all.get(indexOfCurrent - 1); } }




© 2015 - 2025 Weber Informatics LLC | Privacy Policy