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-2004 Sun
 * Microsystems, Inc. All Rights Reserved.
 */
/*
 * ToolbarTabDisplayerUI.java
 *
 * Created on June 1, 2004, 12:31 AM
 */

package org.netbeans.swing.tabcontrol.plaf;

import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseListener;
import java.util.Arrays;
import javax.swing.*;
import javax.swing.border.Border;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;
import javax.swing.plaf.ComponentUI;
import org.netbeans.swing.tabcontrol.TabDisplayer;
import org.openide.awt.HtmlRenderer;

/**
 * A TabDisplayerUI which uses a JToolBar and JButtons.  This look is used
 * in various places such as the property sheet and component inspector.
 *
 * @author  Tim Boudreau
 */
public class ToolbarTabDisplayerUI extends AbstractTabDisplayerUI {
    private JToolBar toolbar = null;
    private static final Border buttonBorder;
    
    static {
        //Get the HIE requested button border via an ugly hack
        Border b = (Border) UIManager.get("nb.tabbutton.border"); //NOI18N

        if (b == null) {
            JToolBar toolbar = new JToolBar();
            JButton button = new JButton();
            toolbar.setRollover(true);
            toolbar.add(button);
            b = button.getBorder();
            toolbar.remove(button);
        }
        
        buttonBorder = b;
    }
    
    /** Creates a new instance of ToolbarTabDisplayerUI */
    public ToolbarTabDisplayerUI(TabDisplayer disp) {
        super (disp);
    }
    
    public static ComponentUI createUI (JComponent jc) {
        return new ToolbarTabDisplayerUI ((TabDisplayer) jc);
    }
    
    protected TabLayoutModel createLayoutModel() {
        //not used
        return null;
    }
    
    protected void install() {
        toolbar = new JToolBar();
        toolbar.setLayout (new AutoGridLayout());
        toolbar.setFloatable (false);
        displayer.setLayout (new BorderLayout());
        displayer.add (toolbar, BorderLayout.CENTER);
        if (displayer.getModel() != null && displayer.getModel().size() > 0) {
            syncButtonsWithModel();
        }
    }
    
    protected void modelChanged() {
        if (syncButtonsWithModel()) {
            if (displayer.getParent() != null) {
                ((JComponent) displayer.getParent()).revalidate();
            }
        }
    }
    
    protected MouseListener createMouseListener() {
        return null;
    }
    
    private IndexButton findButtonFor (int index) {
        Component[] c = toolbar.getComponents();
        for (int i=0; i < c.length; i++) {
            if (c[i] instanceof IndexButton && ((IndexButton) c[i]).getIndex() == index) {
                return (IndexButton) c[i];
            }
        }
        return null;
    }    
    
    protected ChangeListener createSelectionListener() {
        return new ChangeListener() {
            private int lastKnownSelection = -1;
            public void stateChanged (ChangeEvent ce) {
                int selection = selectionModel.getSelectedIndex();
                if (selection != lastKnownSelection) {
                    if (lastKnownSelection != -1) {
                        IndexButton last = findButtonFor(lastKnownSelection);
                        if (last != null) {
                            last.getModel().setSelected(false);
                        }
                    }
                    if (selection != -1) {
                        IndexButton current = findButtonFor (selection);
                        if (toolbar.getComponentCount() == 0) {
                            syncButtonsWithModel();
                        }
                        if (current != null) {
                            current.getModel().setSelected (true);
                        }
                    }
                }
                lastKnownSelection = selection;
            }
        };
    }
    
    public Polygon getExactTabIndication(int index) {
        JToggleButton jb = findButtonFor (index);
        if (jb != null) {
            return new EqualPolygon (jb.getBounds());
        } else {
            return new EqualPolygon (new Rectangle());
        }
    }
    
    public Polygon getInsertTabIndication(int index) {
        return getExactTabIndication (index);
    }
    
    public Rectangle getTabRect(int index, Rectangle destination) {
        destination.setBounds(findButtonFor(index).getBounds());
        return destination;
    }
    
    public int tabForCoordinate(Point p) {
        Point p1 = SwingUtilities.convertPoint(displayer, p, toolbar);
        Component c = toolbar.getComponentAt(p1);
        if (c instanceof IndexButton) {
            return ((IndexButton) c).getIndex();
        }
        return -1;
    }
    
    public Dimension getPreferredSize(JComponent c) {
        return toolbar.getLayout().preferredLayoutSize(c);
    }

    public Dimension getMinimumSize(JComponent c) {
        return toolbar.getLayout().minimumLayoutSize(c);
    }

    
    private boolean syncButtonsWithModel() {
        assert SwingUtilities.isEventDispatchThread();
        
        int expected = displayer.getModel().size();
        int actual = toolbar.getComponentCount();
        boolean result = actual != expected;
        if (result) {
            if (expected > actual) {
                for (int i = actual; i < expected; i++) {
                    toolbar.add(new IndexButton());
                }
            } else if (expected < actual) {
                for (int i=expected; i < actual; i++) {
                    toolbar.remove(toolbar.getComponentCount() -1);
                }
            }
        }
        int selIdx = selectionModel.getSelectedIndex();
        if (selIdx != -1) {
            findButtonFor(selIdx).setSelected(true);
        }
        if (result) {
            displayer.revalidate();
            displayer.repaint();
        }
        return result;
    }    
    
    private ButtonGroup bg = new ButtonGroup();
    private static int fontHeight = -1;
    private static int ascent = -1;
    
    /**
     * A button which will get its content from an index in the datamodel 
     * which corresponds to its index in its parent's component hierarchy.
     */
    public final class IndexButton extends JToggleButton implements ActionListener {
        private String lastKnownText = null;

        /** Create a new button representing an index in the model.  The index is immutable for the life of the
         * button.
         */
        public IndexButton () {
            addActionListener(this);
            setFont (displayer.getFont());
            setFocusable(false);
            setBorder (buttonBorder);
        }

        public void addNotify() {
            super.addNotify();
            ToolTipManager.sharedInstance().registerComponent(this);
            bg.add(this);
        }

        public void removeNotify() {
            super.removeNotify();
            ToolTipManager.sharedInstance().unregisterComponent(this);
            bg.remove(this);
        }

        /** Accessor for the UI delegate to determine if the tab displayer is currently active */
        public boolean isActive() {
            return displayer.isActive();
        }
        
        public String getText() {
             //so the font height is included in super.getPreferredSize();
            return " ";
        }

        public String doGetText() {
            int idx = getIndex();
            if (idx == -1) {
                //We're being called in the superclass constructor when the UI is
                //assigned
                return "";
            }
            if (getIndex() < displayer.getModel().size()) {
                lastKnownText = displayer.getModel().getTab(idx).getText();
            } else {
                return "This tab doesn't exist."; //NOI18N
            }
            return lastKnownText;
        }
        
        public Dimension getPreferredSize() {
            Dimension result = super.getPreferredSize();
            String s = doGetText();
            int w = DefaultTabLayoutModel.textWidth(s, getFont());
            result.width += w;
            return result;
        }
        
        public void paintComponent (Graphics g) {
            super.paintComponent(g);
            String s = doGetText();
            
            Insets ins = getInsets();
            int x = ins.left;
            int w = getWidth() - (ins.left + ins.right);
            int h = getHeight();
            
            int txtW = DefaultTabLayoutModel.textWidth(s, getFont());
            if (txtW < w) {
                x += (w / 2) - (txtW / 2);
            }
            
            if (fontHeight == -1) {
                FontMetrics fm = g.getFontMetrics(getFont());
                fontHeight = fm.getHeight();
                ascent = fm.getMaxAscent();
            }
            int y = ins.top + ascent + (((getHeight() - (ins.top + ins.bottom)) / 2) - (fontHeight / 2));
            
            HtmlRenderer.renderString(s, g, x, y, w, h, getFont(), getForeground(), 
                HtmlRenderer.STYLE_TRUNCATE, true);
        }
        
        public String getToolTipText() {
            return displayer.getModel().getTab(getIndex()).getTooltip();
        }

        /** Implementation of ActionListener - sets the selected index in the selection model */
        public final void actionPerformed(ActionEvent e) {
            selectionModel.setSelectedIndex (getIndex());
        }

        /** Get the index into the data model that this button represents */
        public int getIndex() {
            if (getParent() != null) {
                return Arrays.asList(getParent().getComponents()).indexOf(this);
            }
            return -1;
        }
        
        public Icon getIcon() {
            return null;
        }

        /**
         * Test if the text or icon in the model has changed since the last time getText() or
         * getIcon() was called.  If a change has occured, the button will fire the appropriate
         * property changes, including preferred size, to ensure the tab displayer is re-laid out correctly.
         * This method is called when a change happens in the model over the index this button represents.
         *
         * @return true if something has changed
         */
        final boolean checkChanged() {
            boolean result = false;
            String txt = lastKnownText;
            String nu = doGetText();
            if (nu != txt) { //Equality compare probably not needed
                firePropertyChange ("text", lastKnownText, doGetText()); //NOI18N
                result = true;
            }
            if (result) {
                firePropertyChange ("preferredSize", null, null); //NOI18N
            }
            return result;
        }
    }    
    
    /**
     * Originally in org.netbeans.form.palette.CategorySelectPanel.
     *
     * @author Tomas Pavek
     */
    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;

                
                Dimension result = new Dimension(containerWidth, prefHeight);
                return result;
            }
        }

        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.