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

com.alee.extended.collapsible.WebCollapsiblePane Maven / Gradle / Ivy

There is a newer version: 1.2.14
Show newest version
/*
 * This file is part of WebLookAndFeel library.
 *
 * WebLookAndFeel library is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * WebLookAndFeel 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 General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with WebLookAndFeel library.  If not, see .
 */

package com.alee.extended.collapsible;

import com.alee.api.annotations.NotNull;
import com.alee.api.annotations.Nullable;
import com.alee.api.data.BoxOrientation;
import com.alee.extended.WebContainer;
import com.alee.managers.style.StyleId;
import com.alee.managers.style.StyleManager;

import javax.swing.*;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.InputEvent;
import java.awt.event.MouseEvent;

/**
 * This extended components allows you to quickly create and manipulate a collapsible pane.
 * Pane title, content and style can be modified in any way you like.
 *
 * @author Mikle Garin
 */
public class WebCollapsiblePane extends WebContainer
{
    /**
     * Component properties.
     */
    public static final String HEADER_POSITION_PROPERTY = "headerPosition";
    public static final String HEADER_COMPONENT_PROPERTY = "headerComponent";
    public static final String TITLE_PROPERTY = "title";
    public static final String TITLE_COMPONENT_PROPERTY = "titleComponent";
    public static final String CONTROL_COMPONENT_PROPERTY = "controlComponent";
    public static final String CONTENT_PROPERTY = "content";
    public static final String EXPANDED_PROPERTY = "expanded";
    public static final String IN_TRANSITION_PROPERTY = "inTransition";

    /**
     * Title {@link Component}.
     */
    @Nullable
    protected Component header;

    /**
     * Title {@link Component}.
     */
    @Nullable
    protected Component title;

    /**
     * Control {@link Component}.
     */
    @Nullable
    protected Component control;

    /**
     * Content {@link Component}.
     */
    @Nullable
    protected Component content;

    /**
     * Header panel position.
     */
    @Nullable
    protected BoxOrientation headerPosition;

    /**
     * Whether or not {@link WebCollapsiblePane} is expanded.
     */
    protected boolean expanded = true;

    /**
     * Constructs empty {@link WebCollapsiblePane}.
     */
    public WebCollapsiblePane ()
    {
        this ( StyleId.auto, ( String ) null );
    }

    /**
     * Constructs empty {@link WebCollapsiblePane} with specified title text.
     *
     * @param title title text
     */
    public WebCollapsiblePane ( @Nullable final String title )
    {
        this ( StyleId.auto, null, title );
    }

    /**
     * Constructs empty {@link WebCollapsiblePane} with specified title icon and text.
     *
     * @param icon  title icon
     * @param title title text
     */
    public WebCollapsiblePane ( @Nullable final Icon icon, @Nullable final String title )
    {
        this ( StyleId.auto, icon, title, null );
    }

    /**
     * Constructs {@link WebCollapsiblePane} with specified content.
     *
     * @param content content {@link Component}
     */
    public WebCollapsiblePane ( @Nullable final Component content )
    {
        this ( StyleId.auto, null, null, content );
    }

    /**
     * Constructs {@link WebCollapsiblePane} with specified title text and content.
     *
     * @param title   title text
     * @param content content {@link Component}
     */
    public WebCollapsiblePane ( @Nullable final String title, @Nullable final Component content )
    {
        this ( StyleId.auto, null, title, content );
    }

    /**
     * Constructs {@link WebCollapsiblePane} with specified title icon, text and content.
     *
     * @param icon    title icon
     * @param title   title text
     * @param content content {@link Component}
     */
    public WebCollapsiblePane ( @Nullable final Icon icon, @Nullable final String title, @Nullable final Component content )
    {
        this ( StyleId.auto, icon, title, content );
    }

    /**
     * Constructs empty {@link WebCollapsiblePane}.
     *
     * @param id style ID
     */
    public WebCollapsiblePane ( @NotNull final StyleId id )
    {
        this ( id, "" );
    }

    /**
     * Constructs empty {@link WebCollapsiblePane} with specified title text.
     *
     * @param id    style ID
     * @param title title text
     */
    public WebCollapsiblePane ( @NotNull final StyleId id, @Nullable final String title )
    {
        this ( id, null, title );
    }

    /**
     * Constructs empty {@link WebCollapsiblePane} with specified title icon and text.
     *
     * @param id    style ID
     * @param icon  title icon
     * @param title title text
     */
    public WebCollapsiblePane ( @NotNull final StyleId id, @Nullable final Icon icon, @Nullable final String title )
    {
        this ( id, icon, title, null );
    }

    /**
     * Constructs {@link WebCollapsiblePane} with specified content.
     *
     * @param id      style ID
     * @param content content {@link Component}
     */
    public WebCollapsiblePane ( @NotNull final StyleId id, @Nullable final Component content )
    {
        this ( id, null, "", content );
    }

    /**
     * Constructs {@link WebCollapsiblePane} with specified title text and content.
     *
     * @param id      style ID
     * @param title   title text
     * @param content content {@link Component}
     */
    public WebCollapsiblePane ( @NotNull final StyleId id, @Nullable final String title, @Nullable final Component content )
    {
        this ( id, null, title, content );
    }

    /**
     * Constructs {@link WebCollapsiblePane} with specified title icon, text and content.
     *
     * @param id      style ID
     * @param icon    title icon
     * @param title   title text
     * @param content content {@link Component}
     */
    public WebCollapsiblePane ( @NotNull final StyleId id, @Nullable final Icon icon, @Nullable final String title,
                                @Nullable final Component content )
    {
        updateUI ();
        setIcon ( icon );
        setTitle ( title );
        setContent ( content );
        setStyleId ( id );
    }

    @Override
    public StyleId getDefaultStyleId ()
    {
        return StyleId.collapsiblepane;
    }

    @Override
    public void setLayout ( @Nullable final LayoutManager layout )
    {
        if ( layout == null || layout instanceof CollapsiblePaneLayout )
        {
            final CollapsiblePaneLayout oldLayout = getLayout ();
            if ( oldLayout != null )
            {
                oldLayout.uninstall ( this );
            }
            final CollapsiblePaneLayout newLayout = ( CollapsiblePaneLayout ) layout;
            if ( layout != null )
            {
                newLayout.install ( this );
            }
            super.setLayout ( layout );
        }
        else
        {
            throw new IllegalArgumentException ( "Only CollapsiblePaneLayout instances are supported" );
        }
    }

    @Override
    public CollapsiblePaneLayout getLayout ()
    {
        return ( CollapsiblePaneLayout ) super.getLayout ();
    }

    /**
     * Returns header panel position.
     *
     * @return header panel position
     */
    @NotNull
    public BoxOrientation getHeaderPosition ()
    {
        return headerPosition != null ? headerPosition : BoxOrientation.top;
    }

    /**
     * Sets header panel position.
     *
     * @param position new header panel position
     */
    public void setHeaderPosition ( @Nullable final BoxOrientation position )
    {
        final BoxOrientation headerPosition = getHeaderPosition ();
        if ( headerPosition != position )
        {
            this.headerPosition = position;
            firePropertyChange ( HEADER_POSITION_PROPERTY, headerPosition, position );
        }
    }

    /**
     * Returns current header {@link Component}.
     *
     * @return current header {@link Component}
     */
    @NotNull
    public Component getHeaderComponent ()
    {
        if ( header == null )
        {
            setHeaderComponent ( createHeaderComponent () );
        }
        return header;
    }

    /**
     * Sets header {@link Component}.
     * Note that modifying header will cause custom icon, title and control to be lost.
     *
     * @param header header {@link Component}
     */
    public void setHeaderComponent ( @NotNull final Component header )
    {
        if ( this.header != header )
        {
            final Component old = this.header;
            this.header = header;
            firePropertyChange ( HEADER_COMPONENT_PROPERTY, old, header );
        }
    }

    /**
     * Returns default header {@link Component}.
     *
     * @return default header {@link Component}
     */
    @NotNull
    protected Component createHeaderComponent ()
    {
        return new AbstractHeaderPanel.UIResource ()
        {
            @NotNull
            @Override
            public BoxOrientation getHeaderPosition ()
            {
                return WebCollapsiblePane.this.getHeaderPosition ();
            }

            @Override
            public boolean isExpanded ()
            {
                return WebCollapsiblePane.this.isExpanded ();
            }

            @Override
            public boolean isInTransition ()
            {
                return WebCollapsiblePane.this.isInTransition ();
            }

            @Override
            protected void onHeaderAction ( @NotNull final InputEvent e )
            {
                expandOrCollapse ( e );
            }
        };
    }

    /**
     * Returns default title component {@link Icon}.
     *
     * @return default title component {@link Icon}
     */
    @Nullable
    public Icon getIcon ()
    {
        return title instanceof AbstractTitleLabel ? ( ( AbstractTitleLabel ) title ).getIcon () : null;
    }

    /**
     * Sets default title component {@link Icon}.
     * Note that this will only work with default {@link AbstractTitleLabel} implementation or it's derivatives.
     *
     * @param icon new default title component {@link Icon}
     */
    public void setIcon ( @Nullable final Icon icon )
    {
        final Component titleComponent = getTitleComponent ();
        if ( titleComponent instanceof AbstractTitleLabel )
        {
            final AbstractTitleLabel titleLabel = ( AbstractTitleLabel ) titleComponent;
            final Icon old = titleLabel.getIcon ();
            titleLabel.setIcon ( icon );
            firePropertyChange ( TITLE_PROPERTY, old, titleComponent );
        }
    }

    /**
     * Returns default title component text.
     *
     * @return default title component text
     */
    @Nullable
    public String getTitle ()
    {
        return title instanceof AbstractTitleLabel ? ( ( AbstractTitleLabel ) title ).getText () : null;
    }

    /**
     * Sets default title component text.
     * Note that this will only work with default {@link AbstractTitleLabel} implementation or it's derivatives.
     *
     * @param title new title text
     */
    public void setTitle ( @Nullable final String title )
    {
        final Component titleComponent = getTitleComponent ();
        if ( titleComponent instanceof AbstractTitleLabel )
        {
            final AbstractTitleLabel titleLabel = ( AbstractTitleLabel ) titleComponent;
            final String oldTitle = titleLabel.getText ();
            titleLabel.setText ( title );
            firePropertyChange ( TITLE_PROPERTY, oldTitle, title );
        }
    }

    /**
     * Returns title {@link Component}.
     *
     * @return title {@link Component}
     */
    @Nullable
    public Component getTitleComponent ()
    {
        if ( title == null )
        {
            setTitleComponent ( createTitleComponent () );
        }
        return title;
    }

    /**
     * Sets title {@link Component}.
     * Note that modifying title component will cause custom icon and title to be lost.
     *
     * @param title new title {@link Component}
     */
    public void setTitleComponent ( @Nullable final Component title )
    {
        if ( this.title != title )
        {
            final Component oldTitle = this.title;
            this.title = title;
            firePropertyChange ( TITLE_COMPONENT_PROPERTY, oldTitle, title );
        }
    }

    /**
     * Returns default title {@link Component}.
     *
     * @return default title {@link Component}
     */
    @Nullable
    protected Component createTitleComponent ()
    {
        return new AbstractTitleLabel.UIResource ()
        {
            @NotNull
            @Override
            public BoxOrientation getHeaderPosition ()
            {
                return WebCollapsiblePane.this.getHeaderPosition ();
            }

            @Override
            public boolean isExpanded ()
            {
                return WebCollapsiblePane.this.isExpanded ();
            }

            @Override
            public boolean isInTransition ()
            {
                return WebCollapsiblePane.this.isInTransition ();
            }
        };
    }

    /**
     * Returns control {@link Component}.
     *
     * @return control {@link Component}
     */
    @Nullable
    public Component getControlComponent ()
    {
        if ( control == null )
        {
            setControlComponent ( createControlComponent () );
        }
        return control;
    }

    /**
     * Sets control {@link Component}.
     *
     * @param control new control {@link Component}
     */
    public void setControlComponent ( @Nullable final Component control )
    {
        if ( this.control != control )
        {
            final Component old = this.control;
            this.control = control;
            firePropertyChange ( CONTROL_COMPONENT_PROPERTY, old, control );
        }
    }

    /**
     * Returns default expansion control {@link Component}.
     *
     * @return default expansion control {@link Component}
     */
    @Nullable
    protected Component createControlComponent ()
    {
        return new AbstractControlButton.UIResource ()
        {
            @NotNull
            @Override
            public BoxOrientation getHeaderPosition ()
            {
                return WebCollapsiblePane.this.getHeaderPosition ();
            }

            @Override
            public boolean isExpanded ()
            {
                return WebCollapsiblePane.this.isExpanded ();
            }

            @Override
            public boolean isInTransition ()
            {
                return WebCollapsiblePane.this.isInTransition ();
            }

            @Override
            protected void onControlAction ( @NotNull final ActionEvent e )
            {
                expandOrCollapse ( e );
            }
        };
    }

    /**
     * Either expands or collapses this {@link WebCollapsiblePane}.
     *
     * @param e {@link AWTEvent}
     */
    protected void expandOrCollapse ( @NotNull final AWTEvent e )
    {
        WebCollapsiblePane.this.setExpanded ( !WebCollapsiblePane.this.isExpanded () );
        if ( e instanceof MouseEvent || e instanceof ActionEvent )
        {
            if ( WebCollapsiblePane.this.isShowing () && WebCollapsiblePane.this.isEnabled () )
            {
                if ( WebCollapsiblePane.this.isFocusable () )
                {
                    WebCollapsiblePane.this.requestFocusInWindow ();
                }
                else
                {
                    WebCollapsiblePane.this.transferFocus ();
                }
            }
        }
    }

    /**
     * Returns content {@link Component}.
     *
     * @return content {@link Component}
     */
    @Nullable
    public Component getContent ()
    {
        return content;
    }

    /**
     * Sets content {@link Component}.
     *
     * @param content new content {@link Component}
     */
    public void setContent ( @Nullable final Component content )
    {
        if ( this.content != content )
        {
            final Component old = this.content;
            this.content = content;
            firePropertyChange ( CONTENT_PROPERTY, old, content );
        }
    }

    /**
     * Returns whether or not {@link WebCollapsiblePane} is expanded.
     *
     * @return {@code true} if {@link WebCollapsiblePane} is expanded, {@code false} otherwise
     */
    public boolean isExpanded ()
    {
        return expanded;
    }

    /**
     * Sets whether or not {@link WebCollapsiblePane} is expanded
     *
     * @param expanded whether or not {@link WebCollapsiblePane} is expanded
     */
    public void setExpanded ( final boolean expanded )
    {
        if ( this.expanded != expanded )
        {
            final boolean old = this.expanded;
            this.expanded = expanded;
            firePropertyChange ( EXPANDED_PROPERTY, old, expanded );
        }
    }

    /**
     * Returns whether or not {@link WebCollapsiblePane} is in transition to either of two expansion states.
     * Note this will only be {@code true} whenever {@link #expanded} state changes and {@link CollapsiblePaneLayout} is configured to
     * perform an animated transition on the {@link #content} of this {@link WebCollapsiblePane}.
     *
     * @return {@code true} if {@link WebCollapsiblePane} is in transition, {@code false} otherwise
     */
    public boolean isInTransition ()
    {
        return getLayout ().isInTransition ();
    }

    /**
     * Adds {@link CollapsiblePaneListener}.
     *
     * @param listener {@link CollapsiblePaneListener} to add
     */
    public void addCollapsiblePaneListener ( @NotNull final CollapsiblePaneListener listener )
    {
        listenerList.add ( CollapsiblePaneListener.class, listener );
    }

    /**
     * Removes {@link CollapsiblePaneListener}.
     *
     * @param listener {@link CollapsiblePaneListener} to remove
     */
    public void removeCollapsiblePaneListener ( @NotNull final CollapsiblePaneListener listener )
    {
        listenerList.remove ( CollapsiblePaneListener.class, listener );
    }

    /**
     * Notifies when {@link WebCollapsiblePane} starts to expand.
     */
    public void fireExpanding ()
    {
        for ( final CollapsiblePaneListener listener : listenerList.getListeners ( CollapsiblePaneListener.class ) )
        {
            listener.expanding ( this );
        }
    }

    /**
     * Notifies when {@link WebCollapsiblePane} finished expanding.
     */
    public void fireExpanded ()
    {
        for ( final CollapsiblePaneListener listener : listenerList.getListeners ( CollapsiblePaneListener.class ) )
        {
            listener.expanded ( this );
        }
    }

    /**
     * Notifies when {@link WebCollapsiblePane} starts to collapse.
     */
    public void fireCollapsing ()
    {
        for ( final CollapsiblePaneListener listener : listenerList.getListeners ( CollapsiblePaneListener.class ) )
        {
            listener.collapsing ( this );
        }
    }

    /**
     * Notifies when {@link WebCollapsiblePane} finished collapsing.
     */
    public void fireCollapsed ()
    {
        for ( final CollapsiblePaneListener listener : listenerList.getListeners ( CollapsiblePaneListener.class ) )
        {
            listener.collapsed ( this );
        }
    }

    /**
     * Returns the look and feel (LaF) object that renders this component.
     *
     * @return the {@link WCollapsiblePaneUI} object that renders this component
     */
    public WCollapsiblePaneUI getUI ()
    {
        return ( WCollapsiblePaneUI ) ui;
    }

    /**
     * Sets the LaF object that renders this component.
     *
     * @param ui {@link WCollapsiblePaneUI}
     */
    public void setUI ( final WCollapsiblePaneUI ui )
    {
        super.setUI ( ui );
    }

    @Override
    public void updateUI ()
    {
        StyleManager.getDescriptor ( this ).updateUI ( this );
    }

    @NotNull
    @Override
    public String getUIClassID ()
    {
        return StyleManager.getDescriptor ( this ).getUIClassId ();
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy