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 }