001: /*
002: * $Id: TabbedPanel.java 4079 2006-02-02 10:18:54 -0800 (Thu, 02 Feb 2006)
003: * ivaynberg $ $Revision: 462413 $ $Date: 2006-02-02 10:18:54 -0800 (Thu, 02 Feb
004: * 2006) $
005: *
006: * ==================================================================== Licensed
007: * under the Apache License, Version 2.0 (the "License"); you may not use this
008: * file except in compliance with the License. You may obtain a copy of the
009: * License at
010: *
011: * http://www.apache.org/licenses/LICENSE-2.0
012: *
013: * Unless required by applicable law or agreed to in writing, software
014: * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
015: * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
016: * License for the specific language governing permissions and limitations under
017: * the License.
018: */
019: package wicket.extensions.markup.html.tabs;
020:
021: import java.util.List;
022:
023: import wicket.Component;
024: import wicket.WicketRuntimeException;
025: import wicket.behavior.AttributeAppender;
026: import wicket.behavior.SimpleAttributeModifier;
027: import wicket.markup.html.WebMarkupContainer;
028: import wicket.markup.html.basic.Label;
029: import wicket.markup.html.link.Link;
030: import wicket.markup.html.list.Loop;
031: import wicket.markup.html.panel.Panel;
032: import wicket.model.AbstractReadOnlyModel;
033: import wicket.model.IModel;
034: import wicket.model.Model;
035:
036: /**
037: * TabbedPanel component represets a panel with tabs that are used to switch
038: * between different content panels inside the TabbedPanel panel.
039: * <p>
040: * Example:
041: *
042: * <pre>
043: *
044: * List tabs=new ArrayList();
045: *
046: * tabs.add(new AbstractTab(new Model("first tab")) {
047: *
048: * public Panel getPanel(String panelId)
049: * {
050: * return new TabPanel1(panelId);
051: * }
052: *
053: * });
054: *
055: * tabs.add(new AbstractTab(new Model("second tab")) {
056: *
057: * public Panel getPanel(String panelId)
058: * {
059: * return new TabPanel2(panelId);
060: * }
061: *
062: * });
063: *
064: * add(new TabbedPanel("tabs", tabs);
065: *
066: *
067: * <span wicket:id="tabs" class="tabpanel">[tabbed panel will be here]</span>
068: *
069: * </pre>
070: *
071: * </p>
072: *
073: * <p>
074: * For a complete example see the component references in wicket-examples
075: * project
076: * </p>
077: *
078: * @see wicket.extensions.markup.html.tabs.ITab
079: *
080: * @author Igor Vaynberg (ivaynberg)
081: *
082: */
083: public class TabbedPanel extends Panel {
084: private static final long serialVersionUID = 1L;
085:
086: /**
087: * id used for child panels
088: */
089: public static final String TAB_PANEL_ID = "panel";
090:
091: private List tabs;
092:
093: /**
094: * Constructor
095: *
096: * @param id
097: * component id
098: * @param tabs
099: * list of ITab objects used to represent tabs
100: */
101: public TabbedPanel(String id, List tabs) {
102: super (id, new Model(new Integer(-1)));
103:
104: if (tabs == null) {
105: throw new IllegalArgumentException(
106: "argument [tabs] cannot be null");
107: }
108:
109: if (tabs.size() < 1) {
110: throw new IllegalArgumentException(
111: "argument [tabs] must contain a list of at least one tab");
112: }
113:
114: this .tabs = tabs;
115:
116: final IModel tabCount = new AbstractReadOnlyModel() {
117: private static final long serialVersionUID = 1L;
118:
119: public Object getObject(Component component) {
120: return new Integer(TabbedPanel.this .tabs.size());
121: }
122: };
123:
124: // add the loop used to generate tab names
125: add(new Loop("tabs", tabCount) {
126: private static final long serialVersionUID = 1L;
127:
128: protected void populateItem(LoopItem item) {
129: final int index = item.getIteration();
130: final ITab tab = ((ITab) TabbedPanel.this .tabs
131: .get(index));
132: final int selected = getSelectedTab();
133:
134: final WebMarkupContainer titleLink = newLink("link",
135: index);
136:
137: titleLink.add(new Label("title", tab.getTitle()));
138: item.add(titleLink);
139:
140: item.add(new SimpleAttributeModifier("class",
141: "selected") {
142: private static final long serialVersionUID = 1L;
143:
144: public boolean isEnabled() {
145: return index == selected;
146: }
147:
148: });
149: if (item.getIteration() == getIterations() - 1) {
150: item.add(new AttributeAppender("class", true,
151: new Model("last"), " "));
152: }
153:
154: }
155:
156: });
157:
158: // select the first tab by default
159: setSelectedTab(0);
160:
161: }
162:
163: /**
164: * @return list of tabs that can be used by the user to add/remove/reorder
165: * tabs in the panel
166: */
167: public final List getTabs() {
168: return tabs;
169: }
170:
171: /**
172: * Factory method for links used to switch between tabs.
173: *
174: * The created component is attached to the following markup. Label
175: * component with id: title will be added for you by the tabbed panel.
176: *
177: * <pre>
178: * <a href="#" wicket:id="link"><span wicket:id="title">[[tab title]]</span></a>
179: * </pre>
180: *
181: * Example implementation:
182: *
183: * <pre>
184: * protected WebMarkupContainer newLink(String linkId, final int index)
185: * {
186: * return new Link(linkId)
187: * {
188: * private static final long serialVersionUID = 1L;
189: *
190: * public void onClick()
191: * {
192: * setSelectedTab(index);
193: * }
194: * };
195: * }
196: * </pre>
197: *
198: * @param linkId
199: * component id with which the link should be created
200: * @param index
201: * index of the tab that should be activated when this link is
202: * clicked. See {@link #setSelectedTab(int)}.
203: * @return created link component
204: */
205: protected WebMarkupContainer newLink(String linkId, final int index) {
206: return new Link(linkId) {
207: private static final long serialVersionUID = 1L;
208:
209: public void onClick() {
210: setSelectedTab(index);
211: }
212: };
213: }
214:
215: /**
216: * sets the selected tab
217: *
218: * @param index
219: * index of the tab to select
220: *
221: */
222: public final void setSelectedTab(int index) {
223: if (index < 0 || index >= tabs.size()) {
224: throw new IndexOutOfBoundsException();
225: }
226:
227: setModelObject(new Integer(index));
228:
229: ITab tab = (ITab) tabs.get(index);
230:
231: Panel panel = tab.getPanel(TAB_PANEL_ID);
232:
233: if (panel == null) {
234: throw new WicketRuntimeException(
235: "ITab.getPanel() returned null. TabbedPanel ["
236: + getPath() + "] ITab index [" + index
237: + "]");
238:
239: }
240:
241: if (!panel.getId().equals(TAB_PANEL_ID)) {
242: throw new WicketRuntimeException(
243: "ITab.getPanel() returned a panel with invalid id ["
244: + panel.getId()
245: + "]. You must always return a panel with id equal to the provided panelId parameter. TabbedPanel ["
246: + getPath() + "] ITab index [" + index
247: + "]");
248: }
249:
250: if (get(TAB_PANEL_ID) == null) {
251: add(panel);
252: } else {
253: replace(panel);
254: }
255: }
256:
257: /**
258: * @return index of the selected tab
259: */
260: public final int getSelectedTab() {
261: return ((Integer) getModelObject()).intValue();
262: }
263:
264: }
|