From a9e255b9416c43db72ccbece0f2b43a6a35f2860 Mon Sep 17 00:00:00 2001 From: mgarin Date: Tue, 1 Oct 2019 18:43:39 +0300 Subject: [PATCH] CollapsiblePane [ #552 ] - CollapsiblePanePainter.java - Added `expanded`, `expanding`, `collapsed` and `collapsing` states support for style - AbstractHeaderPanel.java, AbstractTitleLabel.java, AbstractControlButton.java - Added `expanding` and `collapsing` states support for style - collapsiblepane.xml - Simplified default style Accordion [ #552 ] - AccordionPane.java - Added `expanded`, `expanding`, `collapsed` and `collapsing` states support for style Styling - AbstractDecorationPainter.java - Minor code optimizations and refactoring - DecorationState.java - Added `expanding` and `collapsing` default states --- .../extended/accordion/AccordionPane.java | 25 +++++- .../extended/accordion/WebAccordionUI.java | 9 +- .../collapsible/AbstractControlButton.java | 4 + .../collapsible/AbstractHeaderPanel.java | 4 + .../collapsible/AbstractTitleLabel.java | 4 + .../collapsible/CollapsiblePanePainter.java | 84 ++++++++++++++++++- .../laf/scroll/layout/ScrollBarSettings.java | 9 +- .../laf/tree/TreeDropLocationPainter.java | 2 +- .../decoration/AbstractDecorationPainter.java | 56 +++++++------ .../painter/decoration/DecorationState.java | 20 +++++ .../skin/dark/resources/collapsiblepane.xml | 20 ++--- .../skin/web/resources/collapsiblepane.xml | 20 ++--- 12 files changed, 195 insertions(+), 62 deletions(-) diff --git a/modules/ui/src/com/alee/extended/accordion/AccordionPane.java b/modules/ui/src/com/alee/extended/accordion/AccordionPane.java index e41aae9b7..7a3989735 100644 --- a/modules/ui/src/com/alee/extended/accordion/AccordionPane.java +++ b/modules/ui/src/com/alee/extended/accordion/AccordionPane.java @@ -27,6 +27,8 @@ import com.alee.extended.collapsible.HeaderLayout; import com.alee.laf.panel.WebPanel; import com.alee.managers.style.StyleId; +import com.alee.painter.decoration.DecorationState; +import com.alee.painter.decoration.Stateful; import com.alee.utils.SwingUtils; import javax.swing.*; @@ -34,6 +36,8 @@ import java.awt.event.ActionEvent; import java.awt.event.InputEvent; import java.awt.event.MouseEvent; +import java.util.ArrayList; +import java.util.List; /** * {@link AccordionPane} for a single collapsible content {@link Component} within {@link WebAccordion}. @@ -46,7 +50,7 @@ * @see AccordionModel * @see WebAccordionModel */ -public class AccordionPane extends WebPanel implements Identifiable +public class AccordionPane extends WebPanel implements Stateful, Identifiable { /** * {@link AccordionPane} unique identifier. @@ -143,6 +147,25 @@ public String getId () return id; } + @Nullable + @Override + public List getStates () + { + final List states = new ArrayList ( 3 ); + + // Header position state + states.add ( getHeaderPosition ().name () ); + + // Expansion state + states.add ( isExpanded () || isInTransition () ? DecorationState.expanded : DecorationState.collapsed ); + if ( isInTransition () ) + { + states.add ( isExpanded () ? DecorationState.expanding : DecorationState.collapsing ); + } + + return states; + } + /** * Returns header {@link JComponent}. * diff --git a/modules/ui/src/com/alee/extended/accordion/WebAccordionUI.java b/modules/ui/src/com/alee/extended/accordion/WebAccordionUI.java index 67da6039d..5c5745c9c 100644 --- a/modules/ui/src/com/alee/extended/accordion/WebAccordionUI.java +++ b/modules/ui/src/com/alee/extended/accordion/WebAccordionUI.java @@ -175,20 +175,15 @@ protected void updateDecorationStates () */ protected void updateDecorationStates ( @NotNull final AccordionPane pane ) { - // Updating pane decoration states - DecorationUtils.fireStatesChanged ( pane ); - - // Updating pane header decoration states final Component header = pane.getHeader (); - DecorationUtils.fireStatesChanged ( header ); - - // Updating pane header contents decoration states if ( header instanceof AbstractHeaderPanel ) { final AbstractHeaderPanel headerPanel = ( AbstractHeaderPanel ) header; DecorationUtils.fireStatesChanged ( headerPanel.getTitle () ); DecorationUtils.fireStatesChanged ( headerPanel.getControl () ); } + DecorationUtils.fireStatesChanged ( header ); + DecorationUtils.fireStatesChanged ( pane ); } @NotNull diff --git a/modules/ui/src/com/alee/extended/collapsible/AbstractControlButton.java b/modules/ui/src/com/alee/extended/collapsible/AbstractControlButton.java index e944a2f00..930421a5d 100644 --- a/modules/ui/src/com/alee/extended/collapsible/AbstractControlButton.java +++ b/modules/ui/src/com/alee/extended/collapsible/AbstractControlButton.java @@ -108,6 +108,10 @@ public List getStates () // Expansion state states.add ( isExpanded () || isInTransition () ? DecorationState.expanded : DecorationState.collapsed ); + if ( isInTransition () ) + { + states.add ( isExpanded () ? DecorationState.expanding : DecorationState.collapsing ); + } return states; } diff --git a/modules/ui/src/com/alee/extended/collapsible/AbstractHeaderPanel.java b/modules/ui/src/com/alee/extended/collapsible/AbstractHeaderPanel.java index 3e271a144..fb1d38d0f 100644 --- a/modules/ui/src/com/alee/extended/collapsible/AbstractHeaderPanel.java +++ b/modules/ui/src/com/alee/extended/collapsible/AbstractHeaderPanel.java @@ -169,6 +169,10 @@ public List getStates () // Expansion state states.add ( isExpanded () || isInTransition () ? DecorationState.expanded : DecorationState.collapsed ); + if ( isInTransition () ) + { + states.add ( isExpanded () ? DecorationState.expanding : DecorationState.collapsing ); + } return states; } diff --git a/modules/ui/src/com/alee/extended/collapsible/AbstractTitleLabel.java b/modules/ui/src/com/alee/extended/collapsible/AbstractTitleLabel.java index 01e3a3711..36ab49e21 100644 --- a/modules/ui/src/com/alee/extended/collapsible/AbstractTitleLabel.java +++ b/modules/ui/src/com/alee/extended/collapsible/AbstractTitleLabel.java @@ -116,6 +116,10 @@ public List getStates () // Expansion state states.add ( isExpanded () || isInTransition () ? DecorationState.expanded : DecorationState.collapsed ); + if ( isInTransition () ) + { + states.add ( isExpanded () ? DecorationState.expanding : DecorationState.collapsing ); + } // Icon state if ( getIcon () != null ) diff --git a/modules/ui/src/com/alee/extended/collapsible/CollapsiblePanePainter.java b/modules/ui/src/com/alee/extended/collapsible/CollapsiblePanePainter.java index 408a3981f..518f9ac57 100644 --- a/modules/ui/src/com/alee/extended/collapsible/CollapsiblePanePainter.java +++ b/modules/ui/src/com/alee/extended/collapsible/CollapsiblePanePainter.java @@ -17,9 +17,14 @@ package com.alee.extended.collapsible; +import com.alee.api.annotations.NotNull; import com.alee.painter.decoration.AbstractDecorationPainter; +import com.alee.painter.decoration.DecorationState; +import com.alee.painter.decoration.DecorationUtils; import com.alee.painter.decoration.IDecoration; +import java.util.List; + /** * Basic painter for {@link WebCollapsiblePane} component. * It is used as {@link WCollapsiblePaneUI} default painter. @@ -35,6 +40,83 @@ public class CollapsiblePanePainter implements ICollapsiblePanePainter { /** - * Implementation is used completely from {@link AbstractDecorationPainter}. + * Listeners. + */ + protected transient CollapsiblePaneListener collapsiblePaneListener; + + @Override + protected void installPropertiesAndListeners () + { + super.installPropertiesAndListeners (); + installCollapsiblePaneListener (); + } + + @Override + protected void uninstallPropertiesAndListeners () + { + uninstallCollapsiblePaneListener (); + super.uninstallPropertiesAndListeners (); + } + + /** + * Installs {@link CollapsiblePaneListener}. + */ + protected void installCollapsiblePaneListener () + { + collapsiblePaneListener = new CollapsiblePaneListener () + { + @Override + public void expanding ( @NotNull final WebCollapsiblePane pane ) + { + DecorationUtils.fireStatesChanged ( pane ); + } + + @Override + public void expanded ( @NotNull final WebCollapsiblePane pane ) + { + DecorationUtils.fireStatesChanged ( pane ); + } + + @Override + public void collapsing ( @NotNull final WebCollapsiblePane pane ) + { + DecorationUtils.fireStatesChanged ( pane ); + } + + @Override + public void collapsed ( @NotNull final WebCollapsiblePane pane ) + { + DecorationUtils.fireStatesChanged ( pane ); + } + }; + component.addCollapsiblePaneListener ( collapsiblePaneListener ); + } + + /** + * Uninstalls {@link CollapsiblePaneListener}. */ + protected void uninstallCollapsiblePaneListener () + { + component.removeCollapsiblePaneListener ( collapsiblePaneListener ); + collapsiblePaneListener = null; + } + + @NotNull + @Override + public List getDecorationStates () + { + final List states = super.getDecorationStates (); + + // Header position state + states.add ( component.getHeaderPosition ().name () ); + + // Expansion state + states.add ( component.isExpanded () || component.isInTransition () ? DecorationState.expanded : DecorationState.collapsed ); + if ( component.isInTransition () ) + { + states.add ( component.isExpanded () ? DecorationState.expanding : DecorationState.collapsing ); + } + + return states; + } } \ No newline at end of file diff --git a/modules/ui/src/com/alee/laf/scroll/layout/ScrollBarSettings.java b/modules/ui/src/com/alee/laf/scroll/layout/ScrollBarSettings.java index 55cce053f..63b4e6d4a 100644 --- a/modules/ui/src/com/alee/laf/scroll/layout/ScrollBarSettings.java +++ b/modules/ui/src/com/alee/laf/scroll/layout/ScrollBarSettings.java @@ -17,6 +17,7 @@ package com.alee.laf.scroll.layout; +import com.alee.api.annotations.Nullable; import com.alee.api.merge.Mergeable; import com.thoughtworks.xstream.annotations.XStreamAlias; import com.thoughtworks.xstream.annotations.XStreamAsAttribute; @@ -37,6 +38,7 @@ public class ScrollBarSettings implements Mergeable, Cloneable, Serializable * Exact corner taken by the scroll bar depends on the scroll bar orientation. * This setting is set to {@code false} by default to replicate common Swing scroll panes behavior. */ + @Nullable @XStreamAsAttribute protected Boolean leading; @@ -45,6 +47,7 @@ public class ScrollBarSettings implements Mergeable, Cloneable, Serializable * Exact corner taken by the scroll bar depends on the scroll bar orientation. * This setting is set to {@code false} by default to replicate common Swing scroll panes behavior. */ + @Nullable @XStreamAsAttribute protected Boolean trailing; @@ -55,6 +58,7 @@ public class ScrollBarSettings implements Mergeable, Cloneable, Serializable * It is important to know that hovering non-opaque scroll bar also forces underlying components to be non-opaque, * otherwise you will encounter many repainting issues with the content and scroll bar itself. */ + @Nullable @XStreamAsAttribute protected Boolean hovering; @@ -62,6 +66,7 @@ public class ScrollBarSettings implements Mergeable, Cloneable, Serializable * Whether or not scroll bar should be counted in scroll pane preferred size when it is {@link #hovering}. * It could be useful to receive a better scroll pane preferred size to avoid scroll bar obstructing any content. */ + @Nullable @XStreamAsAttribute protected Boolean extending; @@ -81,9 +86,9 @@ public ScrollBarSettings () * @param hovering whether scroll bar should hover above the scroll pane content instead of taking extra space * @param extending whether or not scroll bar should be counted in scroll pane preferred size */ - public ScrollBarSettings ( final Boolean leading, final Boolean trailing, final Boolean hovering, final Boolean extending ) + public ScrollBarSettings ( @Nullable final Boolean leading, @Nullable final Boolean trailing, + @Nullable final Boolean hovering, @Nullable final Boolean extending ) { - super (); this.leading = leading; this.trailing = trailing; this.hovering = hovering; diff --git a/modules/ui/src/com/alee/laf/tree/TreeDropLocationPainter.java b/modules/ui/src/com/alee/laf/tree/TreeDropLocationPainter.java index 344088764..2eafd817a 100644 --- a/modules/ui/src/com/alee/laf/tree/TreeDropLocationPainter.java +++ b/modules/ui/src/com/alee/laf/tree/TreeDropLocationPainter.java @@ -72,7 +72,7 @@ public void prepareToPaint ( final JTree.DropLocation location ) } @Override - protected boolean isDecorationAvailable ( final D decoration ) + protected boolean isDecorationAvailable ( @NotNull final D decoration ) { // We don't need to paint anything when drop location is not available return location != null && super.isDecorationAvailable ( decoration ); diff --git a/modules/ui/src/com/alee/painter/decoration/AbstractDecorationPainter.java b/modules/ui/src/com/alee/painter/decoration/AbstractDecorationPainter.java index 339433e1d..2f22fc5c0 100644 --- a/modules/ui/src/com/alee/painter/decoration/AbstractDecorationPainter.java +++ b/modules/ui/src/com/alee/painter/decoration/AbstractDecorationPainter.java @@ -885,6 +885,7 @@ protected boolean isEnabled () * * @return properly sorted current component decoration states */ + @NotNull protected final List collectDecorationStates () { // Retrieving current decoration states @@ -992,13 +993,12 @@ protected final boolean usesState ( final Decorations decorations, final S * @param forStates decoration states to retrieve decoration for * @return decorations for the specified states */ - @Nullable + @NotNull protected final List getDecorations ( @NotNull final List forStates ) { - final List result; + final List result = new ArrayList ( ); if ( decorations != null && decorations.size () > 0 ) { - result = new ArrayList ( 1 ); for ( final D decoration : decorations ) { if ( decoration.isApplicableTo ( forStates ) ) @@ -1007,10 +1007,6 @@ protected final List getDecorations ( @NotNull final List forStates ) } } } - else - { - result = null; - } return result; } @@ -1018,7 +1014,7 @@ protected final List getDecorations ( @NotNull final List forStates ) @Override public final D getDecoration () { - // Optimization for painter without decorations + final D result; if ( decorations != null && decorations.size () > 0 ) { // Decoration key @@ -1135,13 +1131,14 @@ else if ( Objects.notEquals ( previous, current ) ) } // Returning existing decoration - return stateDecorationCache.get ( current ); + result = stateDecorationCache.get ( current ); } else { // No decorations added - return null; + result = null; } + return result; } /** @@ -1150,7 +1147,8 @@ else if ( Objects.notEquals ( previous, current ) ) * @param decorations decorations to retrieve unique combination key for * @return unique decorations combination key */ - protected final String getDecorationsKey ( final List decorations ) + @NotNull + protected final String getDecorationsKey ( @NotNull final List decorations ) { final StringBuilder key = new StringBuilder ( 15 * decorations.size () ); for ( final D decoration : decorations ) @@ -1169,7 +1167,7 @@ protected final String getDecorationsKey ( final List decorations ) * * @param c painted component */ - protected final void deactivateLastDecoration ( final C c ) + protected final void deactivateLastDecoration ( @NotNull final C c ) { final D decoration = getDecoration (); if ( decoration != null ) @@ -1214,7 +1212,7 @@ protected Insets getBorder () { final Insets insets; final D decoration = getDecoration (); - if ( isDecorationAvailable ( decoration ) ) + if ( decoration != null && isDecorationAvailable ( decoration ) ) { insets = decoration.getBorderInsets ( component ); } @@ -1248,7 +1246,7 @@ public Boolean isOpaque () { final Boolean opaque; final D decoration = getDecoration (); - if ( isDecorationAvailable ( decoration ) ) + if ( decoration != null && isDecorationAvailable ( decoration ) ) { opaque = isOpaqueDecorated (); } @@ -1289,55 +1287,61 @@ protected Boolean isOpaqueUndecorated () @Override public boolean contains ( @NotNull final C c, @NotNull final U ui, @NotNull final Bounds bounds, final int x, final int y ) { + final boolean contains; final D decoration = getDecoration (); - if ( isDecorationAvailable ( decoration ) ) + if ( decoration != null && isDecorationAvailable ( decoration ) ) { // Creating additional bounds final Bounds marginBounds = new Bounds ( bounds, BoundsType.margin, c, decoration ); // Using decoration contains method - return decoration.contains ( c, marginBounds, x, y ); + contains = decoration.contains ( c, marginBounds, x, y ); } else { // Using default contains method - return super.contains ( c, ui, bounds, x, y ); + contains = super.contains ( c, ui, bounds, x, y ); } + return contains; } @Override public int getBaseline ( @NotNull final C c, @NotNull final U ui, @NotNull final Bounds bounds ) { + final int baseline; final D decoration = getDecoration (); - if ( isDecorationAvailable ( decoration ) ) + if ( decoration != null && isDecorationAvailable ( decoration ) ) { // Creating additional bounds final Bounds marginBounds = new Bounds ( bounds, BoundsType.margin, c, decoration ); // Calculating decoration baseline - return decoration.getBaseline ( c, marginBounds ); + baseline = decoration.getBaseline ( c, marginBounds ); } else { // Calculating default baseline - return super.getBaseline ( c, ui, bounds ); + baseline = super.getBaseline ( c, ui, bounds ); } + return baseline; } @Override public Component.BaselineResizeBehavior getBaselineResizeBehavior ( @NotNull final C c, @NotNull final U ui ) { + final Component.BaselineResizeBehavior behavior; final D decoration = getDecoration (); - if ( isDecorationAvailable ( decoration ) ) + if ( decoration != null && isDecorationAvailable ( decoration ) ) { // Returning decoration baseline behavior - return decoration.getBaselineResizeBehavior ( c ); + behavior = decoration.getBaselineResizeBehavior ( c ); } else { // Returning default baseline behavior - return super.getBaselineResizeBehavior ( c, ui ); + behavior = super.getBaselineResizeBehavior ( c, ui ); } + return behavior; } @Override @@ -1354,7 +1358,7 @@ public void paint ( @NotNull final Graphics2D g2d, @NotNull final C c, @NotNull // Painting current decoration state final D decoration = getDecoration (); - if ( isDecorationAvailable ( decoration ) ) + if ( decoration != null && isDecorationAvailable ( decoration ) ) { // Creating additional bounds final Bounds marginBounds = new Bounds ( bounds, BoundsType.margin, c, decoration ); @@ -1402,9 +1406,9 @@ protected boolean isPlainBackgroundRequired ( final C c ) * @param decoration decoration to be painted * @return {@code true} if painting specified decoration is available, {@code false} otherwise */ - protected boolean isDecorationAvailable ( final D decoration ) + protected boolean isDecorationAvailable ( @NotNull final D decoration ) { - return decoration != null; + return true; } @NotNull diff --git a/modules/ui/src/com/alee/painter/decoration/DecorationState.java b/modules/ui/src/com/alee/painter/decoration/DecorationState.java index c69a4d321..921778be7 100644 --- a/modules/ui/src/com/alee/painter/decoration/DecorationState.java +++ b/modules/ui/src/com/alee/painter/decoration/DecorationState.java @@ -197,6 +197,15 @@ public interface DecorationState */ public static final String hasIcon = "has-icon"; + /** + * Used to provide component collapsing state. + * + * @see com.alee.extended.collapsible.CollapsiblePanePainter#getDecorationStates() + * @see com.alee.extended.collapsible.AbstractTitleLabel#getStates() + * @see com.alee.extended.collapsible.AbstractHeaderPanel#getStates() + */ + public static final String collapsing = "collapsing"; + /** * Used to provide component collapsed state. * @@ -208,11 +217,21 @@ public interface DecorationState * @see com.alee.laf.tree.TreeRowPainter#getDecorationStates() * @see com.alee.laf.tree.TreeNodePainter#getDecorationStates() * @see com.alee.extended.tree.WebCheckBoxTreeCellRenderer#getStates() + * @see com.alee.extended.collapsible.CollapsiblePanePainter#getDecorationStates() * @see com.alee.extended.collapsible.AbstractTitleLabel#getStates() * @see com.alee.extended.collapsible.AbstractHeaderPanel#getStates() */ public static final String collapsed = "collapsed"; + /** + * Used to provide component expanding state. + * + * @see com.alee.extended.collapsible.CollapsiblePanePainter#getDecorationStates() + * @see com.alee.extended.collapsible.AbstractTitleLabel#getStates() + * @see com.alee.extended.collapsible.AbstractHeaderPanel#getStates() + */ + public static final String expanding = "expanding"; + /** * Used to provide component expanded state. * @@ -224,6 +243,7 @@ public interface DecorationState * @see com.alee.laf.tree.TreeRowPainter#getDecorationStates() * @see com.alee.laf.tree.TreeNodePainter#getDecorationStates() * @see com.alee.extended.tree.WebCheckBoxTreeCellRenderer#getStates() + * @see com.alee.extended.collapsible.CollapsiblePanePainter#getDecorationStates() * @see com.alee.extended.collapsible.AbstractTitleLabel#getStates() * @see com.alee.extended.collapsible.AbstractHeaderPanel#getStates() */ diff --git a/modules/ui/src/com/alee/skin/dark/resources/collapsiblepane.xml b/modules/ui/src/com/alee/skin/dark/resources/collapsiblepane.xml index e74f18146..771975be7 100644 --- a/modules/ui/src/com/alee/skin/dark/resources/collapsiblepane.xml +++ b/modules/ui/src/com/alee/skin/dark/resources/collapsiblepane.xml @@ -39,30 +39,26 @@ 77,81,83 - - - - - + + - + - + + - + + - + - - - diff --git a/modules/ui/src/com/alee/skin/web/resources/collapsiblepane.xml b/modules/ui/src/com/alee/skin/web/resources/collapsiblepane.xml index 6f5ff49a4..6a70e44e6 100644 --- a/modules/ui/src/com/alee/skin/web/resources/collapsiblepane.xml +++ b/modules/ui/src/com/alee/skin/web/resources/collapsiblepane.xml @@ -39,30 +39,26 @@ 223,223,223 - - - - - + + - + - + + - + + - + - - -