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.netbeans.modules.form.palette;

import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import javax.swing.border.*;
import javax.swing.event.*;

/**
 * A toolbar holding toggle buttons for selecting the category in the
 * palette UI.
 *
 * @author Tomas Pavek
 */

class CategorySelectPanel extends JToolBar {

    private int selectedIndex = -1;

    private ButtonGroup buttonGroup = new ButtonGroup();
    private ActionListener buttonActionListener = new ButtonActionListener();
    private MouseListener buttonMouseListener = new ButtonMouseListener();

    /** External ChangeListener for listening to changes in selected category. */
    private ChangeListener extChangeListener;
    private ChangeEvent changeEvent;

    /** External mouse listener attached to each created category button to
     * handle popup menu invocation. */
    private MouseListener extMouseListener;

    private static Border buttonBorder;

    /** Constructor. */
    CategorySelectPanel(ChangeListener changeListener,
                        MouseListener mouseListener)
    {
        // the toolbar should have roll-over buttons and no handle for dragging
        setFloatable(false);
        setBorder(BorderFactory.createEmptyBorder(0, 0, 0, 0));
//        setBorder(new BevelBorder(BevelBorder.RAISED,
//                                  UIManager.getColor("controlLtHighlight"), // NOI18N
//                                  UIManager.getColor("ToolBar.background"), // NOI18N
//                                  UIManager.getColor("controlShadow"), // NOI18N
//                                  UIManager.getColor("ToolBar.background"))); // NOI18N

        // use special layout
        setLayout(new AutoGridLayout());

        // [having such hardcoded listeners isn't very flexible...]
        extChangeListener = changeListener;
        extMouseListener = mouseListener;

        addMouseListener(extMouseListener);
    }

    public void paintComponent(Graphics g) {
        super.paintComponent(g);

        Color color = g.getColor();

        g.setColor(UIManager.getColor("controlLtHighlight")); // NOI18N
        g.drawLine(0, 0, getWidth(), 0);
        g.drawLine(0, 0, 0, getHeight());
        g.setColor(UIManager.getColor("controlShadow")); // NOI18N
        g.drawLine(0, getHeight()-1, getWidth(), getHeight()-1);

        g.setColor(color);
    }

    // --------

    void addCategory(String displayName, int index) {
        addCategory(displayName, null, index);
    }

    void addCategory(String displayName, String description, int index) {
        AbstractButton button;
        // 46134: WindowsButtonUI doesn't paint focus on buttons in toolbar
        if (UIManager.getLookAndFeel().getID().equals("Windows")) { // NOI18N
            button = new JToggleButton() {
                protected void paintComponent(Graphics g) {
                    super.paintComponent(g);
                    if (isFocusOwner()) {
                        int width = getWidth();
                        int height = getHeight();
                        g.setColor(UIManager.getColor("Button.focus")); // NOI18N
                        javax.swing.plaf.basic.BasicGraphicsUtils.drawDashedRect(g,
                        2, 2, width - 4, height - 4);
                    }
                }
            };
            button.setText(displayName);
        } else {
            button = new JToggleButton(displayName);
        }
        button.setRolloverEnabled(true);
        button.setMargin(new Insets(0, 3, 0, 3));
        if (description != null) // accessibility description provided
            button.setToolTipText(description);

        if (buttonBorder == null) // for some l&f's, core will supply one
            buttonBorder = UIManager.getBorder("nb.tabbutton.border"); //NOI18N

        if (buttonBorder == null) {
            JToolBar toolbar = new JToolBar();
            toolbar.setRollover(true);
            toolbar.add(button);
            buttonBorder = button.getBorder();
            toolbar.remove(button);
        }

        if (index < 0)
            add(button);
        else
            add(button, index);
        buttonGroup.add(button);

        button.setBorder(buttonBorder);

        // as we cannot get the button small enough using the margin and border...
        if (buttonBorder instanceof CompoundBorder) { // from BasicLookAndFeel
            Dimension pref = button.getPreferredSize();
            pref.height -= 3;
            button.setPreferredSize(pref);
        }

        button.addActionListener(buttonActionListener);
        button.addMouseListener(buttonMouseListener);
        button.addMouseListener(extMouseListener);

        if (getCategoryCount() == 1) // first button added, select it
            setSelectedIndex(0);
    }

    void removeCategory(int index) {
        AbstractButton button = getButton(index);
        buttonGroup.remove(button);
        remove(button);

        if (index == selectedIndex) // removed button was selected
            setSelectedIndex(selectedIndex >= getCategoryCount() ?
                                 getCategoryCount() - 1 : selectedIndex);
        else if (index < selectedIndex) // same button remains selected,
            selectedIndex--;            // just with lower index
    }

    void clearCategories() {
        buttonGroup = new ButtonGroup();
        removeAll();
        selectedIndex = -1;
        setSelectedIndex(-1);
    }

    int getSelectedIndex() {
        return selectedIndex;
    }

    void setSelectedIndex(int index) {
        if (index >= 0)
            getButton(index).setSelected(true);
        else if (selectedIndex >= 0)
            getButton(selectedIndex).setSelected(false);

        selectedIndex = index;

        if (changeEvent == null)
            changeEvent = new ChangeEvent(this);
        extChangeListener.stateChanged(changeEvent);
    }

    int getCategoryCount() {
        return getComponentCount();
    }

    int indexOfComponent(Component comp) {
        int index = -1;
        Component[] components = getComponents();
        for (int i=0; i < components.length; i++)
            if (comp == components[i]) {
                index = i;
                break;
            }
        return index;
    }

    AbstractButton getButton(int index) {
        return (AbstractButton) getComponent(index);
    }

    // --------
    // listeners for category buttons

    private class ButtonActionListener implements ActionListener {
        public void actionPerformed(ActionEvent e) {
            AbstractButton button = (AbstractButton) e.getSource();
            setSelectedIndex(indexOfComponent(button));
        }
    }

    private static class ButtonMouseListener extends MouseAdapter {
        public void mouseEntered(MouseEvent e) {
            AbstractButton b = (AbstractButton)e.getComponent();
            b.getModel().setRollover(true);
        }
        public void mouseExited(MouseEvent e) {
            AbstractButton b = (AbstractButton)e.getComponent();
            b.getModel().setRollover(false);
        }
    }

    // --------
    // special layout manager for category buttons - manages an adapting grid
    // of components

    static class AutoGridLayout implements LayoutManager {

        private int h_margin_left = 2; // margin on the left
        private int h_margin_right = 1; // margin on the right
        private int v_margin_top = 2; // margin at the top
        private int v_margin_bottom = 3; // margin at the bottom
        private int h_gap = 1; // horizontal gap between components
        private int v_gap = 1; // vertical gap between components

        public void addLayoutComponent(String name, Component comp) {
        }

        public void removeLayoutComponent(Component comp) {
        }

        public Dimension preferredLayoutSize(Container parent) {
            synchronized (parent.getTreeLock()) {
                int containerWidth = parent.getWidth();
                int count = parent.getComponentCount();

                if (containerWidth <= 0 || count == 0) {
                    // compute cumulated width of all components placed on one row
                    int cumulatedWidth = 0;
                    int height = 0;
                    for (int i=0; i < count; i++) {
                        Dimension size = parent.getComponent(i).getPreferredSize();
                        cumulatedWidth += size.width;
                        if (i + 1 < count)
                            cumulatedWidth += h_gap;
                        if (size.height > height)
                            height = size.height;
                    }
                    cumulatedWidth += h_margin_left + h_margin_right;
                    height += v_margin_top + v_margin_bottom;
                    return new Dimension(cumulatedWidth, height);
                }

                // otherwise the container already has some width set - so we
                // just compute preferred height for it

                // get max. component width and height
                int columnWidth = 0;
                int rowHeight = 0;
                for (int i=0; i < count; i++) {
                    Dimension size = parent.getComponent(i).getPreferredSize();
                    if (size.width > columnWidth)
                        columnWidth = size.width;
                    if (size.height > rowHeight)
                        rowHeight = size.height;
                }

                // compute column count
                int columnCount = 0;
                int w = h_margin_left + columnWidth + h_margin_right;
                do {
                    columnCount++;
                    w += h_gap + columnWidth;
                }
                while (w <= containerWidth && columnCount < count);

                // compute row count and preferred height
                int rowCount = count / columnCount +
                               (count % columnCount > 0 ? 1 : 0);
                int prefHeight = v_margin_top + rowCount * rowHeight
                                     + (rowCount - 1) * v_gap + v_margin_bottom;

                return new Dimension(containerWidth, prefHeight);
            }
        }

        public Dimension minimumLayoutSize(Container parent) {
            return new Dimension(h_margin_left + h_margin_right,
                                 v_margin_top + v_margin_bottom);
        }

        public void layoutContainer(Container parent) {
            synchronized (parent.getTreeLock()) {
                int count = parent.getComponentCount();
                if (count == 0)
                    return;

                // get max. component width and height
                int columnWidth = 0;
                int rowHeight = 0;
                for (int i=0; i < count; i++) {
                    Dimension size = parent.getComponent(i).getPreferredSize();
                    if (size.width > columnWidth)
                        columnWidth = size.width;
                    if (size.height > rowHeight)
                        rowHeight = size.height;
                }

                // compute column count
                int containerWidth = parent.getWidth();
                int columnCount = 0;
                int w = h_margin_left + columnWidth + h_margin_right;
                do {
                    columnCount++;
                    w += h_gap + columnWidth;
                }
                while (w <= containerWidth && columnCount < count);

                // adjust layout matrix - balance number of columns according
                // to last row
                if (count % columnCount > 0) {
                    int roundedRowCount = count / columnCount;
                    int lastRowEmpty = columnCount - count % columnCount;
                    if (lastRowEmpty > roundedRowCount)
                        columnCount -= lastRowEmpty / (roundedRowCount + 1);
                }

                // adjust column width
                if (count > columnCount)
                    columnWidth = (containerWidth - h_margin_left - h_margin_right
                                     - (columnCount - 1) * h_gap) / columnCount;
                if (columnWidth < 0)
                    columnWidth = 0;

                // layout the components
                for (int i=0, col=0, row=0; i < count; i++) {
                    parent.getComponent(i).setBounds(
                                       h_margin_left + col * (columnWidth + h_gap),
                                       v_margin_top + row * (rowHeight + v_gap),
                                       columnWidth,
                                       rowHeight);
                    if (++col >= columnCount) {
                        col = 0;
                        row++;
                    }
                }
            }
        }
    }
}
... 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.