001: /*
002: * $Id: RefreshingView.java 5564 2006-04-28 16:05:28 -0700 (Fri, 28 Apr 2006)
003: * ivaynberg $ $Revision: 460550 $ $Date: 2006-04-28 16:05:28 -0700 (Fri, 28 Apr
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.repeater.refreshing;
020:
021: import java.util.Iterator;
022:
023: import wicket.extensions.markup.html.repeater.RepeatingView;
024: import wicket.extensions.markup.html.repeater.util.ModelIteratorAdapter;
025: import wicket.model.IModel;
026: import wicket.version.undo.Change;
027:
028: /**
029: * An abstract repeater view that provides refreshing functionality to its
030: * subclasses. The view is refreshed every request, making it well suited for
031: * displaying dynamic data.
032: * <p>
033: * The view is populated by implementing {@link RefreshingView#getItemModels() }
034: * and {@link RefreshingView#populateItem(Item) } methods. RefreshingView builds
035: * the items that will be rendered by looping over the models retrieved from
036: * {@link RefreshingView#getItemModels() } and calling the
037: * {@link RefreshingView#newItem(String, int, IModel) } to generate the child
038: * item container followed by a call to
039: * {@link RefreshingView#populateItem(Item) } to let the user populate the newly
040: * created item container with custom components.
041: * </p>
042: * <p>
043: * The provided {@link ModelIteratorAdapter} can make implementing
044: * {@link RefreshingView#getItemModels() } easier if you have an iterator over
045: * item objects.
046: * </p>
047: *
048: * @see RepeatingView
049: * @see ModelIteratorAdapter
050: *
051: * @author Igor Vaynberg (ivaynberg)
052: *
053: */
054: public abstract class RefreshingView extends RepeatingView {
055: private static final long serialVersionUID = 1L;
056:
057: /**
058: * The item reuse strategy that will be used to recycle items when the page
059: * is changed or the view is redrawn.
060: *
061: * @see IItemReuseStrategy
062: */
063: private IItemReuseStrategy itemReuseStrategy;
064:
065: /**
066: * Constructor
067: *
068: * @param id
069: * component id
070: */
071: public RefreshingView(String id) {
072: super (id);
073: }
074:
075: /**
076: * Constructor
077: *
078: * @param id
079: * component id
080: * @param model
081: * model
082: */
083: public RefreshingView(String id, IModel model) {
084: super (id, model);
085: }
086:
087: /**
088: * Refresh the items in the view. Delegates the creation of items to the
089: * selected item reuse strategy
090: */
091: protected void internalOnAttach() {
092: super .internalOnAttach();
093:
094: if (isVisibleInHierarchy()) {
095:
096: IItemFactory itemFactory = new IItemFactory() {
097:
098: public Item newItem(int index, IModel model) {
099: String id = RefreshingView.this .newChildId();
100: Item item = RefreshingView.this .newItem(id, index,
101: model);
102: RefreshingView.this .populateItem(item);
103: return item;
104: }
105:
106: };
107:
108: Iterator models = getItemModels();
109: Iterator items = getItemReuseStrategy().getItems(
110: itemFactory, models, getItems());
111: removeAll();
112: addItems(items);
113: }
114:
115: }
116:
117: /**
118: * Returns an iterator over models for items that will be added to this view
119: *
120: * @return an iterator over models for items that will be added to this view
121: */
122: protected abstract Iterator getItemModels();
123:
124: /**
125: * Populate the given Item container.
126: * <p>
127: * <b>be carefull</b> to add any components to the item and not the view
128: * itself. So, don't do:
129: *
130: * <pre>
131: * add(new Label("foo", "bar"));
132: * </pre>
133: *
134: * but:
135: *
136: * <pre>
137: * item.add(new Label("foo", "bar"));
138: * </pre>
139: *
140: * </p>
141: *
142: * @param item
143: * The item to populate
144: */
145: protected abstract void populateItem(final Item item);
146:
147: /**
148: * Factory method for Item container. Item containers are simple
149: * MarkupContainer used to aggregate the user added components for a row
150: * inside the view.
151: *
152: * @see Item
153: * @param id
154: * component id for the new data item
155: * @param index
156: * the index of the new data item
157: * @param model
158: * the model for the new data item
159: *
160: * @return DataItem created DataItem
161: */
162: protected Item newItem(final String id, int index,
163: final IModel model) {
164: return new Item(id, index, model);
165: }
166:
167: /**
168: * @return iterator over item instances that exist as children of this view
169: */
170: public Iterator getItems() {
171: return iterator();
172: }
173:
174: /**
175: * Add items to the view. Prior to this all items were removed so every
176: * request this function starts from a clean slate.
177: *
178: * @param items
179: * item instances to be added to this view
180: */
181: protected void addItems(Iterator items) {
182: while (items.hasNext()) {
183: add((Item) items.next());
184: }
185: }
186:
187: // /////////////////////////////////////////////////////////////////////////
188: // ITEM GENERATION
189: // /////////////////////////////////////////////////////////////////////////
190:
191: /**
192: * @return currently set item reuse strategy. Defaults to
193: * <code>DefaultItemReuseStrategy</code> if none was set.
194: *
195: * @see DefaultItemReuseStrategy
196: */
197: public IItemReuseStrategy getItemReuseStrategy() {
198: if (itemReuseStrategy == null) {
199: return DefaultItemReuseStrategy.getInstance();
200: }
201: return itemReuseStrategy;
202: }
203:
204: /**
205: * Sets the item reuse strategy. This strategy controls the creation of
206: * {@link Item}s.
207: *
208: * @see IItemReuseStrategy
209: *
210: * @param strategy
211: * item reuse strategy
212: * @return this for chaining
213: */
214: public RefreshingView setItemReuseStrategy(
215: IItemReuseStrategy strategy) {
216: if (strategy == null) {
217: throw new IllegalArgumentException();
218: }
219:
220: if (!strategy.equals(itemReuseStrategy)) {
221: if (isVersioned()) {
222: addStateChange(new Change() {
223: private static final long serialVersionUID = 1L;
224:
225: private final IItemReuseStrategy old = itemReuseStrategy;
226:
227: public void undo() {
228: itemReuseStrategy = old;
229: }
230:
231: public String toString() {
232: return "ItemsReuseStrategyChange[component: "
233: + getPath() + ", reuse: " + old + "]";
234: }
235: });
236: }
237: itemReuseStrategy = strategy;
238: }
239: return this;
240: }
241:
242: }
|