001    /*
002     * Copyright 2002-2007 the original author or authors.
003     * 
004     * Licensed under the Apache License, Version 2.0 (the "License"); you may not
005     * use this file except in compliance with the License. You may obtain a copy of
006     * the License at
007     * 
008     * http://www.apache.org/licenses/LICENSE-2.0
009     * 
010     * Unless required by applicable law or agreed to in writing, software
011     * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
012     * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
013     * License for the specific language governing permissions and limitations under
014     * the License.
015     */
016    package org.springframework.richclient.dialog.control;
017    
018    import java.beans.PropertyChangeEvent;
019    import java.beans.PropertyChangeListener;
020    import java.util.ArrayList;
021    import java.util.List;
022    
023    import javax.swing.JComponent;
024    import javax.swing.JTabbedPane;
025    import javax.swing.event.ChangeEvent;
026    import javax.swing.event.ChangeListener;
027    
028    import org.springframework.richclient.factory.ControlFactory;
029    import org.springframework.richclient.util.EventListenerListHelper;
030    
031    /**
032     * Wrapper around <code>JTabbedPane</code>. When a <code>Tab</code> is made invisible, the tab is hidden from the
033     * ui, and vice versa.
034     * <p>
035     * TODO: move this to another package?
036     * 
037     * @author Peter De Bruycker
038     */
039    public class ExtTabbedPane implements ControlFactory {
040    
041        private List tabs = new ArrayList();
042    
043        private JTabbedPane tabbedPane;
044    
045        private PropertyChangeListener propertyChangeHandler = new PropertyChangeListener() {
046            public void propertyChange(PropertyChangeEvent evt) {
047                Tab tab = (Tab) evt.getSource();
048                if (tab.isVisible()) {
049                    int index = getUIIndex(tab);
050                    if (index >= 0) {
051                        if (evt.getPropertyName().equals(Tab.TITLE_PROPERTY)) {
052                            tabbedPane.setTitleAt(index, tab.getTitle());
053                        }
054                        if (evt.getPropertyName().equals(Tab.TOOLTIP_PROPERTY)) {
055                            tabbedPane.setToolTipTextAt(index, tab.getTooltip());
056                        }
057                        if (evt.getPropertyName().equals(Tab.ICON_PROPERTY)) {
058                            tabbedPane.setIconAt(index, tab.getIcon());
059                        }
060                        if (evt.getPropertyName().equals(Tab.COMPONENT_PROPERTY)) {
061                            tabbedPane.setComponentAt(index, tab.getComponent());
062                        }
063                        if (evt.getPropertyName().equals(Tab.MNEMONIC_PROPERTY)) {
064                            tabbedPane.setMnemonicAt(index, tab.getMnemonic());
065                        }
066                        if (evt.getPropertyName().equals(Tab.ENABLED_PROPERTY)) {
067                            tabbedPane.setMnemonicAt(index, tab.getMnemonic());
068                        }
069                    }
070                }
071                if (evt.getPropertyName().equals("visible")) {
072                    updateTabVisibility(tab);
073                }
074            }
075        };
076    
077        private EventListenerListHelper changeListeners = new EventListenerListHelper(ChangeListener.class);
078    
079        public ExtTabbedPane(JTabbedPane tabbedPane) {
080            this.tabbedPane = tabbedPane;
081            tabbedPane.addChangeListener(new ChangeListener() {
082                public void stateChanged(ChangeEvent e) {
083                    // delegate change events to registered listeners
084                    changeListeners.fire("stateChanged", e);
085                }
086            });
087        }
088    
089        public ExtTabbedPane() {
090            this(new JTabbedPane());
091        }
092    
093        public void addChangeListener(ChangeListener listener) {
094            changeListeners.add(listener);
095        }
096    
097        public void removeChangeListener(ChangeListener listener) {
098            changeListeners.remove(listener);
099        }
100    
101        public JComponent getControl() {
102            return tabbedPane;
103        }
104    
105        public void addTab(Tab tab) {
106            tabs.add(tab);
107            if (tab.isVisible()) {
108                tabbedPane.addTab(tab.getTitle(), tab.getIcon(), tab.getComponent(), tab.getTooltip());
109            }
110            tab.addPropertyChangeListener(propertyChangeHandler);
111        }
112    
113        public Tab getTab(int index) {
114            return (Tab) tabs.get(index);
115        }
116    
117        public void removeTab(Tab tab) {
118            removeTab(tabs.indexOf(tab));
119        }
120    
121        public void addTab(int index, Tab tab) {
122            tabs.add(index, tab);
123            if (tab.isVisible()) {
124                tabbedPane.insertTab(tab.getTitle(), tab.getIcon(), tab.getComponent(), tab.getTooltip(), index);
125            }
126            tab.addPropertyChangeListener(propertyChangeHandler);
127        }
128    
129        public void removeTab(int index) {
130            tabbedPane.removeTabAt(index);
131            Tab tab = (Tab) tabs.remove(index);
132            tab.removePropertyChangeListener(propertyChangeHandler);
133        }
134    
135        public void selectTab(Tab tab) {
136            if (tab.isVisible()) {
137                int targetIndex = getUIIndex(tab);
138                if (targetIndex >= 0) {
139                    tabbedPane.setSelectedIndex(targetIndex);
140                }
141            }
142        }
143    
144        public int convertUIIndexToModelIndex(int index) {
145            int modelIndex = index;
146            for (int i = 0; i <= modelIndex; i++) {
147                if (!getTab(i).isVisible()) {
148                    modelIndex++;
149                }
150            }
151    
152            return modelIndex;
153        }
154    
155        public int getUIIndex(Tab tab) {
156            return convertModelIndexToUIIndex(tabs.indexOf(tab));
157        }
158    
159        public int convertModelIndexToUIIndex(int index) {
160            int uiIndex = 0;
161    
162            for (int i = 0; i < index; i++) {
163                if (getTab(i).isVisible()) {
164                    uiIndex++;
165                }
166            }
167    
168            return uiIndex;
169        }
170    
171        private void updateTabVisibility(Tab tab) {
172            if (tab.isVisible()) {
173                tabbedPane.insertTab(tab.getTitle(), tab.getIcon(), tab.getComponent(), tab.getTooltip(), getUIIndex(tab));
174            }
175            else {
176                tabbedPane.removeTabAt(getUIIndex(tab));
177    
178            }
179    
180            // because insert and remove don't change the selected tab index, we
181            // trigger one manually
182            ChangeEvent event = new ChangeEvent(tabbedPane);
183            changeListeners.fire("stateChanged", event);
184        }
185    }