001    package org.springframework.richclient.form;
002    
003    import org.springframework.util.Assert;
004    import org.springframework.binding.form.VetoableCommitListener;
005    import org.springframework.binding.form.FormModel;
006    import org.springframework.binding.form.NewFormObjectAware;
007    import org.springframework.richclient.components.MessagableTabbedPane;
008    import org.springframework.richclient.components.SkipComponentsFocusTraversalPolicy;
009    import org.springframework.richclient.util.RcpSupport;
010    
011    import javax.swing.event.ChangeListener;
012    import javax.swing.event.ChangeEvent;
013    import javax.swing.*;
014    import java.util.List;
015    import java.util.ArrayList;
016    import java.awt.*;
017    
018    public abstract class TabbedForm extends AbstractFocussableForm implements ChangeListener, NewFormObjectAware
019    {
020    
021        private List<VetoableCommitListener> vetoableCommitListeners;
022    
023        private JTabbedPane tabbedPane = null;
024    
025        public TabbedForm(Object formObject, String formId)
026        {
027            this(FormModelHelper.createFormModel(formObject), formId);
028        }
029    
030        public TabbedForm(FormModel formModel, String formId)
031        {
032            super(formModel, formId);
033    
034            if (this.getFormModel().getId() == null)
035                this.getFormModel().setId(formId);
036        }
037    
038        public TabbedForm(FormModel formModel)
039        {
040            this(formModel, formModel.getId());
041        }
042    
043        protected JTabbedPane getTabbedPane()
044        {
045            return tabbedPane;
046        }
047    
048        protected final JComponent createFormControl()
049        {
050            tabbedPane = new MessagableTabbedPane(SwingConstants.TOP);
051            tabbedPane.setFocusTraversalPolicyProvider(true);
052            tabbedPane
053                    .setFocusTraversalPolicy(SkipComponentsFocusTraversalPolicy.skipJTextComponentTraversalPolicy);
054            for (TabbedForm.Tab tab : getTabs())
055            {
056                tab.setParent(tabbedPane);
057            }
058            tabbedPane.addChangeListener(this);
059            return tabbedPane;
060        }
061    
062        public JComponent getRevertComponent()
063        {
064            return getRevertCommand().createButton();
065        }
066    
067        public void setFormObject(Object formObject)
068        {
069            if (formObject == null)
070                selectTab(0);
071            super.setFormObject(formObject);
072        }
073    
074        public void setNewFormObject(Object formObject)
075        {
076            if (formObject != null)
077            {
078                super.setFormObject(formObject);
079            }
080            else
081            {
082                getNewFormObjectCommand().execute();
083            }
084            selectTab(0);
085        }
086    
087        public void selectTab(int tabIndex)
088        {
089            if ((tabbedPane != null) && (tabbedPane.getTabCount() > tabIndex))
090                tabbedPane.setSelectedIndex(tabIndex);
091        }
092    
093        public void selectTab(Tab tab)
094        {
095            if (tab.getTabIndex() > 0)
096            {
097                tabbedPane.setSelectedIndex(tab.getTabIndex());
098            }
099        }
100    
101        protected abstract Tab[] getTabs();
102    
103        protected class Tab
104        {
105    
106            private final String tabId;
107    
108            private final String title;
109    
110            private final JComponent panel;
111    
112            private FocusTraversalPolicy focusTraversalPolicy;
113    
114            private JTabbedPane parentPane;
115    
116            private int tabIndex = -1;
117    
118            private boolean enabled = true;
119    
120            private boolean visible = true;
121    
122            public Tab(String tabId, JComponent panel)
123            {
124                Assert.notNull(panel);
125                this.tabId = tabId;
126                this.title = RcpSupport.getMessage(getId(), this.tabId, RcpSupport.TITLE);
127                this.panel = panel;
128                this.panel.setBorder(BorderFactory.createEmptyBorder(5, 5, 5, 5));
129            }
130    
131            /**
132             * Set parent for overlays and enabling
133             *
134             * @param parentPane
135             */
136            protected void setParent(JTabbedPane parentPane)
137            {
138                this.parentPane = parentPane;
139                if (this.parentPane != null)
140                    setVisible(visible);
141            }
142    
143            public void setVisible(boolean visible)
144            {
145                if (parentPane != null)
146                {
147                    if (visible)
148                    {
149                        parentPane.addTab(title, panel);
150                        tabIndex = parentPane.indexOfComponent(panel);
151                        parentPane.setEnabledAt(tabIndex, isEnabled());
152                    }
153                    else
154                    {
155                        parentPane.remove(panel);
156                        tabIndex = -1;
157                    }
158                }
159                this.visible = visible;
160            }
161    
162            public void setEnabled(boolean enabled)
163            {
164                if ((parentPane != null) && (tabIndex > -1))
165                    parentPane.setEnabledAt(tabIndex, enabled);
166    
167                this.enabled = enabled;
168            }
169    
170            /**
171             * Gets the index of the tab on the tabbedpane
172             *
173             * @return index of the tab, -1 if not visible
174             */
175            public int getTabIndex()
176            {
177                return tabIndex;
178            }
179    
180            public boolean isEnabled()
181            {
182                return this.enabled;
183            }
184    
185            public void setMarked(boolean enable)
186            {
187                Icon icon = RcpSupport.getIcon(tabId + ".icon");
188                if ((parentPane != null) && (tabIndex > -1))
189                    parentPane.setIconAt(getTabIndex(), enable ? icon : null);
190    
191            }
192    
193            public void setFocusTraversalPolicy(FocusTraversalPolicy focusTraversalPolicy)
194            {
195                this.focusTraversalPolicy = focusTraversalPolicy;
196                panel.setFocusTraversalPolicy(this.focusTraversalPolicy);
197                panel.setFocusTraversalPolicyProvider(this.focusTraversalPolicy == null ? false : true);
198            }
199        }
200    
201        @Override
202        public void commit()
203        {
204            FormModel formModel = getFormModel();
205            if (vetoableCommitListeners != null)
206            {
207                for (VetoableCommitListener v : vetoableCommitListeners)
208                {
209                    if (!v.proceedWithCommit(formModel))
210                        return;
211                }
212            }
213            super.commit();
214        }
215    
216        public void stateChanged(ChangeEvent e)
217        {
218        }
219    
220        /**
221         * Adding a vetoableCommitListener might prevent a formModel.commit() but this is not the correct location
222         * to add back-end logic to check for a consistent formObject. Besides this the vetoableCommitListener
223         * doesn't add any other real advantage for our case. Therefor deprecating to prevent wrong usage.
224         */
225        @Deprecated
226        public void addVetoableCommitListener(VetoableCommitListener vetoableCommitListener)
227        {
228            if (vetoableCommitListeners == null)
229                vetoableCommitListeners = new ArrayList<VetoableCommitListener>(5);
230            vetoableCommitListeners.add(vetoableCommitListener);
231        }
232    
233        @Deprecated
234        public void removeVetoableCommitListener(VetoableCommitListener vetoableCommitListener)
235        {
236            if (vetoableCommitListeners != null)
237                vetoableCommitListeners.remove(vetoableCommitListener);
238        }
239    }