org.richfaces.component.UIDatascroller.java Source code

Java tutorial

Introduction

Here is the source code for org.richfaces.component.UIDatascroller.java

Source

/**
 * License Agreement.
 *
 *  JBoss RichFaces - Ajax4jsf Component Library
 *
 * Copyright (C) 2007  Exadel, Inc.
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License version 2.1 as published by the Free Software Foundation.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301  USA
 */

package org.richfaces.component;

import java.util.Map;

import javax.el.ELException;
import javax.el.MethodExpression;
import javax.el.ValueExpression;
import javax.faces.FacesException;
import javax.faces.application.FacesMessage;
import javax.faces.component.ActionSource;
import javax.faces.component.UIComponent;
import javax.faces.component.UIData;
import javax.faces.component.UIInput;
import javax.faces.context.FacesContext;
import javax.faces.event.AbortProcessingException;
import javax.faces.event.FacesEvent;

import org.ajax4jsf.Messages;
import org.ajax4jsf.component.AjaxActionComponent;
import org.ajax4jsf.event.AjaxEvent;
import org.ajax4jsf.renderkit.AjaxRendererUtils;
import org.ajax4jsf.renderkit.RendererUtils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.richfaces.component.util.MessageUtil;
import org.richfaces.event.DataScrollerEvent;
import org.richfaces.event.DataScrollerListener;
import org.richfaces.event.DataScrollerSource;

/** JSF component class */
//xxxx nick -> alex - extend UIComponentBase and
//create event listener & event classes to define PageSwitchEvent
//public abstract class UIDatascroller extends UIComponentBase implements DataScrollerSource{
public abstract class UIDatascroller extends AjaxActionComponent implements DataScrollerSource, ActionSource {

    public static final String LAST_PAGE_MODE_FULL = "full";

    public static final String LAST_PAGE_MODE_SHORT = "short";

    private static final Log log = LogFactory.getLog(UIDatascroller.class);

    private Integer page;

    public static final String COMPONENT_TYPE = "org.richfaces.Datascroller";
    public static final String COMPONENT_FAMILY = "org.richfaces.Datascroller";

    public static final String FIRST_FACET_NAME = "first";

    public static final String LAST_FACET_NAME = "last";

    public static final String NEXT_FACET_NAME = "next";

    public static final String PREVIOUS_FACET_NAME = "previous";

    public static final String FAST_FORWARD_FACET_NAME = "fastforward";

    public static final String FAST_REWIND_FACET_NAME = "fastrewind";

    public static final String FIRST_DISABLED_FACET_NAME = "first_disabled";

    public static final String LAST_DISABLED_FACET_NAME = "last_disabled";

    public static final String NEXT_DISABLED_FACET_NAME = "next_disabled";

    public static final String PREVIOUS_DISABLED_FACET_NAME = "previous_disabled";

    public static final String FAST_FORWARD_DISABLED_FACET_NAME = "fastforward_disabled";

    public static final String FAST_REWIND_DISABLED_FACET_NAME = "fastrewind_disabled";

    public void addScrollerListener(DataScrollerListener listener) {
        addFacesListener(listener);
    }

    public DataScrollerListener[] getScrollerListeners() {
        return (DataScrollerListener[]) getFacesListeners(DataScrollerListener.class);
    }

    public void removeScrollerListener(DataScrollerListener listener) {
        removeFacesListener(listener);
    }

    public void broadcast(FacesEvent event) throws AbortProcessingException {
        super.broadcast(event);
        if (event instanceof DataScrollerEvent) {
            DataScrollerEvent dataScrollerEvent = (DataScrollerEvent) event;

            updateModel(dataScrollerEvent.getPage());

            FacesContext context = getFacesContext();

            MethodExpression scrollerListener = getScrollerListener();
            if (scrollerListener != null) {
                scrollerListener.invoke(context.getELContext(), new Object[] { event });
            }
        } else if (event instanceof AjaxEvent) {
            FacesContext context = getFacesContext();

            AjaxRendererUtils.addRegionByName(context, this, this.getId());
            AjaxRendererUtils.addRegionByName(context, this, this.getFor());

            setupReRender(context);
        }
    }

    public abstract MethodExpression getScrollerListener();

    public abstract void setScrollerListener(MethodExpression scrollerListener);

    public abstract void setFor(String f);

    public abstract String getFor();

    public abstract int getFastStep();

    public abstract void setFastStep(int FastStep);

    public abstract boolean isRenderIfSinglePage();

    public abstract void setRenderIfSinglePage(boolean renderIfSinglePage);

    public abstract int getMaxPages();

    public abstract void setMaxPages(int maxPages);

    public abstract String getSelectedStyleClass();

    public abstract void setSelectedStyleClass(String selectedStyleClass);

    public abstract String getSelectedStyle();

    public abstract void setSelectedStyle(String selectedStyle);

    public abstract String getEventsQueue();

    public abstract void setEventsQueue(String eventsQueue);

    public abstract boolean isAjaxSingle();

    public abstract void setAjaxSingle(boolean ajaxSingle);

    public abstract int getRequestDelay();

    public abstract void setRequestDelay(int requestDelay);

    public abstract String getSimilarityGroupingId();

    public abstract void setSimilarityGroupingId(String similarityGroupingId);

    public abstract String getTableStyleClass();

    public abstract void setTableStyleClass(String tableStyleClass);

    public abstract String getStyleClass();

    public abstract String getStyle();

    public abstract void setStyleClass(String styleClass);

    public abstract void setStyle(String styleClass);

    public abstract String getAlign();

    public abstract void setAlign(String align);

    public abstract String getBoundaryControls();

    public abstract void setBoundaryControls(String boundaryControls);

    public abstract String getFastControls();

    public abstract void setFastControls(String fastControls);

    public abstract String getStepControls();

    public abstract void setStepControls(String stepControls);

    public abstract String getInactiveStyleClass();

    public abstract String getInactiveStyle();

    public abstract void setInactiveStyleClass(String inactiveStyleClass);

    public abstract void setInactiveStyle(String inactiveStyle);

    public abstract String getLastPageMode();

    public abstract void setLastPageMode(String lastPageMode);

    /**
     * Finds the dataTable which id is mapped to the "for" property
     *
     * @return the dataTable component
     */
    public UIData getDataTable() {
        String forAttribute = getFor();
        UIComponent forComp;
        if (forAttribute == null) {
            forComp = this;
            while ((forComp = forComp.getParent()) != null) {
                if (forComp instanceof UIData) {
                    setFor(forComp.getId());
                    return (UIData) forComp;
                }
            }
            throw new FacesException("could not find dataTable for  datascroller " + this.getId());
        } else {
            forComp = RendererUtils.getInstance().findComponentFor(this, forAttribute);
        }
        if (forComp == null) {
            throw new IllegalArgumentException("could not find dataTable with id '" + forAttribute + "'");
        } else if (!(forComp instanceof UIData)) {
            throw new IllegalArgumentException("component with id '" + forAttribute + "' must be of type "
                    + UIData.class.getName() + ", not type " + forComp.getClass().getName());
        }
        return (UIData) forComp;
    }

    private int getFastStepOrDefault() {
        int step = getFastStep();
        if (step <= 0) {
            return 1;
        } else {
            return step;
        }
    }

    /**
     * @param data
     * @return
     * @see #getPage()
     * @deprecated
     */
    public int getPageIndex(UIData data) {
        return getPageIndex();
    }

    /**
     * @return
     * @see #getPage()
     * @deprecated
     */
    public int getPageIndex() {
        return getPage();
    }

    public int getPageForFacet(String facetName) {
        if (facetName == null) {
            throw new NullPointerException();
        }

        int newPage = 1;
        int pageCount = getPageCount();

        if (FIRST_FACET_NAME.equals(facetName)) {
            newPage = 1;
        } else if (PREVIOUS_FACET_NAME.equals(facetName)) {
            newPage = getPage() - 1;
        } else if (NEXT_FACET_NAME.equals(facetName)) {
            newPage = getPage() + 1;
        } else if (LAST_FACET_NAME.equals(facetName)) {
            newPage = pageCount > 0 ? pageCount : 1;
        } else if (FAST_FORWARD_FACET_NAME.equals(facetName)) {
            newPage = getPage() + getFastStepOrDefault();
        } else if (FAST_REWIND_FACET_NAME.equals(facetName)) {
            newPage = getPage() - getFastStepOrDefault();
        } else {
            try {
                newPage = Integer.parseInt(facetName.toString());
            } catch (NumberFormatException e) {
                throw new FacesException(e.getLocalizedMessage(), e);
            }
        }

        if (newPage >= 1 && newPage <= pageCount) {
            return newPage;
        } else {
            return 0;
        }
    }

    /**
     * Sets the page number according to the parameter recived from the
     * commandLink
     *
     * @param facetName - can be "first:, "last", "next",  "previous",
     * "fastforward", "fastrewind"
     * 
     * @see #setPage(int)
     * @see #getPageForFacet(String)
     * 
     * @deprecated as of 3.2 replaced with <code>setPage(int)</page>
     */
    public void setPage(String facetName) {
        int newPage = getPageForFacet(facetName);
        if (newPage != 0) {
            setPage(newPage);
        }
    }

    public int getPageCount(UIData data) {
        int rowCount = getRowCount(data);
        int rows = getRows(data);
        return getPageCount(data, rowCount, rows);
    }

    public int getPageCount(UIData data, int rowCount, int rows) {
        int pageCount;
        if (rows > 0) {
            pageCount = rows <= 0 ? 1 : rowCount / rows;
            if (rowCount % rows > 0) {
                pageCount++;
            }
            if (pageCount == 0) {
                pageCount = 1;
            }
        } else {
            rows = 1;
            pageCount = 1;
        }
        return pageCount;
    }

    /** @return the page count of the uidata */
    public int getPageCount() {
        return getPageCount(getDataTable());
    }

    public int getRowCount(UIData data) {
        int rowCount = data.getRowCount();
        if (rowCount >= 0) {
            return rowCount;
        }

        return BinarySearch.search(data);
    }

    /** @return int */
    public int getRowCount() {
        //xxx nick -> alex - scrollable models can return -1 here
        //let's implement "dychotomic" discovery
        // setPage(1)... if isPageAvailable() setPage(2) then 4, 8, etc.
        // setPage() { setRowIndex(pageIdx * rows); }
        // isPageAvailable() { return isRowAvailable() }
        //return getUIData().getRowCount();
        return getRowCount(getDataTable());
    }

    public int getRows(UIData data) {
        int row = 0;
        row = data.getRows();
        if (row == 0) {
            row = getRowCount(data);
        }

        return row;
    }

    /**
     * @param data
     * @return
     * @see #getPage()
     * @deprecated
     */
    public int getFirstRow(UIData data) {
        return data.getFirst();
    }

    /**
     * @param rows
     * @see #setPage(int)
     * @deprecated
     */
    public void setFirstRow(int rows) {
        getDataTable().setFirst(rows);
    }

    // facet getter methods
    public UIComponent getFirst() {
        return getFacet(FIRST_FACET_NAME);
    }

    public UIComponent getLast() {
        return getFacet(LAST_FACET_NAME);
    }

    public UIComponent getNext() {
        return getFacet(NEXT_FACET_NAME);
    }

    public UIComponent getFastForward() {
        return getFacet(FAST_FORWARD_FACET_NAME);
    }

    public UIComponent getFastRewind() {
        return getFacet(FAST_REWIND_FACET_NAME);
    }

    public UIComponent getPrevious() {
        return getFacet(PREVIOUS_FACET_NAME);
    }

    private static boolean isRendered(UIComponent component) {
        UIComponent c = component;
        while (c != null) {
            if (!c.isRendered()) {
                return false;
            }

            c = c.getParent();
        }

        return true;
    }

    public void setupFirstRowValue() {
        UIData dataTable = getDataTable();
        if (isRendered()) {
            int rowCount = getRowCount(dataTable);
            int rows = getRows(dataTable);

            Integer pageCount = getPageCount(dataTable, rowCount, rows);

            int page = getPage();
            int newPage = -1;
            if (page < 1) {
                newPage = 1;
            } else if (page > pageCount) {
                newPage = (pageCount != 0 ? pageCount : 1);
            }

            if (newPage != -1) {
                FacesContext context = getFacesContext();
                Object label = MessageUtil.getLabel(context, this);
                String formattedMessage = Messages.getMessage(Messages.DATASCROLLER_PAGE_MISSING,
                        new Object[] { label, page, pageCount, newPage });

                log.warn(formattedMessage);

                page = newPage;
                dataTable.getAttributes().put(SCROLLER_STATE_ATTRIBUTE, page);
            }

            if (isRendered(dataTable)) {
                int first;

                String lastPageMode = getLastPageMode();
                if (lastPageMode == null) {
                    lastPageMode = LAST_PAGE_MODE_SHORT;
                } else if (!LAST_PAGE_MODE_SHORT.equals(lastPageMode)
                        && !LAST_PAGE_MODE_FULL.equals(lastPageMode)) {

                    throw new IllegalArgumentException(
                            "Illegal value of 'lastPageMode' attribute: '" + lastPageMode + "'");
                }

                if (page != pageCount || LAST_PAGE_MODE_SHORT.equals(lastPageMode)) {
                    first = (page - 1) * rows;
                } else {
                    first = rowCount - rows;
                    if (first < 0) {
                        first = 0;
                    }
                }

                dataTable.setFirst(first);
            }
        }
    }

    public void setPage(int newPage) {
        this.page = newPage;
    }

    public int getPage() {
        Map<String, Object> attributes = getDataTable().getAttributes();
        Integer state = (Integer) attributes.get(SCROLLER_STATE_ATTRIBUTE);
        if (state != null) {
            return state;
        }

        if (this.page != null) {
            return page;
        }

        ValueExpression ve = getValueExpression("page");
        if (ve != null) {
            try {
                Integer pageObject = (Integer) ve.getValue(getFacesContext().getELContext());

                if (pageObject != null) {
                    return pageObject;
                } else {
                    return 1;
                }
            } catch (ELException e) {
                throw new FacesException(e);
            }
        } else {
            return 1;
        }
    }

    private void updateModel(int newPage) {
        UIData dataTable = getDataTable();

        if (isRendered(dataTable)) {
            dataTable.setFirst((newPage - 1) * getRows(dataTable));
        }

        Map<String, Object> attributes = dataTable.getAttributes();
        attributes.put(SCROLLER_STATE_ATTRIBUTE, newPage);

        FacesContext context = getFacesContext();
        ValueExpression ve = getValueExpression("page");
        if (ve != null) {
            try {
                ve.setValue(context.getELContext(), newPage);
                attributes.remove(SCROLLER_STATE_ATTRIBUTE);
            } catch (ELException e) {
                String messageStr = e.getMessage();
                Throwable result = e.getCause();
                while (null != result && result.getClass().isAssignableFrom(ELException.class)) {
                    messageStr = result.getMessage();
                    result = result.getCause();
                }
                FacesMessage message;
                if (null == messageStr) {
                    message = MessageUtil.getMessage(context, UIInput.UPDATE_MESSAGE_ID,
                            new Object[] { MessageUtil.getLabel(context, this) });
                } else {
                    message = new FacesMessage(FacesMessage.SEVERITY_ERROR, messageStr, messageStr);
                }
                context.getExternalContext().log(message.getSummary(), result);
                context.addMessage(getClientId(context), message);
                context.renderResponse();
            } catch (IllegalArgumentException e) {
                FacesMessage message = MessageUtil.getMessage(context, UIInput.UPDATE_MESSAGE_ID,
                        new Object[] { MessageUtil.getLabel(context, this) });
                context.getExternalContext().log(message.getSummary(), e);
                context.addMessage(getClientId(context), message);
                context.renderResponse();
            } catch (Exception e) {
                FacesMessage message = MessageUtil.getMessage(context, UIInput.UPDATE_MESSAGE_ID,
                        new Object[] { MessageUtil.getLabel(context, this) });
                context.getExternalContext().log(message.getSummary(), e);
                context.addMessage(getClientId(context), message);
                context.renderResponse();
            }
        }
    }

    public String getFamily() {
        return COMPONENT_FAMILY;
    }

    static class BinarySearch {

        public static int search(UIData data) {
            int rowIndex = data.getRowIndex();
            try {
                int n = 1;
                int k = 2;
                for (;;) {
                    data.setRowIndex(k - 1);
                    if (data.isRowAvailable()) {
                        n = k;
                        k = k * 2;
                    } else {
                        break;
                    }
                }

                while (n < k) {
                    int kk = Math.round((n + k) / 2) + 1;
                    data.setRowIndex(kk - 1);
                    if (data.isRowAvailable()) {
                        n = kk;
                    } else {
                        k = kk - 1;
                    }
                }

                data.setRowIndex(k - 1);
                if (data.isRowAvailable()) {
                    return k;
                } else {
                    return 0;
                }
            } finally {
                data.setRowIndex(rowIndex);
            }
        }
    }

    public Object saveState(FacesContext context) {
        return new Object[] { super.saveState(context), page };

    }

    public void restoreState(FacesContext context, Object object) {
        Object[] state = (Object[]) object;

        super.restoreState(context, state[0]);
        page = (Integer) state[1];
    }

    public static final String SCROLLER_STATE_ATTRIBUTE = COMPONENT_TYPE + ":page";

    public boolean isLocalPageSet() {
        return page != null;
    }

    public void resetLocalPage() {
        page = null;
    }

}