Package org.apache.wicket.markup.repeater

Source Code of org.apache.wicket.markup.repeater.AbstractPageableView$CappedIteratorAdapter

/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements.  See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License.  You may obtain a copy of the License at
*
*      http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.wicket.markup.repeater;

import java.util.Iterator;
import java.util.NoSuchElementException;

import org.apache.wicket.markup.html.navigation.paging.IPageable;
import org.apache.wicket.model.IModel;
import org.apache.wicket.version.undo.Change;


/**
* An abstract repeater view that provides paging functionality to its subclasses.
* <p>
* The view is populated by overriding the <code>getItemModels(int offset, int count)</code>
* method and providing an iterator that returns models for items in the current page. The
* AbstractPageableView builds the items that will be rendered by looping over the models and
* calling the <code>newItem(String id, int index, IModel model)</code> to generate the child item
* container followed by <code>populateItem(Component item)</code> to let the user populate the
* newly created item container with with custom components.
* </p>
*
* @see org.apache.wicket.markup.repeater.RefreshingView
* @see org.apache.wicket.markup.html.navigation.paging.IPageable
*
* @author Igor Vaynberg (ivaynberg)
*
*/
public abstract class AbstractPageableView extends RefreshingView implements IPageable

{
  /**
   *
   */
  private static final long serialVersionUID = 1L;

  /**
   * Keeps track of the number of items we show per page. The default is Integer.MAX_VALUE which
   * effectively disables paging.
   */
  private int itemsPerPage = Integer.MAX_VALUE;

  /**
   * Keeps track of the current page number.
   */
  private int currentPage;

  /**
   * <code>cachedItemCount</code> is used to cache the call to
   * <code>internalGetItemCount()</code> for the duration of the request because that call can
   * potentially be expensive ( a select count query ) and so we do not want to execute it
   * multiple times.
   */
  private transient int cachedItemCount;


  /** @see org.apache.wicket.Component#Component(String, IModel) */
  public AbstractPageableView(String id, IModel model)
  {
    super(id, model);
    clearCachedItemCount();
  }


  /** @see org.apache.wicket.Component#Component(String) */
  public AbstractPageableView(String id)
  {
    super(id);
    clearCachedItemCount();
  }


  /**
   * This method retrieves the subset of models for items in the current page and allows
   * RefreshingView to generate items.
   *
   * @return iterator over models for items in the current page
   */
  protected Iterator getItemModels()
  {
    int offset = getViewOffset();
    int size = getViewSize();

    Iterator models = getItemModels(offset, size);

    models = new CappedIteratorAdapter(models, size);

    return models;
  }

  protected void onBeforeRender()
  {
    clearCachedItemCount();
    super.onBeforeRender();
  }

  /**
   * Returns an iterator over models for items in the current page
   *
   * @param offset
   *            index of first item in this page
   * @param size
   *            number of items that will be shown in the current page
   * @return an iterator over models for items in the current page
   */
  protected abstract Iterator getItemModels(int offset, int size);


  // /////////////////////////////////////////////////////////////////////////
  // ITEM COUNT CACHE
  // /////////////////////////////////////////////////////////////////////////


  private void clearCachedItemCount()
  {
    cachedItemCount = -1;
  }

  private void setCachedItemCount(int itemCount)
  {
    cachedItemCount = itemCount;
  }

  private int getCachedItemCount()
  {
    if (cachedItemCount < 0)
    {
      throw new IllegalStateException("getItemCountCache() called when cache was not set");
    }
    return cachedItemCount;
  }

  private boolean isItemCountCached()
  {
    return cachedItemCount >= 0;
  }

  // /////////////////////////////////////////////////////////////////////////
  // PAGING
  // /////////////////////////////////////////////////////////////////////////

  /**
   * @return maximum number of items that will be shown per page
   */
  protected final int internalGetRowsPerPage()
  {
    return itemsPerPage;
  }

  /**
   * Sets the maximum number of items to show per page. The current page will also be set to zero
   *
   * @param items
   */
  protected final void internalSetRowsPerPage(int items)
  {
    if (items < 1)
    {
      throw new IllegalArgumentException("Argument [itemsPerPage] cannot be less than 1");
    }

    if (itemsPerPage != items)
    {
      if (isVersioned())
      {
        addStateChange(new Change()
        {
          private static final long serialVersionUID = 1L;

          final int old = itemsPerPage;

          public void undo()
          {
            itemsPerPage = old;
          }

          public String toString()
          {
            return "ItemsPerPageChange[component: " + getPath() + ", itemsPerPage: " +
              old + "]";
          }
        });
      }
    }

    itemsPerPage = items;

    // because items per page can effect the total number of pages we always
    // reset the current page back to zero
    setCurrentPage(0);
  }

  /**
   * @return total item count
   */
  protected abstract int internalGetItemCount();

  /**
   * @return total item count
   */
  public final int getRowCount()
  {
    if (!isVisibleInHierarchy())
    {
      return 0;
    }

    if (isItemCountCached())
    {
      return getCachedItemCount();
    }

    int count = internalGetItemCount();

    setCachedItemCount(count);

    return count;
  }

  /**
   * @see org.apache.wicket.markup.html.navigation.paging.IPageable#getCurrentPage()
   */
  public final int getCurrentPage()
  {
    int page = currentPage;

    /*
     * trim current page if its out of bounds this can happen if items are added/deleted between
     * requests
     */

    if (page > 0 && page >= getPageCount())
    {
      page = Math.max(getPageCount() - 1, 0);
      currentPage = page;
      return page;
    }

    return page;
  }

  /**
   * @see org.apache.wicket.markup.html.navigation.paging.IPageable#setCurrentPage(int)
   */
  public final void setCurrentPage(int page)
  {
    // If page == 0, short-circuit the range check. This saves a call to
    // getPageCount(), but more importantly avoids it being called until
    // your AbstractPageableView is actually rendered.
    if (page != 0 && (page < 0 || (page >= getPageCount() && getPageCount() > 0)))
    {
      throw new IndexOutOfBoundsException("argument [page]=" + page + ", must be 0<=page<" +
        getPageCount());
    }

    if (currentPage != page)
    {
      if (isVersioned())
      {
        addStateChange(new Change()
        {
          private static final long serialVersionUID = 1L;

          private final int old = currentPage;

          public void undo()
          {
            currentPage = old;
          }

          public String toString()
          {
            return "CurrentPageChange[component: " + getPath() + ", currentPage: " +
              old + "]";
          }
        });

      }
    }
    currentPage = page;
  }

  /**
   * @see org.apache.wicket.markup.html.navigation.paging.IPageable#getPageCount()
   */
  public final int getPageCount()
  {
    int total = getRowCount();
    int page = internalGetRowsPerPage();
    int count = total / page;

    if (page * count < total)
    {
      count++;
    }

    return count;

  }

  /**
   * @return the index of the first visible item
   */
  protected int getViewOffset()
  {
    return getCurrentPage() * internalGetRowsPerPage();
  }


  /**
   * @return the number of items visible
   */
  protected int getViewSize()
  {
    return Math.min(internalGetRowsPerPage(), getRowCount() - getViewOffset());
  }

  // /////////////////////////////////////////////////////////////////////////
  // HELPER CLASSES
  // /////////////////////////////////////////////////////////////////////////

  /**
   * Iterator adapter that makes sure only the specified max number of items can be accessed from
   * its delegate.
   */
  private static class CappedIteratorAdapter implements Iterator
  {
    private final int max;
    private int index;
    private final Iterator delegate;

    /**
     * Constructor
     *
     * @param delegate
     *            delegate iterator
     * @param max
     *            maximum number of items that can be accessed.
     */
    public CappedIteratorAdapter(Iterator delegate, int max)
    {
      this.delegate = delegate;
      this.max = max;
    }

    /**
     * @see java.util.Iterator#remove()
     */
    public void remove()
    {
      throw new UnsupportedOperationException();
    }

    /**
     * @see java.util.Iterator#hasNext()
     */
    public boolean hasNext()
    {
      return (index < max) && delegate.hasNext();
    }

    /**
     * @see java.util.Iterator#next()
     */
    public Object next()
    {
      if (index >= max)
      {
        throw new NoSuchElementException();
      }
      index++;
      return delegate.next();
    }

  };

  protected void onDetach()
  {
    clearCachedItemCount();
    super.onDetach();
  }
}
TOP

Related Classes of org.apache.wicket.markup.repeater.AbstractPageableView$CappedIteratorAdapter

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.