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

org.datacleaner.widgets.tabs.CloseableTabbedPaneUI Maven / Gradle / Ivy

/**
 * DataCleaner (community edition)
 * Copyright (C) 2014 Free Software Foundation, Inc.
 *
 * This copyrighted material is made available to anyone wishing to use, modify,
 * copy, or redistribute it subject to the terms and conditions of the GNU
 * Lesser General Public License, as published by the Free Software Foundation.
 *
 * This program 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 distribution; if not, write to:
 * Free Software Foundation, Inc.
 * 51 Franklin Street, Fifth Floor
 * Boston, MA  02110-1301  USA
 */
package org.datacleaner.widgets.tabs;

import java.awt.Color;
import java.awt.Font;
import java.awt.FontMetrics;
import java.awt.Graphics;
import java.awt.Image;
import java.awt.Insets;
import java.awt.Rectangle;

import javax.swing.Icon;
import javax.swing.border.Border;
import javax.swing.plaf.basic.BasicTabbedPaneUI;

import org.datacleaner.util.IconUtils;
import org.datacleaner.util.ImageManager;
import org.datacleaner.util.WidgetUtils;

/**
 * This is a slightly rewritten/modified version of swingutil's
 * ClosableTabbedPane
 */
final class CloseableTabbedPaneUI extends BasicTabbedPaneUI {

    // the close image(s)
    private static final Image CLOSE_IMAGE = ImageManager.get().getImage("images/widgets/tab_close.png");
    private static final Image CLOSE_IMAGE_HOVER = ImageManager.get().getImage("images/widgets/tab_close_hover.png");

    // the width of the close images
    private static final int CLOSE_ICON_WIDTH = IconUtils.ICON_SIZE_MEDIUM;

    // the top-margin of a close icon
    private static final int CLOSE_ICON_RIGHT_MARGIN = 6;

    // the insets for a single tab
    private static final Insets TAB_INSETS = new Insets(0, 2, 1, 3);

    // the width of a separator
    private static final int SEPARATOR_WIDTH = 10;

    private final Color _tabUnselectedBackgroundColor = WidgetUtils.COLOR_WELL_BACKGROUND;
    private final Color _tabSelectedBackgroundColor = WidgetUtils.COLOR_DEFAULT_BACKGROUND;
    private final Color _tabBorderColor = WidgetUtils.BG_COLOR_LESS_BRIGHT;

    private final CloseableTabbedPaneMouseListener _mouseListener;
    private final CloseableTabbedPane _pane;

    public CloseableTabbedPaneUI(final CloseableTabbedPane pane) {
        super();
        _pane = pane;
        _mouseListener = new CloseableTabbedPaneMouseListener(this, pane);
    }

    @Override
    protected Insets getTabInsets(final int tabPlacement, final int tabIndex) {
        return TAB_INSETS;
    }

    @Override
    protected Insets getSelectedTabPadInsets(final int tabPlacement) {
        return TAB_INSETS;
    }

    @Override
    protected Insets getContentBorderInsets(final int tabPlacement) {
        return new Insets(2, 2, 2, 2);
    }

    @Override
    protected Insets getTabAreaInsets(final int tabPlacement) {
        return new Insets(0, 0, 0, 0);
    }

    @Override
    protected int getTabLabelShiftY(final int tabPlacement, final int tabIndex, final boolean isSelected) {
        if (isSelected) {
            return 1;
        }
        return 0;
    }

    // increases the visibility of the getRunForTab(...) method
    public int getRunForTab(final int tabCount, final int tabIndex) {
        return super.getRunForTab(tabCount, tabIndex);
    }

    private Insets getBorderInsets() {
        final Border border = _pane.getBorder();
        if (border == null) {
            return new Insets(0, 0, 0, 0);
        }
        return border.getBorderInsets(_pane);
    }

    /**
     * Helper-method to get a rectangle definition for the close-icon
     *
     * @param tabIndex
     * @return
     */
    public Rectangle closeRectFor(final int tabIndex) {
        final Rectangle rect = rects[tabIndex];
        final int x = rect.x + rect.width - CLOSE_ICON_WIDTH - CLOSE_ICON_RIGHT_MARGIN;
        final int y = rect.y + (rect.height - CLOSE_ICON_WIDTH) / 2;
        final int width = CLOSE_ICON_WIDTH;
        return new Rectangle(x, y, width, width);
    }

    /**
     * Override this to provide extra space on right for close button
     */
    @Override
    protected int calculateTabWidth(final int tabPlacement, final int tabIndex, final FontMetrics metrics) {
        if (_pane.getSeparators().contains(tabIndex)) {
            return SEPARATOR_WIDTH;
        }
        int width = super.calculateTabWidth(tabPlacement, tabIndex, metrics);
        if (!_pane.getUnclosables().contains(tabIndex)) {
            width += CLOSE_ICON_WIDTH;
        }
        return width;
    }

    @Override
    protected int calculateTabAreaHeight(final int tabPlacement, final int horizRunCount, final int maxTabHeight) {
        final Insets insets = getBorderInsets();
        return maxTabHeight * horizRunCount + insets.top;
    }

    @Override
    protected int calculateTabHeight(final int tabPlacement, final int tabIndex, final int fontHeight) {
        return super.calculateTabHeight(tabPlacement, tabIndex, fontHeight);
    }

    @Override
    protected void paintText(final Graphics g, final int tabPlacement, final Font font, final FontMetrics metrics,
            final int tabIndex, final String title, final Rectangle textRect, final boolean isSelected) {
        final Rectangle r = new Rectangle(textRect);
        if (!_pane.getUnclosables().contains(tabIndex)) {
            r.x -= CLOSE_ICON_WIDTH - (CLOSE_ICON_WIDTH / 2);
        }
        super.paintText(g, tabPlacement, font, metrics, tabIndex, title, r, isSelected);
    }

    @Override
    protected void paintIcon(final Graphics g, final int tabPlacement, final int tabIndex, final Icon icon,
            final Rectangle iconRect, final boolean isSelected) {
        final Rectangle r = new Rectangle(iconRect);
        if (!_pane.getUnclosables().contains(tabIndex)) {
            r.x -= CLOSE_ICON_WIDTH - (CLOSE_ICON_WIDTH / 2);
        }
        super.paintIcon(g, tabPlacement, tabIndex, icon, r, isSelected);
    }

    @Override
    protected void paintTabBorder(final Graphics g, final int tabPlacement, final int tabIndex, final int x,
            final int y, final int w, final int h, final boolean isSelected) {
        g.setColor(_tabBorderColor);

        // the top line
        g.drawLine(x, y, x + w, y);

        // left line
        g.drawLine(x, y, x, y + h);

        // right line
        g.drawLine(x + w, y, x + w, y + h);

        // the left arc
        g.drawLine(x, y, x, y);

        // the right arc
        g.drawLine(x + w, y, x + w, y);
    }

    @Override
    protected void paintTabBackground(final Graphics g, final int tabPlacement, final int tabIndex, final int x,
            final int y, final int w, final int h, final boolean isSelected) {

        final Color backgroundColor;
        if (isSelected) {
            backgroundColor = _tabSelectedBackgroundColor;
        } else {
            backgroundColor = _tabUnselectedBackgroundColor;
        }

        g.setColor(backgroundColor);

        // height of filled rectangle needs to fill many tab runs and the
        // potential "empty space" generated by separators
        final int height = h * 4;

        g.fillRect(x, y, w, height);

        if (!_pane.getUnclosables().contains(tabIndex)) {
            final Rectangle closeRect = closeRectFor(tabIndex);
            final Image image = _mouseListener.getClosedIndex() != tabIndex ? CLOSE_IMAGE : CLOSE_IMAGE_HOVER;
            g.drawImage(image, closeRect.x, closeRect.y, _pane);
        }
    }

    /**
     * Paints the border for the tab's content, ie. the area below the tabs
     */
    @Override
    protected void paintContentBorder(final Graphics g, final int tabPlacement, final int tabIndex) {
        final int w = tabPane.getWidth();
        final int h = tabPane.getHeight();
        final Insets tabAreaInsets = getTabAreaInsets(tabPlacement);

        final int x = 0;
        final int y = calculateTabAreaHeight(tabPlacement, runCount, maxTabHeight) + tabAreaInsets.bottom;

        g.setColor(_tabSelectedBackgroundColor);
        g.fillRect(x, y, w, h);

        g.setColor(_tabBorderColor);

        // top line, except below selected tab
        final Rectangle selectTabBounds = getTabBounds(tabPane, tabIndex);
        g.drawLine(x, y, selectTabBounds.x, y);
        g.drawLine(selectTabBounds.x + selectTabBounds.width, y, x + w, y);
    }

    @Override
    protected int getTabRunIndent(final int tabPlacement, final int run) {
        return 4;
    }

    @Override
    protected void installListeners() {
        super.installListeners();
        _pane.addMouseListener(_mouseListener);
        _pane.addMouseMotionListener(_mouseListener);
    }

    @Override
    protected void paintTab(final Graphics g, final int tabPlacement, final Rectangle[] rects, final int tabIndex,
            final Rectangle iconRect, final Rectangle textRect) {
        if (_pane.getSeparators().contains(tabIndex)) {
            return;
        }
        super.paintTab(g, tabPlacement, rects, tabIndex, iconRect, textRect);
    }

    @Override
    protected void paintFocusIndicator(final Graphics g, final int tabPlacement, final Rectangle[] rects,
            final int tabIndex, final Rectangle iconRect, final Rectangle textRect, final boolean isSelected) {
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy