All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.jdesktop.swingx.plaf.basic.BasicStatusBarUI Maven / Gradle / Ivy

There is a newer version: 1.7.2
Show newest version
/*
 * $Id: BasicStatusBarUI.java 3927 2011-02-22 16:34:11Z kleopatra $
 *
 * Copyright 2004 Sun Microsystems, Inc., 4150 Network Circle,
 * Santa Clara, California 95054, U.S.A. All rights reserved.
 *
 * 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.
 *
 * 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.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
 */

package org.jdesktop.swingx.plaf.basic;

import org.jdesktop.swingx.JXStatusBar;
import org.jdesktop.swingx.JXStatusBar.Constraint;
import org.jdesktop.swingx.plaf.StatusBarUI;
import org.jdesktop.swingx.plaf.UIManagerExt;

import javax.swing.BorderFactory;
import javax.swing.JComponent;
import javax.swing.LookAndFeel;
import javax.swing.SwingUtilities;
import javax.swing.border.Border;
import javax.swing.plaf.BorderUIResource;
import javax.swing.plaf.ComponentUI;
import javax.swing.plaf.UIResource;
import java.awt.Color;
import java.awt.Component;
import java.awt.Container;
import java.awt.Cursor;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Insets;
import java.awt.LayoutManager;
import java.awt.LayoutManager2;
import java.awt.Point;
import java.awt.Rectangle;
import java.awt.Window;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.awt.event.MouseMotionListener;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.util.HashMap;
import java.util.Map;

/**
 * @author rbair
 * @author Karl Schaefer
 */
public class BasicStatusBarUI extends StatusBarUI {

    private class Handler implements MouseListener, MouseMotionListener, PropertyChangeListener {

        private Window window = SwingUtilities.getWindowAncestor(statusBar);
        private int handleBoundary = getHandleBoundary();
        private boolean validPress = false;
        private Point startingPoint;

        private int getHandleBoundary() {
            Border border = statusBar.getBorder();

            if (border == null || !statusBar.isResizeHandleEnabled()) {
                return 0;
            }

            if (statusBar.getComponentOrientation().isLeftToRight()) {
                return border.getBorderInsets(statusBar).right;
            } else {
                return border.getBorderInsets(statusBar).left;
            }
        }

        private boolean isHandleAreaPoint(Point point) {
            if (window == null || window.isMaximumSizeSet()) {
                return false;
            }

            if (statusBar.getComponentOrientation().isLeftToRight()) {
                return point.x >= statusBar.getWidth() - handleBoundary;
            } else {
                return point.x <= handleBoundary;
            }
        }

        /**
         * {@inheritDoc}
         */
        @Override
        public void mouseClicked(MouseEvent e) {
            //does nothing
        }

        /**
         * {@inheritDoc}
         */
        @Override
        public void mouseEntered(MouseEvent e) {
            if (isHandleAreaPoint(e.getPoint())) {
                if (statusBar.getComponentOrientation().isLeftToRight()) {
                    window.setCursor(Cursor.getPredefinedCursor(Cursor.SE_RESIZE_CURSOR));
                } else {
                    window.setCursor(Cursor.getPredefinedCursor(Cursor.SW_RESIZE_CURSOR));
                }
            } else {
                window.setCursor(null);
            }
        }

        /**
         * {@inheritDoc}
         */
        @Override
        public void mouseExited(MouseEvent e) {
            if (!validPress) {
                window.setCursor(null);
            }
        }

        /**
         * {@inheritDoc}
         */
        @Override
        public void mousePressed(MouseEvent e) {
            validPress = SwingUtilities.isLeftMouseButton(e) && isHandleAreaPoint(e.getPoint());
            startingPoint = e.getPoint();
            SwingUtilities.convertPointToScreen(startingPoint, statusBar);
        }

        /**
         * {@inheritDoc}
         */
        @Override
        public void mouseReleased(MouseEvent e) {
            validPress = !SwingUtilities.isLeftMouseButton(e);
            window.validate();
            window.setCursor(null);
        }

        /**
         * {@inheritDoc}
         */
        @Override
        public void mouseDragged(MouseEvent e) {
            if (validPress) {
                Rectangle wb = window.getBounds();
                Point p = e.getPoint();
                SwingUtilities.convertPointToScreen(p, statusBar);

                wb.height += p.y - startingPoint.y;
                if (statusBar.getComponentOrientation().isLeftToRight()) {
                    wb.width += p.x - startingPoint.x;
                } else {
                    wb.x += p.x - startingPoint.x;
                    wb.width += startingPoint.x - p.x;
                }

                window.setBounds(wb);
                window.validate();
                startingPoint = p;
            }
        }

        /**
         * {@inheritDoc}
         */
        @Override
        public void mouseMoved(MouseEvent e) {
            if (isHandleAreaPoint(e.getPoint())) {
                if (statusBar.getComponentOrientation().isLeftToRight()) {
                    window.setCursor(Cursor.getPredefinedCursor(Cursor.SE_RESIZE_CURSOR));
                } else {
                    window.setCursor(Cursor.getPredefinedCursor(Cursor.SW_RESIZE_CURSOR));
                }
            } else {
                window.setCursor(null);
            }
        }

        /**
         * {@inheritDoc}
         */
        @Override
        public void propertyChange(PropertyChangeEvent evt) {
            if ("ancestor".equals(evt.getPropertyName())) {
                window = SwingUtilities.getWindowAncestor(statusBar);

                boolean useResizeHandle = statusBar.getParent() != null
                                          && statusBar.getRootPane() != null
                                          && (statusBar.getParent() == statusBar.getRootPane()
                                              || statusBar.getParent() == statusBar.getRootPane().getContentPane());
                statusBar.setResizeHandleEnabled(useResizeHandle);
            } else if ("border".equals(evt.getPropertyName())) {
                handleBoundary = getHandleBoundary();
            } else if ("componentOrientation".equals(evt.getPropertyName())) {
                handleBoundary = getHandleBoundary();
            } else if ("resizeHandleEnabled".equals(evt.getPropertyName())) {
                //TODO disable handle display
                handleBoundary = getHandleBoundary();
            }
        }
    }

    public static final String AUTO_ADD_SEPARATOR = "auto-add-separator";
    /**
     * Used to help reduce the amount of trash being generated
     */
    private static final Insets TEMP_INSETS = new Insets(0, 0, 0, 0);
    /**
     * The one and only JXStatusBar for this UI delegate
     */
    protected JXStatusBar statusBar;

    protected MouseListener mouseListener;

    protected MouseMotionListener mouseMotionListener;

    protected PropertyChangeListener propertyChangeListener;

    private Handler handler;

    /**
     * Creates a new instance of BasicStatusBarUI
     */
    public BasicStatusBarUI() {
    }

    /**
     * Returns an instance of the UI delegate for the specified component.
     * Each subclass must provide its own static createUI
     * method that returns an instance of that UI delegate subclass.
     * If the UI delegate subclass is stateless, it may return an instance
     * that is shared by multiple components.  If the UI delegate is
     * stateful, then it should return a new instance per component.
     * The default implementation of this method throws an error, as it
     * should never be invoked.
     */
    public static ComponentUI createUI(JComponent c) {
        return new BasicStatusBarUI();
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public void installUI(JComponent c) {
        assert c instanceof JXStatusBar;
        statusBar = (JXStatusBar) c;

        installDefaults(statusBar);
        installListeners(statusBar);

        // only set the layout manager if the layout manager of the component is
        // null or a UIResource. Do not replace custom layout managers.
        LayoutManager m = statusBar.getLayout();
        if (m == null || m instanceof UIResource) {
            statusBar.setLayout(createLayout());
        }
    }

    protected void installDefaults(JXStatusBar sb) {
        //only set the border if it is an instanceof UIResource
        //In other words, only replace the border if it has not been
        //set by the developer. UIResource is the flag we use to indicate whether
        //the value was set by the UIDelegate, or by the developer.
        Border b = statusBar.getBorder();
        if (b == null || b instanceof UIResource) {
            statusBar.setBorder(createBorder());
        }

        LookAndFeel.installProperty(sb, "opaque", Boolean.TRUE);
    }

    private Handler getHandler() {
        if (handler == null) {
            handler = new Handler();
        }

        return handler;
    }

    /**
     * Creates a {@code MouseListener} which will be added to the
     * status bar. If this method returns null then it will not
     * be added to the status bar.
     * 

* Subclasses may override this method to return instances of their own * MouseEvent handlers. * * @return an instance of a {@code MouseListener} or null */ protected MouseListener createMouseListener() { return getHandler(); } /** * Creates a {@code MouseMotionListener} which will be added to the * status bar. If this method returns null then it will not * be added to the status bar. *

* Subclasses may override this method to return instances of their own * MouseEvent handlers. * * @return an instance of a {@code MouseMotionListener} or null */ protected MouseMotionListener createMouseMotionListener() { return getHandler(); } /** * Creates a {@code PropertyChangeListener} which will be added to the * status bar. If this method returns null then it will not * be added to the status bar. *

* Subclasses may override this method to return instances of their own * PropertyChangeEvent handlers. * * @return an instance of a {@code PropertyChangeListener} or null */ protected PropertyChangeListener createPropertyChangeListener() { return getHandler(); } /** * Create and install the listeners for the status bar. * This method is called when the UI is installed. */ protected void installListeners(JXStatusBar sb) { if ((mouseListener = createMouseListener()) != null) { statusBar.addMouseListener(mouseListener); } if ((mouseMotionListener = createMouseMotionListener()) != null) { statusBar.addMouseMotionListener(mouseMotionListener); } if ((propertyChangeListener = createPropertyChangeListener()) != null) { statusBar.addPropertyChangeListener(propertyChangeListener); } } /** * {@inheritDoc} */ @Override public void uninstallUI(JComponent c) { assert c instanceof JXStatusBar; uninstallDefaults(statusBar); uninstallListeners(statusBar); if (statusBar.getLayout() instanceof UIResource) { statusBar.setLayout(null); } } protected void uninstallDefaults(JXStatusBar sb) { if (sb.getBorder() instanceof UIResource) { sb.setBorder(null); } } /** * Remove the installed listeners from the status bar. * The number and types of listeners removed in this method should be * the same that were added in installListeners */ protected void uninstallListeners(JXStatusBar sb) { if (mouseListener != null) { statusBar.removeMouseListener(mouseListener); } if (mouseMotionListener != null) { statusBar.removeMouseMotionListener(mouseMotionListener); } if (propertyChangeListener != null) { statusBar.removePropertyChangeListener(propertyChangeListener); } } @Override public void paint(Graphics g, JComponent c) { //paint the background if opaque if (statusBar.isOpaque()) { Graphics2D g2 = (Graphics2D) g; paintBackground(g2, statusBar); } if (includeSeparators()) { //now paint the separators getSeparatorInsets(TEMP_INSETS); for (int i = 0; i < statusBar.getComponentCount() - 1; i++) { Component comp = statusBar.getComponent(i); int x = comp.getX() + comp.getWidth() + TEMP_INSETS.left; int y = TEMP_INSETS.top; int w = getSeparatorWidth() - TEMP_INSETS.left - TEMP_INSETS.right; int h = c.getHeight() - TEMP_INSETS.top - TEMP_INSETS.bottom; paintSeparator((Graphics2D) g, statusBar, x, y, w, h); } } } //----------------------------------------------------- Extension Points protected void paintBackground(Graphics2D g, JXStatusBar bar) { if (bar.isOpaque()) { g.setColor(bar.getBackground()); g.fillRect(0, 0, bar.getWidth(), bar.getHeight()); } } protected void paintSeparator(Graphics2D g, JXStatusBar bar, int x, int y, int w, int h) { Color fg = UIManagerExt.getSafeColor("Separator.foreground", Color.BLACK); Color bg = UIManagerExt.getSafeColor("Separator.background", Color.WHITE); x += w / 2; g.setColor(fg); g.drawLine(x, y, x, h); g.setColor(bg); g.drawLine(x + 1, y, x + 1, h); } protected Insets getSeparatorInsets(Insets insets) { if (insets == null) { insets = new Insets(0, 0, 0, 0); } insets.top = 4; insets.left = 4; insets.bottom = 2; insets.right = 4; return insets; } protected int getSeparatorWidth() { return 10; } protected boolean includeSeparators() { Boolean b = (Boolean) statusBar.getClientProperty(AUTO_ADD_SEPARATOR); return b == null || b.booleanValue(); } protected BorderUIResource createBorder() { return new BorderUIResource(BorderFactory.createEmptyBorder(4, 5, 4, 22)); } protected LayoutManager createLayout() { //This is in the UI delegate because the layout //manager takes into account spacing for the separators between components return new LayoutManager2() { private final Map constraints = new HashMap<>(); @Override public void addLayoutComponent(String name, Component comp) { addLayoutComponent(comp, null); } @Override public void removeLayoutComponent(Component comp) { constraints.remove(comp); } @Override public Dimension minimumLayoutSize(Container parent) { return preferredLayoutSize(parent); } @Override public Dimension maximumLayoutSize(Container target) { return new Dimension(Integer.MAX_VALUE, Integer.MAX_VALUE); } @Override public float getLayoutAlignmentX(Container target) { return .5f; } @Override public float getLayoutAlignmentY(Container target) { return .5f; } @Override public void invalidateLayout(Container target) { } @Override public void addLayoutComponent(Component comp, Object constraint) { //we accept an Insets, a ResizeBehavior, or a Constraint. if (constraint instanceof Insets) { constraint = new Constraint((Insets) constraint); } else if (constraint instanceof Constraint.ResizeBehavior) { constraint = new Constraint((Constraint.ResizeBehavior) constraint); } constraints.put(comp, (Constraint) constraint); } @Override public Dimension preferredLayoutSize(Container parent) { Dimension prefSize = new Dimension(); int count = 0; for (Map.Entry entry : constraints.entrySet()) { Constraint c = entry.getValue(); Dimension d = entry.getKey().getPreferredSize(); int prefWidth = 0; if (c != null) { Insets i = c.getInsets(); d.width += i.left + i.right; d.height += i.top + i.bottom; prefWidth = c.getFixedWidth(); } prefSize.height = Math.max(prefSize.height, d.height); prefSize.width += Math.max(d.width, prefWidth); //If this is not the last component, add extra space between each //component (for the separator). count++; if (includeSeparators() && constraints.size() < count) { prefSize.width += getSeparatorWidth(); } } Insets insets = parent.getInsets(); prefSize.height += insets.top + insets.bottom; prefSize.width += insets.left + insets.right; return prefSize; } @Override public void layoutContainer(Container parent) { /* * Layout algorithm: * If the parent width is less than the sum of the preferred * widths of the components (including separators), where * preferred width means either the component preferred width + * constraint insets, or fixed width + constraint insets, then * simply layout the container from left to right and let the * right hand components flow off the parent. * * Otherwise, lay out each component according to its preferred * width except for components with a FILL constraint. For these, * resize them evenly for each FILL constraint. */ //the insets of the parent component. Insets parentInsets = parent.getInsets(); //the available width for putting components. int availableWidth = parent.getWidth() - parentInsets.left - parentInsets.right; if (includeSeparators()) { //remove from availableWidth the amount of space the separators will take availableWidth -= (parent.getComponentCount() - 1) * getSeparatorWidth(); } //the preferred widths of all of the components -- where preferred //width mean the preferred width after calculating fixed widths and //constraint insets int[] preferredWidths = new int[parent.getComponentCount()]; int sumPreferredWidths = 0; for (int i = 0; i < preferredWidths.length; i++) { preferredWidths[i] = getPreferredWidth(parent.getComponent(i)); sumPreferredWidths += preferredWidths[i]; } //if the availableWidth is greater than the sum of preferred //sizes, then adjust the preferred width of each component that //has a FILL constraint, to evenly use up the extra space. if (availableWidth > sumPreferredWidths) { //the number of components with a fill constraint int numFilledComponents = 0; for (Component comp : parent.getComponents()) { Constraint c = constraints.get(comp); if (c != null && c.getResizeBehavior() == Constraint.ResizeBehavior.FILL) { numFilledComponents++; } } if (numFilledComponents > 0) { //calculate the share of free space each FILL component will take availableWidth -= sumPreferredWidths; double weight = 1.0 / (double) numFilledComponents; int share = (int) (availableWidth * weight); int remaining = numFilledComponents; for (int i = 0; i < parent.getComponentCount(); i++) { Component comp = parent.getComponent(i); Constraint c = constraints.get(comp); if (c != null && c.getResizeBehavior() == Constraint.ResizeBehavior.FILL) { if (remaining > 1) { preferredWidths[i] += share; availableWidth -= share; } else { preferredWidths[i] += availableWidth; } remaining--; } } } } //now lay out the components int nextX = parentInsets.left; int height = parent.getHeight() - parentInsets.top - parentInsets.bottom; for (int i = 0; i < parent.getComponentCount(); i++) { Component comp = parent.getComponent(i); Constraint c = constraints.get(comp); Insets insets = c == null ? new Insets(0, 0, 0, 0) : c.getInsets(); int width = preferredWidths[i] - (insets.left + insets.right); int x = nextX + insets.left; int y = parentInsets.top + insets.top; comp.setSize(width, height); comp.setLocation(x, y); nextX = x + width + insets.right; //If this is not the last component, add extra space //for the separator if (includeSeparators() && i < parent.getComponentCount() - 1) { nextX += getSeparatorWidth(); } } } /** * @return the "preferred" width, where that means either * comp.getPreferredSize().width + constraintInsets, or * constraint.fixedWidth + constraintInsets. */ private int getPreferredWidth(Component comp) { Constraint c = constraints.get(comp); if (c == null) { return comp.getPreferredSize().width; } else { Insets insets = c.getInsets(); assert insets != null; if (c.getFixedWidth() <= 0) { return comp.getPreferredSize().width + insets.left + insets.right; } else { return c.getFixedWidth() + insets.left + insets.right; } } } }; } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy