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.MouseEvent;
import javax.swing.*;
import javax.swing.border.*;
import javax.swing.event.MouseInputListener;
import javax.swing.plaf.basic.BasicListUI;
import java.beans.BeanInfo;
import java.lang.ref.WeakReference;

import org.openide.nodes.Node;

/**
 * Specialized JList for palette items (content of a palette category) - having
 * special UI and renderer providing fine-tuned alignment, rollover effect,
 * showing names and different icon size. Used by CategoryPresentPanel.
 *
 * @author Tomas Pavek
 */

class CategoryList extends JList {

    private int rolloverIndex = -1;
    private boolean showNames;

    static final int BASIC_ICONSIZE = BeanInfo.ICON_COLOR_16x16;
    private int iconSize = BASIC_ICONSIZE;

    private static WeakReference rendererRef;

    /** Constructor. */
    CategoryList() {
        super();
        setOpaque(false);
        setBorder(new EmptyBorder(2, 2, 2, 1));
        setLayoutOrientation(JList.HORIZONTAL_WRAP);
        setVisibleRowCount(0);
        setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
        setCellRenderer(getItemRenderer());
    }

    public void updateUI() {
        setUI(new CategoryListUI());
        invalidate();
    }
    
    // Workaround for issue 39037. Due to the following method we can
    // use getPreferredSize() in the implementation of the method
    // getPreferredHeight(). Otherwise we would have to copy the content
    // of getPreferredSize() into the layout manager of the enclosing JScrollPane.
    // We cannot change the width directly through setBounds() method
    // because it would force another repaint.
    Integer tempWidth;
    public int getWidth() {
        return (tempWidth == null) ? super.getWidth() : tempWidth.intValue();
    }

    // ---------

    boolean getShowNames() {
        return showNames;
    }

    void setShowNames(boolean show) {
        if (show != showNames) {
            showNames = show;
            firePropertyChange("cellRenderer", null, null); // NOI18N
        }
    }

    int getIconSize() {
        return iconSize;
    }

    void setIconSize(int size) {
        if (size != iconSize) {
            iconSize = size;
            firePropertyChange("cellRenderer", null, null); // NOI18N
        }
    }
    
    // workaround for bug 4832765, which can cause the
    // scroll pane to not let the user easily scroll up to the beginning
    // of the list.  An alternative would be to set the unitIncrement
    // of the JScrollBar to a fixed value. You wouldn't get the nice
    // aligned scrolling, but it should work.
    public int getScrollableUnitIncrement(Rectangle visibleRect, int orientation, int direction) {
        int row;
        if (orientation == SwingConstants.VERTICAL &&
            direction < 0 && (row = getFirstVisibleIndex()) != -1) {
            Rectangle r = getCellBounds(row, row);
            if ((r.y == visibleRect.y) && (row != 0))  {
                Point loc = r.getLocation();
                loc.y--;
                int prevIndex = locationToIndex(loc);
                Rectangle prevR = getCellBounds(prevIndex, prevIndex);
                
                if (prevR == null || prevR.y >= r.y) {
                    return 0;
                }
                return prevR.height;
            }
        }
        return super.getScrollableUnitIncrement(visibleRect, orientation, direction);
    }

    /**
     * Returns preferred height of the list for the specified width.
     *
     * @return preferred height of the list for the specified width.
     */
    public int getPreferredHeight(int width) {
        return ((CategoryListUI)getUI()).getPreferredHeight(width);
    }

    // --------
    // list item renderer

    private static ListCellRenderer getItemRenderer() {
        ListCellRenderer renderer = rendererRef == null ? null :
                                      (ListCellRenderer) rendererRef.get();
        if (renderer == null) {
            renderer = new ItemRenderer();
            rendererRef = new WeakReference(renderer);
        }
        return renderer;
    }

    static class ItemRenderer implements ListCellRenderer {

        private static JToggleButton button;
        private static Border defaultBorder;

        ItemRenderer() {
            if (button == null) {
                button = new JToggleButton();

                String laf = UIManager.getLookAndFeel().getClass().getName();
                if (laf.equals("javax.swing.plaf.metal.MetalLookAndFeel") // NOI18N
                    || laf.equals("com.sun.java.swing.plaf.windows.WindowsLookAndFeel")) // NOI18N
                { // for Metal and Windows Look&Feel use toolbar button rendering
                    button.setMargin(new Insets(1, 0, 1, 0));
                    JToolBar toolbar = new JToolBar();
                    toolbar.setRollover(true);
                    toolbar.setFloatable(false);
                    toolbar.setLayout(new BorderLayout(0, 0));
                    toolbar.setBorder(new EmptyBorder(0, 0, 0, 0));
                    toolbar.add(button);
                }
                else { // otherwise use normal button with default or empty border
                    button.setMargin(new Insets(1, 1, 1, 1));
                    defaultBorder = button.getBorder();
                }
            }
        }

        public Component getListCellRendererComponent(JList list,
                                                      Object value, 
                                                      int index,
                                                      boolean isSelected,
                                                      boolean cellHasFocus)
        {
            CategoryList categoryList = (CategoryList) list;
            boolean showNames = categoryList.getShowNames();
            int iconSize = categoryList.getIconSize();

            JComponent rendererComponent = defaultBorder == null ?
                (JComponent) button.getParent() : button;

            Node node = (Node) value;
            Icon icon = new ImageIcon(node.getIcon(iconSize));
            button.setIcon(icon);
            
            button.setText(showNames ? node.getDisplayName() : null);
            rendererComponent.setToolTipText(
                node.getShortDescription().replace('-', '.')); // NOI18N

            button.setSelected(isSelected);
            if (defaultBorder == null) { // Windows or Metal
                // let the toolbar UI render the button according to "rollover"
                button.getModel().setRollover(
                    index == categoryList.rolloverIndex && !isSelected);
            }
            else { // Mac OS X and others - set the border explicitly
                button.setBorder(defaultBorder);
            }
            button.setBorderPainted((index == categoryList.rolloverIndex) || isSelected);

            button.setHorizontalAlignment(showNames && iconSize == BASIC_ICONSIZE ?
                                   SwingConstants.LEFT : SwingConstants.CENTER);
            button.setHorizontalTextPosition(iconSize == BASIC_ICONSIZE ?
                                  SwingConstants.RIGHT : SwingConstants.CENTER);
            button.setVerticalTextPosition(iconSize == BASIC_ICONSIZE ?
                                 SwingConstants.CENTER : SwingConstants.BOTTOM);

            return rendererComponent;
        }
    }

    // ---------
    // list UI

    static class CategoryListUI extends BasicListUI {

        protected void updateLayoutState() {
            super.updateLayoutState();

            if (list.getLayoutOrientation() == JList.HORIZONTAL_WRAP) {
                Insets insets = list.getInsets();
                int listWidth = list.getWidth() - (insets.left + insets.right);
                if (listWidth >= cellWidth) {
                    int columnCount = listWidth / cellWidth;
                    cellWidth = listWidth / columnCount;
                }
            }
        }
        
        public int getPreferredHeight(int width) {
            ((CategoryList)list).tempWidth = new Integer(width);
            int result;
            try {
                result = (int)getPreferredSize(list).getHeight();
            } finally {
                ((CategoryList)list).tempWidth = null;
            }
            return result;
        }

        protected MouseInputListener createMouseInputListener() {
            return new ListMouseInputHandler();
        }

        private class ListMouseInputHandler extends MouseInputHandler {

            private int selIndex = -1;

            public void mousePressed(MouseEvent e) {
                if (getValidIndex(e.getPoint()) >= 0) {
                    selIndex = list.getSelectedIndex();
                    super.mousePressed(e);
                }
            }

            public void mouseDragged(MouseEvent e) {
                if (getValidIndex(e.getPoint()) >= 0)
                    super.mouseDragged(e);
            }

            public void mouseMoved(MouseEvent e) {
                mouseEntered(e);
            }

            public void mouseEntered(MouseEvent e) {
                if (list.isEnabled())
                    setRolloverIndex(getValidIndex(e.getPoint()));
            }

            public void mouseExited(MouseEvent e) {
                if (list.isEnabled())
                    setRolloverIndex(-1);
            }

            public void mouseReleased(MouseEvent e) {
                if (getValidIndex(e.getPoint()) >= 0) {
                    super.mouseReleased(e);
                    if (selIndex > -1 && list.getSelectedIndex() == selIndex)
                        list.removeSelectionInterval(selIndex, selIndex);
                }
            }

            private void setRolloverIndex(int index) {
                int oldIndex = ((CategoryList)list).rolloverIndex;
                if (index != oldIndex) {
                    ((CategoryList)list).rolloverIndex = index;
                    if (oldIndex > -1) {
                        Rectangle r = getCellBounds(list, oldIndex, oldIndex);
                        if (r != null)
                            list.repaint(r.x, r.y, r.width, r.height);
                    }
                    if (index > -1) {
                        Rectangle r = getCellBounds(list, index, index);
                        if (r != null)
                            list.repaint(r.x, r.y, r.width, r.height);
                    }
                }
            }
        }

        private int getValidIndex(Point p) {
            int index = locationToIndex(list, p);
            return index >= 0 && getCellBounds(list, index, index).contains(p) ?
                index : -1;
        }
    }
}
... 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.