001    package org.springframework.richclient.command;
002    
003    import org.springframework.richclient.application.Application;
004    import org.springframework.richclient.command.config.CommandButtonConfigurer;
005    import org.springframework.richclient.command.config.CommandConfigurer;
006    import org.springframework.richclient.factory.ButtonFactory;
007    
008    import javax.swing.*;
009    import java.beans.PropertyChangeListener;
010    import java.beans.PropertyChangeEvent;
011    import java.awt.event.ComponentAdapter;
012    import java.awt.event.ComponentEvent;
013    import java.awt.*;
014    
015    public class SplitPaneExpansionToggleCommand extends ActionCommand
016    {
017    
018        private DefaultButtonModel model;
019    
020        public SplitPaneExpansionToggleCommand(String commandId, JSplitPane splitPane, boolean switchedAway)
021        {
022            super(commandId);
023            this.model = new SplitPaneExpansionButtonModel(splitPane, switchedAway);
024            ((CommandConfigurer) Application.services().getService(CommandConfigurer.class)).configure(this);
025        }
026    
027    
028        protected void doExecuteCommand()
029        {
030            //toggle
031            this.model.setSelected(!this.model.isSelected());
032    
033        }
034    
035        public void doHide()
036        {
037            this.model.setSelected(false);
038        }
039    
040        public void doShow()
041        {
042            this.model.setSelected(true);
043        }
044    
045        public AbstractButton createButton(String faceDescriptorId, ButtonFactory buttonFactory,
046                                           CommandButtonConfigurer configurer)
047        {
048            AbstractButton button = buttonFactory.createToggleButton();
049            attach(button, faceDescriptorId, configurer);
050            return button;
051        }
052    
053        public void attach(AbstractButton button, String faceDescriptorId,
054                           CommandButtonConfigurer configurer)
055        {
056            super.attach(button, faceDescriptorId, configurer);
057            button.setModel(this.model);
058        }
059    
060        public static class SplitPaneExpansionButtonModel extends DefaultButtonModel
061        {
062    
063            private final JSplitPane splitPane;
064    
065            private enum SWITCH_STATE
066            {
067                NO_ACTION, SWITCHED_AWAY, SWITCHED_AWAY_AND_MOVED
068            }
069    
070            ;
071    
072            private SWITCH_STATE state = SWITCH_STATE.NO_ACTION;
073    
074            private transient PropertyChangeListener listener = new PropertyChangeListener()
075            {
076                public void propertyChange(PropertyChangeEvent evt)
077                {
078                    fireStateChanged();
079    
080                    if (state == SWITCH_STATE.SWITCHED_AWAY)
081                        state = SWITCH_STATE.SWITCHED_AWAY_AND_MOVED;
082                    else if (state == SWITCH_STATE.SWITCHED_AWAY_AND_MOVED)
083                        state = SWITCH_STATE.NO_ACTION;
084                }
085            };
086    
087            public SplitPaneExpansionButtonModel(JSplitPane mySplitPane, boolean switchedAway)
088            {
089                super();
090                this.splitPane = mySplitPane;
091    
092                this.splitPane.addPropertyChangeListener(JSplitPane.DIVIDER_LOCATION_PROPERTY,
093                        listener);
094    
095                this.splitPane.addComponentListener(new ComponentAdapter()
096                {
097                    @Override
098                    public void componentResized(ComponentEvent e)
099                    {
100                        if (state == SWITCH_STATE.SWITCHED_AWAY || state == SWITCH_STATE.SWITCHED_AWAY_AND_MOVED)
101                            hidePanel();
102                    }
103    
104                });
105    
106                if (switchedAway)
107                    this.state = SWITCH_STATE.SWITCHED_AWAY;
108            }
109    
110            public boolean isSelected()
111            {
112                return isShown();
113            }
114    
115            public void setSelected(boolean makeVisible)
116            {
117                super.setSelected(makeVisible);
118                if (makeVisible)
119                {
120                    splitPane.resetToPreferredSizes();
121                    state = SWITCH_STATE.NO_ACTION;
122                }
123                else
124                {
125                    hidePanel();
126                }
127            }
128    
129            private void hidePanel()
130            {
131                splitPane.setDividerLocation(getHideRightComponentDividerLocation());
132                state = SWITCH_STATE.SWITCHED_AWAY;
133            }
134    
135            private boolean isShown()
136            {
137                return splitPane.getDividerLocation() < (getHideRightComponentDividerLocation());
138            }
139    
140            private int getHideRightComponentDividerLocation()
141            {
142                Dimension size = splitPane.getSize();
143                int max = getRelevantDimensionpart(size);
144                Insets insets = splitPane.getInsets();
145                int relevantInset = getRelevantInsetpart(insets); // we need to correct with the border size
146                int dividerSize = splitPane.getDividerSize();// we need to correct with the size of the divider!
147                return max - (relevantInset + dividerSize);
148            }
149    
150            private int getRelevantInsetpart(Insets insets)
151            {
152                int orientation = splitPane.getOrientation();
153                int result = (orientation == JSplitPane.VERTICAL_SPLIT) ? // for vertical
154                        (insets.bottom) : //take the height
155                        (insets.right); //  else the width
156                return result;
157            }
158    
159            private int getRelevantDimensionpart(Dimension size)
160            {
161                int orientation = splitPane.getOrientation();
162                int result = (orientation == JSplitPane.VERTICAL_SPLIT) ? // for vertical
163                        (int) Math.ceil(size.getHeight()) : //take the height
164                        (int) Math.ceil(size.getWidth()); //  else the width
165                return result;
166            }
167        }
168    
169    }
170