/*
 * This file is part of muCommander, http://www.mucommander.com
 *
 * muCommander is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 3 of the License, or
 * (at your option) any later version.
 *
 * muCommander is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

package com.mucommander.ui.button;

import java.awt.BorderLayout;
import java.awt.Component;
import java.awt.Insets;
import java.awt.Rectangle;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.ComponentAdapter;
import java.awt.event.ComponentEvent;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;

import javax.swing.AbstractButton;
import javax.swing.JPanel;
import javax.swing.JPopupMenu;
import javax.swing.JSeparator;
import javax.swing.JToggleButton;
import javax.swing.JToolBar;
import javax.swing.event.PopupMenuEvent;
import javax.swing.event.PopupMenuListener;

import com.mucommander.commons.runtime.OsFamily;
import com.mucommander.ui.icon.IconManager;

/*
 * MySwing: Advanced Swing Utilites
 * Copyright (C) 2005  Santhosh Kumar T
 * <p/>
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 * <p/>
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 */

/**
 * Provides a way for toolbar buttons to be displayed when the toolbar itself doesn't have enough space for all buttons.
 * The buttons that are cropped are displayed in a secondary toolbar, using a vertical layout.
 * <p>
 * To use this Feature replace:
 * <code>
 *   frame.getContentPane().add(toolbar, BorderLayout.NORTH);
 * </code>
 * with 
 * <code>
 *   frame.getContentPane().add(MoreButton.wrapToolBar(toolBar), BorderLayout.NORTH);
 * </code>
 * </p>
 * <p>
 * This class is based on the code of Santhosh Kumar T, see
 * <a href="http://www.jroller.com/santhosh/entry/jtoolbar_with_more_button">this link</a> for more information.
 * </p>
 *
 * @author Santhosh Kumar T, Leo Welsch
 */
public class ToolbarMoreButton extends JToggleButton implements ActionListener {

    private static JToolBar moreToolbar;
    JToolBar toolbar;

    protected ToolbarMoreButton(final JToolBar toolbar) {
        super(IconManager.getIcon(IconManager.COMMON_ICON_SET, "more.png"));
        this.toolbar = toolbar;
        addActionListener(this);
        setFocusPainted(false);

        setMargin(new Insets(0, 0, 0, 0));
        setContentAreaFilled(false);
        setBorderPainted(false);
        // Use new JButton decorations introduced in Mac OS X 10.5 (Leopard)
        if (OsFamily.MAC_OS.isCurrent()) {
            putClientProperty("JComponent.sizeVariant", "small");
            putClientProperty("JButton.buttonType", "textured");
        }

        // paint border only when necessary
        addMouseListener(new MouseAdapter() {

            @Override
            public void mouseExited(MouseEvent e) {
                setBorderPainted(false);
            }

            @Override
            public void mouseEntered(MouseEvent e) {
                setBorderPainted(true);
            }
        });

        // hide & seek
        toolbar.addComponentListener(new ComponentAdapter() {

            @Override
            public void componentResized(ComponentEvent e) {
                int nbToolbarComponents = toolbar.getComponentCount();

                final boolean aFlag = nbToolbarComponents>0 && !isVisible(toolbar.getComponent(nbToolbarComponents-1), null);
                setVisible(aFlag);
                moreToolbar.setVisible(aFlag);
            }
        });
    }

    // check visibility
    // partially visible is treated as not visible
    private boolean isVisible(Component comp, Rectangle rect) {
        if (rect == null) {
            rect = toolbar.getVisibleRect();
        }
        return comp.getLocation().x + comp.getWidth() <= rect.getWidth();
    }

    public void actionPerformed(ActionEvent e) {
        Component[] comp = toolbar.getComponents();
        Rectangle visibleRect = toolbar.getVisibleRect();
        for (int i = 0; i < comp.length; i++) {
            if (!isVisible(comp[i], visibleRect)) {
                JPopupMenu popup = new JPopupMenu();
                for (; i < comp.length; i++) {
                    if (comp[i] instanceof AbstractButton) {
                        AbstractButton button = (AbstractButton) comp[i];
                        if (button.getAction() != null) {
                            popup.add(button.getAction());
                        }
                    } else if (comp[i] instanceof JSeparator) {
                        popup.addSeparator();
                    }
                }

                // on popup close make more-button unselected
                popup.addPopupMenuListener(new PopupMenuListener() {

                    public void popupMenuWillBecomeInvisible(PopupMenuEvent e) {
                        setSelected(false);
                    }

                    public void popupMenuCanceled(PopupMenuEvent e) {
                    }

                    public void popupMenuWillBecomeVisible(PopupMenuEvent e) {
                    }
                });
                popup.show(this, 0, getHeight());
            }
        }
    }

    public static JPanel wrapToolBar(JToolBar toolbar) {
        moreToolbar = new JToolBar();
        moreToolbar.setRollover(true);
        moreToolbar.setFloatable(false);
        moreToolbar.add(new ToolbarMoreButton(toolbar));
        moreToolbar.setBorderPainted(false);

        JPanel panel = new JPanel(new BorderLayout());
        panel.add(toolbar, BorderLayout.CENTER);
        panel.add(moreToolbar, BorderLayout.EAST);

        return panel;
    }
}
