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

net.roydesign.ui.JScreenMenu Maven / Gradle / Ivy

Go to download

MRJ Adapter is a wrapper around built in Java Virtual Machine APIs provided by Apple.

The newest version!
/*******************************************************************************

	File:		JScreenMenu.java
	Author:		Steve Roy 
				
	Part of MRJ Adapter, a unified API for easy integration of Mac OS specific
	functionality within your cross-platform Java application.
	
	This library is open source and can be modified and/or distributed under
	the terms of the Artistic License.
	
	
	Change History:
	12/30/02	Created this file - Steve
	02/26/04    Merged into MRJ Adapter - Steve
	04/16/04    Renamed from JMenu to JScreenMenu - Steve

*******************************************************************************/

package net.roydesign.ui;

import net.roydesign.mac.MRJAdapter;

import javax.swing.Action;
import javax.swing.JFrame;
import javax.swing.JMenu;
import javax.swing.JMenuItem;
import javax.swing.JSeparator;
import java.awt.Component;
import java.awt.event.ComponentAdapter;
import java.awt.event.ComponentEvent;
import java.awt.event.ComponentListener;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.util.ArrayList;
import java.util.List;

/**
 * 

A subclass of {@code javax.swing.JMenu} that adds the logistics * needed to make menu bars conform to the Mac OS screen menu bar requirements * without sacrificing the usual way of presenting menu bars on other platforms. * See the class {@code JScreenMenuBar} for more details.

* *

Additionally, if an instance of this class is populated with instances * of JScreenMenuItem, or simply other {@code JScreenMenus}, * then the menu will automatically disable itself when all its items are * disabled, and automatically enable itself back when one of the items becomes * enabled. This is the kind of behavior expected by users from a quality * desktop application and this class takes care of the work for you.

* *

Finally, this class fixes a bug in the Aqua L&F of the Java 1.3.1 VM * from Apple where the disabling the menu before the parent frame is shown * has no effect for Swing menus when using the screen menu bar.

* * @see JScreenMenuBar * * @version MRJ Adapter 1.2 */ public class JScreenMenu extends JMenu implements PropertyChangeListener { /** * The component listener that works around the bug on Mac OS X with * Java 1.3.1 where disabling the menu before the parent frame is shown * has no effect for Swing menus when using the screen menu bar. */ private static final ComponentListener initialStateSetterMRJ3 = new ComponentAdapter() { @Override public void componentResized(ComponentEvent e) { Component comp = e.getComponent(); comp.removeComponentListener(this); if (!comp.isEnabled()) { comp.setEnabled(true); comp.setEnabled(false); } } }; /** * The user frames of this menu. */ private final List> userFrames = new ArrayList<>(); /** * Construct a menu. */ public JScreenMenu() { super(""); } /** * Construct a menu with the given text as the title. * @param text the menu title */ public JScreenMenu(String text) { super(text); } /** * This method is overriden to support automatic enabling and * disabling. * @param menuItem the menu item to be added * @return the menu item added */ @Override public JMenuItem add(JMenuItem menuItem) { menuItem.addPropertyChangeListener(this); return super.add(menuItem); } /** * This method is overriden to support automatic enabling and * disabling. * @param comp the component to be added * @return the component added */ @Override public Component add(Component comp) { comp.addPropertyChangeListener(this); return super.add(comp); } /** * This method is overriden to support automatic enabling and * disabling. * @param comp the component to be added * @param index the index where to insert the component * @return the component added */ @Override public Component add(Component comp, int index) { comp.addPropertyChangeListener(this); return super.add(comp, index); } /** * This method is overriden to support automatic enabling and * disabling. * @param menuItem the menu item to be removed */ @Override public void remove(JMenuItem menuItem) { menuItem.removePropertyChangeListener(this); super.remove(menuItem); } /** * This method is overriden to support automatic enabling and * disabling. * @param index the index of the menu item to be removed */ @Override public void remove(int index) { getItem(index).removePropertyChangeListener(this); super.remove(index); } /** * This method is overriden to support automatic enabling and * disabling. * @param comp the component to be removed */ @Override public void remove(Component comp) { comp.removePropertyChangeListener(this); super.remove(comp); } /** * This method is overriden to support automatic enabling and * disabling. */ @Override public void removeAll() { int n = getMenuComponentCount(); for (int i = 0; i < n; i++) getMenuComponent(i).removePropertyChangeListener(this); super.removeAll(); } /** * This method is overriden to disable or hide the items that don't * belong in the menu for the parent frame. */ @Override public void addNotify() { // Get the parent frame JFrame f = getParentFrame(); // Loop through all menu items and check if the frame // makes any use of each one boolean disabled = true; boolean hasSeparator = true; int n = getMenuComponentCount(); for (int i = n - 1; i >= 0; i--) { Component comp = getMenuComponent(i); if (comp instanceof JSeparator) { if (hasSeparator) { comp.setVisible(false); /** @todo With MRJ 2.x (Swing 1.1.1), the space is not reclaimed */ continue; } hasSeparator = true; } else if (comp instanceof JScreenMenuItem) { JScreenMenuItem mi = (JScreenMenuItem)comp; Action a = mi.getAction(); if (a != null && a instanceof AbstractScreenAction && ((AbstractScreenAction)a).isNotUsedBy(f) || !mi.isUsedBy(f)) { if (MRJAdapter.isSwingUsingScreenMenuBar()) { mi.setEnabled(false); hasSeparator = false; } else { mi.setVisible(false); /** @todo With MRJ 2.x (Swing 1.1.1), the space is not reclaimed */ } } else { hasSeparator = false; } } else if (comp instanceof JScreenMenu) { JScreenMenu m = (JScreenMenu)comp; if (m.isUsedBy(f)) { hasSeparator = false; } else { if (MRJAdapter.isSwingUsingScreenMenuBar()) hasSeparator = false; } m.addNotify(); } else { hasSeparator = false; } if (comp.isVisible() && comp.isEnabled() && !(comp instanceof JSeparator)) disabled = false; } // Disable the menu if all its items are invisible or disabled if (disabled) setEnabled(false); super.addNotify(); } /** * Add the given {@code JFrame} subclass as a user * of the menu. When a menu has no user frames, then all * frames get the menu. * * @param frameClass the {@code JFrame} subclass */ public void addUserFrame(Class frameClass) { userFrames.add(frameClass); } /** * Remove the given {@code JFrame} subclass from the users * of the menu. * * @param frameClass the {@code JFrame} subclass */ public void removeUserFrame(Class frameClass) { userFrames.remove(frameClass); } /** * Get whether the menu is used by the given frame instance. * @return whether the menu is used by the given frame */ public boolean isUsedBy(JFrame frame) { return userFrames.contains(frame.getClass()); } /** * Get the parent frame of the menu. * @return the parent {@code JFrame} */ protected JFrame getParentFrame() { Component comp = getParent(); while (comp != null && !(comp instanceof JFrame)) comp = comp.getParent(); return (JFrame)comp; } /** * Implementation of the property listener interface. This method * disables the menu when all its items are disabled. Conversely, * it enables the menu when at least one of its items is enabled. * @param e the property change event */ @Override public void propertyChange(PropertyChangeEvent e) { if ("enabled".equals(e.getPropertyName())) { if ((Boolean) e.getNewValue()) { setEnabled(true); /** @todo The UI is not repainted when useScreenMenuBar=true on Mac OS X */ } else { int n = getMenuComponentCount(); for (int i = 0; i < n; i++) { Component comp = getMenuComponent(i); if (comp.isVisible() && comp.isEnabled() && !(comp instanceof JSeparator)) return; } setEnabled(false); /** @todo The UI is not repainted when useScreenMenuBar=true on Mac OS X */ } } } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy