alvinalexander.com | career | drupal | java | mac | mysql | perl | scala | uml | unix  

What this is

This file is included in the DevDaily.com "Java Source Code Warehouse" project. The intent of this project is to help you "Learn Java by Example" TM.

Other links

The source code

/*
 *                 Sun Public License Notice
 * 
 * The contents of this file are subject to the Sun Public License
 * Version 1.0 (the "License"). You may not use this file except in
 * compliance with the License. A copy of the License is available at
 * http://www.sun.com/
 * 
 * The Original Code is NetBeans. The Initial Developer of the Original
 * Code is Sun Microsystems, Inc. Portions Copyright 1997-2003 Sun
 * Microsystems, Inc. All Rights Reserved.
 */

package org.openide.awt;

import java.awt.*;
import java.awt.event.*;
import java.io.*;
import java.util.List;

import javax.swing.*;
import javax.swing.event.*;

/**
 * Menu element that can contain other menu items. These items are then
 * displayed "inline". The JInlineMenu can be used to componse more menu items
 * into one that can be added/removed at once.
 * 
 * @deprecated JInlineMenu is resizing itself after being displayed, this
 * behavior causes a lot of troubles for Swing/AWT on various platforms.  Very
 * hard to be fixed.  Module developers should stop using this class.
 * 
 * @author Jan Jancura
 */
public class JInlineMenu extends JMenuItem {
    /** generated Serialized Version UID */
    static final long serialVersionUID = -2310488127953523571L;

    /** north separator */
    private JSeparator north = new JSeparator ();
    /** south separator */
    private JSeparator south = new JSeparator ();
    /** Stores inner MenuItems added to outer menu. */
    private JComponent[] items = new JComponent[0];
    
    /** true iff items of this menu are up to date */
    boolean upToDate;
    
    /** private List of the items previously added to the parent menu */
    private List addedItems;
    
    /**
    * Creates new JInlineMenu.
    */
    public JInlineMenu () {
        setEnabled (false);
        upToDate = true;
    }

    /** Overriden to eliminate big gap at top of JInline popup painting.
     * @return cleared instets (0, 0, 0, 0) */
    public Insets getInsets() {
        return new Insets(0, 0, 0, 0);
    }

    /**
     * Setter for array of items to display. Can be called only from event queue
     * thread.
     *
     * @param newItems array of menu items to display
     */
    public void setMenuItems (final JMenuItem[] newItems) {
//        if(!SwingUtilities.isEventDispatchThread()) {
//System.err.println("JInlineMenu.setMenuItems called outside of event queue !!!");
//Thread.dumpStack();
//        }
            
        // make a tuned private copy
        JComponent[] local = new JComponent[newItems.length];
        for(int i = 0; i < newItems.length; i++) {
            local[i] = newItems[i] != null ? (JComponent)newItems[i] : new JSeparator();
        }
        items = local;
        upToDate = false;
        
        // tell the parent it is not up-to-date as well
        Container parent = getParent();
        while (parent instanceof JInlineMenu) {
            ((JInlineMenu)parent).upToDate = false;
            parent = parent.getParent();
        }
        
        if (isShowing()) { // Ugly thing have happened - we're already visible
//System.err.println("JInlineMenu.setMenuItems on visible is deprecated !!!");
//Thread.dumpStack();
            SwingUtilities.invokeLater(new Updater());
        }
    }
    
    /* This method is overriden so that this class now allow following
     * pattern to be used:
     *
     * (1) nm = new JInlineMenu();
     * (2) nm.setMenuItems( ... some items ... );
     * (3) myJPopupMenu.add(nm);
     *
     * While the old source required (1) (3) and (2)
     */
    public void addNotify() { // addNotify it quite late to do anything, but we'll try
        super.addNotify();
        if (!upToDate) {
//System.err.println("InvokeLater-ing from addNotify()");
            SwingUtilities.invokeLater(new Updater());
        }
    }

    static void prepareItemsInContainer(Container c) {
        Component[] comps = c.getComponents();
        for (int i=0; iJInlineMenu's. Used only by parent
     * JInlineMenu. */
    private void getAllInlineItems(List its) {
        for(int i = 0; i < items.length; i++) {
            Object item = items[i];
            
            if(item instanceof JInlineMenu) {
                ((JInlineMenu)item).getAllInlineItems(its);
            } else {
                its.add(item);
            }
        }
    }

    /** Finds the index of a component in array of components.
     * @return index or -1
     */
    private static int findIndex (Object of, Object[] arr) {
        int menuLength = arr.length;
        for (int i = 0; i < menuLength; i++) {
            if (of == arr[i]) {
                return i;
            }
        }
        return -1;
    }

    void addItems () {
        JComponent m = (JComponent) getParent ();
        if (m == null) return; // Can't happen

        boolean usedToBeContained = false;
        if (m instanceof JPopupMenu) {
            usedToBeContained = JPopupMenuUtils.isPopupContained ((JPopupMenu) m);
        }

        // Get all items, including those ones from sub-JInlineMenu's.
        List its = new java.util.ArrayList(items.length);
        getAllInlineItems(its);
        JComponent[] items = (JComponent[])its.toArray(new JComponent[its.size()]);
        addedItems = its;
        
        // Find me please!
        Component[] array = m.getComponents ();

        int menuPos = findIndex (this, array);
        if (menuPos == -1) return; // not found? strange!

        if (
            menuPos > 0 &&
            items.length > 0 &&
            array.length > 0 && /* should be always true */
            !(array[menuPos - 1] instanceof JSeparator) &&
            !(array[menuPos - 1] instanceof JInlineMenu)
        ) { // not first and not after separator or another inline menu ==>> add separator before
            m.add (north, menuPos++);
            array = m.getComponents ();
        }

        if (menuPos < array.length - 1) {
            // not last
            if (
                items.length > 0 &&
                !(array[menuPos + 1] instanceof JPopupMenu.Separator) &&
                !(array[menuPos + 1] instanceof JSeparator)
            ) {
                // adding non-zero items and not before separator
                m.add (south, menuPos + 1);
            } else if (
                items.length == 0 &&
                (array[menuPos + 1] instanceof JPopupMenu.Separator
                 || array[menuPos + 1] instanceof JSeparator)
            ) {
                // adding zero items and there is an extra separator after the JInlineMenu item ==>> remove it
                m.remove (menuPos + 1);
                array = m.getComponents();
            }
        }

        // Add components to outer menu.
        if (menuPos > array.length) {
            int menuLength = items.length;
            for (int i = 0; i < menuLength; i++) {
                m.add (items[i]);
            }
        } else {
            int menuLength = items.length;
            for (int i = 0; i < menuLength; i++) {
                m.add (items[i], ++menuPos);
                // advance menuPos for JInlineMenu
                // otherwise the next item will be
                // actually placed before expanded
                // items of this JInlineMenu
                if (items[i] instanceof JInlineMenu) {
                    JInlineMenu him = (JInlineMenu) items[i];
                    menuPos += him.items.length;
                }
            }
        }
        
        if(m instanceof JPopupMenu && m.isShowing()) {
            // This can happen when somebody call setMenuItems on visible
            JPopupMenuUtils.dynamicChange((JPopupMenu)m, usedToBeContained);
        } else {
            // ensure correct preferred size computation
            m.invalidate();
        }
    }

    private class Updater implements Runnable {
        Updater() {}
        public void run() {
            updateContents();
        }
    }        

}
... this post is sponsored by my books ...

#1 New Release!

FP Best Seller

 

new blog posts

 

Copyright 1998-2021 Alvin Alexander, alvinalexander.com
All Rights Reserved.

A percentage of advertising revenue from
pages under the /java/jwarehouse URI on this website is
paid back to open source projects.