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 }